From c818442ef2d3363175f8ba960eaf43b121264165 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 12 Apr 2014 19:40:41 +0200 Subject: [PATCH 0001/1332] also linke "files" subdir Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 2f75ffd4..6b0ad9b5 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -33,6 +33,8 @@ import cdist import cdist.message from cdist import core +CONF_SUBDIRS_LINKED = [ "explorer", "files", "manifest", "type" ]: + class Local(object): """Execute commands locally. @@ -216,14 +218,14 @@ class Local(object): pass def _create_conf_path_and_link_conf_dirs(self): - # Link destination directories - for sub_dir in [ "explorer", "manifest", "type" ]: + # Create destination directories + for sub_dir in CONF_SUBDIRS_LINKED: self.mkdir(os.path.join(self.conf_path, sub_dir)) # Iterate over all directories and link the to the output dir for conf_dir in self.conf_dirs: self.log.debug("Checking conf_dir %s ..." % (conf_dir)) - for sub_dir in [ "explorer", "manifest", "type" ]: + for sub_dir in CONF_SUBDIRS_LINKED: current_dir = os.path.join(conf_dir, sub_dir) # Allow conf dirs to contain only partial content From aa8c5555b78591a48bccdd696389105bdac03e9a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 14 Apr 2014 09:46:52 +0200 Subject: [PATCH 0002/1332] document __files Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 7081e762..c6e5053f 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -75,6 +75,10 @@ confdir:: By default it consists of everything in \$HOME/.cdist and cdist/conf/. For more details see cdist(1) +confdir/files/:: + Cdist does not care about this directory besides providing access to it. + It is thought to be a general file storage area. + confdir/manifest/init:: This is the central entry point. It is an executable (+x bit set) shell script that can use @@ -196,6 +200,10 @@ The following environment variables are exported by cdist: __explorer:: Directory that contains all global explorers. Available for: initial manifest, explorer, type explorer, shell +__files:: + Directory that contains content from the "files" subdirectories + from the configuration directories. + Available for: initial manifest, type manifest, type gencode, shell __manifest:: Directory that contains the initial manifest. Available for: initial manifest, type manifest, shell From c363fc24deb63b9ffc029af2a434bd701e045ec1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 May 2014 00:28:18 +0200 Subject: [PATCH 0003/1332] begin to make OBJECT_MARKER dynamic Signed-off-by: Nico Schottelius --- cdist/config.py | 2 +- cdist/core/__init__.py | 2 +- cdist/core/cdist_object.py | 15 +++++++-------- docs/dev/logs/2014-05-06.object-marker | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 docs/dev/logs/2014-05-06.object-marker diff --git a/cdist/config.py b/cdist/config.py index 73ba4710..2fd80db0 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # diff --git a/cdist/core/__init__.py b/cdist/core/__init__.py index 66ee00a5..5dafd061 100644 --- a/cdist/core/__init__.py +++ b/cdist/core/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -23,7 +24,6 @@ from cdist.core.cdist_type import CdistType from cdist.core.cdist_type import NoSuchTypeError from cdist.core.cdist_object import CdistObject from cdist.core.cdist_object import IllegalObjectIdError -from cdist.core.cdist_object import OBJECT_MARKER from cdist.core.explorer import Explorer from cdist.core.manifest import Manifest from cdist.core.code import Code diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index e8c58a67..d13c33dd 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -32,9 +32,6 @@ from cdist.util import fsproperty log = logging.getLogger(__name__) -OBJECT_MARKER = '.cdist' - - class IllegalObjectIdError(cdist.Error): def __init__(self, object_id, message=None): self.object_id = object_id @@ -66,16 +63,18 @@ class CdistObject(object): STATE_RUNNING = "running" STATE_DONE = "done" - def __init__(self, cdist_type, base_path, object_id=''): + def __init__(self, cdist_type, base_path, object_marker=".cdist", object_id=''): self.cdist_type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id + self.object_marker = object_marker + self.validate_object_id() self.sanitise_object_id() self.name = self.join_name(self.cdist_type.name, self.object_id) - self.path = os.path.join(self.cdist_type.path, self.object_id, OBJECT_MARKER) + self.path = os.path.join(self.cdist_type.path, self.object_id, self.object_marker) self.absolute_path = os.path.join(self.base_path, self.path) self.code_local_path = os.path.join(self.path, "code-local") self.code_remote_path = os.path.join(self.path, "code-remote") @@ -97,7 +96,7 @@ class CdistObject(object): def list_object_names(cls, object_base_path): """Return a list of object names""" for path, dirs, files in os.walk(object_base_path): - if OBJECT_MARKER in dirs: + if self.object_marker in dirs: yield os.path.relpath(path, object_base_path) @staticmethod @@ -127,8 +126,8 @@ class CdistObject(object): """Validate the given object_id and raise IllegalObjectIdError if it's not valid. """ if self.object_id: - if OBJECT_MARKER in self.object_id.split(os.sep): - raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) + if self.object_marker in self.object_id.split(os.sep): + raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % self.object_marker) if '//' in self.object_id: raise IllegalObjectIdError(self.object_id, 'object_id may not contain //') if self.object_id == '.': diff --git a/docs/dev/logs/2014-05-06.object-marker b/docs/dev/logs/2014-05-06.object-marker new file mode 100644 index 00000000..4878a2f5 --- /dev/null +++ b/docs/dev/logs/2014-05-06.object-marker @@ -0,0 +1,14 @@ +Change object marker from .cdist to .cdist-TEMPNAME to allow using +object ids that contain / are .cdist. + +Changes required: + + cdist/emulator.py: + needs to know suffix/name + tests: + allow object id named /.cdist + tests: + many + cdist/config.py: + have suffix + From 1e582dceece14690034d609f8610269c6cfa37dc Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 23 Jul 2014 09:22:03 +0200 Subject: [PATCH 0004/1332] bugfix of raw_command with raw_command, you can set env variables in crontab, but cron don't accept env vars if the definition is like this: SHELL=/bin/bash # marker of something ... so we need to make sure that raw commands are not apended by a marker --- cdist/conf/type/__cron/explorer/entry | 7 ++++++- cdist/conf/type/__cron/gencode-remote | 14 +++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) mode change 100755 => 100644 cdist/conf/type/__cron/gencode-remote diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry index c3bf02d2..2167e045 100644 --- a/cdist/conf/type/__cron/explorer/entry +++ b/cdist/conf/type/__cron/explorer/entry @@ -22,4 +22,9 @@ name="$__object_name" user="$(cat "$__object/parameter/user")" -crontab -u $user -l 2>/dev/null | grep "# $name\$" || true +if [ -f "$__object/parameter/raw_command" ]; then + command="$(cat "$__object/parameter/command")" + crontab -u $user -l 2>/dev/null | grep "^$command\$" || true +else + crontab -u $user -l 2>/dev/null | grep "# $name\$" || true +fi diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote old mode 100755 new mode 100644 index 77a63b9b..f5c1cc62 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -26,7 +26,7 @@ command="$(cat "$__object/parameter/command")" if [ -f "$__object/parameter/raw" ]; then raw="$(cat "$__object/parameter/raw")" - entry="$raw $command" + entry="$raw $command # $name" elif [ -f "$__object/parameter/raw_command" ]; then entry="$command" else @@ -35,10 +35,9 @@ else day_of_month="$(cat "$__object/parameter/day_of_month" 2>/dev/null || echo "*")" month="$(cat "$__object/parameter/month" 2>/dev/null || echo "*")" day_of_week="$(cat "$__object/parameter/day_of_week" 2>/dev/null || echo "*")" - entry="$minute $hour $day_of_month $month $day_of_week $command" + entry="$minute $hour $day_of_month $month $day_of_week $command # $name" fi -entry="$entry # $name" mkdir "$__object/files" echo "$entry" > "$__object/files/entry" @@ -85,7 +84,12 @@ case "$state_should" in echo ") | crontab -u $user -" ;; absent) - echo "( crontab -u $user -l 2>/dev/null | grep -v -E \"$filter\" 2>/dev/null || true ) | \\" - echo "grep -v \"# $name\\$\" | crontab -u $user -" + if [ -f "$__object/parameter/raw_command" ]; then + echo "( crontab -u $user -l 2>/dev/null | grep -v -E \"$filter\" 2>/dev/null || true ) | \\" + echo "grep -v \"^$entry\\$\" | crontab -u $user -" + else + echo "( crontab -u $user -l 2>/dev/null | grep -v -E \"$filter\" 2>/dev/null || true ) | \\" + echo "grep -v \"# $name\\$\" | crontab -u $user -" + fi ;; esac From 82bcc83d4164c5e83b5ccde75d74637bceca0887 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Mon, 18 Aug 2014 19:09:19 +0200 Subject: [PATCH 0005/1332] add new __package_dpkg type --- cdist/conf/type/__package_dpkg/gencode-local | 57 +++++++++++++++++++ cdist/conf/type/__package_dpkg/man.text | 47 +++++++++++++++ .../type/__package_dpkg/parameter/required | 1 + cdist/conf/type/__package_dpkg/singleton | 0 4 files changed, 105 insertions(+) create mode 100755 cdist/conf/type/__package_dpkg/gencode-local create mode 100644 cdist/conf/type/__package_dpkg/man.text create mode 100644 cdist/conf/type/__package_dpkg/parameter/required create mode 100644 cdist/conf/type/__package_dpkg/singleton diff --git a/cdist/conf/type/__package_dpkg/gencode-local b/cdist/conf/type/__package_dpkg/gencode-local new file mode 100755 index 00000000..9704c46c --- /dev/null +++ b/cdist/conf/type/__package_dpkg/gencode-local @@ -0,0 +1,57 @@ +#!/bin/sh +# +# 2013 Tomas Pospisek (tpo_deb sourcepole.ch) +# +# This file is based on cdist's __file/gencode-local and 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 . +# +# +# This __package_dpkg type does not check whether a *.deb package is +# allready installed. It just copies the *.deb package over to the +# destination and installs it. We could use __package_apt to check +# whether a *.deb package is allready installed and only install it +# if we're given a --force argument or similar (would be clever not +# to conflict with dpkg's --force options). But currently we don't +# do any checks or --force'ing. +# + +local_package_path=$( cat "$__object/parameter/install" ) +package=$( basename "$local_package_path" ) + +if [ ! -f "$local_package_path" ]; then + echo "Package \"$local_package_path\" does not exist." >&2 + exit 1 +fi + +# upload package to temp directory +temp_dir="cdist.XXXXXXXXXX" +cat << DONE +destination_dir="\$($__remote_exec $__target_host "mktemp -d $temp_dir")" +DONE + +cat << DONE +$__remote_copy $local_package_path ${__target_host}:\$destination_dir +DONE + +# install package +echo "3" >&2 +cat << DONE +$__remote_exec $__target_host "dpkg -i \"\$destination_dir/$package\"" +DONE + +# clean up: remove tmp_dir and contents on remote host +cat << DONE +$__remote_exec $__target_host "rm -rf \"\$destination_dir\"" +DONE diff --git a/cdist/conf/type/__package_dpkg/man.text b/cdist/conf/type/__package_dpkg/man.text new file mode 100644 index 00000000..e6a67e79 --- /dev/null +++ b/cdist/conf/type/__package_dpkg/man.text @@ -0,0 +1,47 @@ +cdist-type__package_dpkg(7) +========================== +Tomas Pospisek + + +NAME +---- +cdist-type__package_dpkg - Manage packages with dpkg + + +DESCRIPTION +----------- +dpkg is usually used on Debian and variants (like Ubuntu) to +install packages. + + +REQUIRED PARAMETERS +------------------- +install:: + Specifies the local path to the *.deb package to be installed + + +OPTIONAL PARAMETERS +------------------- +None + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Install foo package +__package_dpkg --install /tmp/foo_0.1_all.deb +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__package(7) + + +COPYING +------- +Copyright \(C) 2013 Tomas Pospisek. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). +This type is based on __package_apt diff --git a/cdist/conf/type/__package_dpkg/parameter/required b/cdist/conf/type/__package_dpkg/parameter/required new file mode 100644 index 00000000..7c32f559 --- /dev/null +++ b/cdist/conf/type/__package_dpkg/parameter/required @@ -0,0 +1 @@ +install diff --git a/cdist/conf/type/__package_dpkg/singleton b/cdist/conf/type/__package_dpkg/singleton new file mode 100644 index 00000000..e69de29b From d8af4d3ad5e53b8aac3b571aac969f36a63d2d6b Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Mon, 18 Aug 2014 19:11:28 +0200 Subject: [PATCH 0006/1332] fix email address --- cdist/conf/type/__package_dpkg/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_dpkg/man.text b/cdist/conf/type/__package_dpkg/man.text index e6a67e79..6dc07c41 100644 --- a/cdist/conf/type/__package_dpkg/man.text +++ b/cdist/conf/type/__package_dpkg/man.text @@ -1,6 +1,6 @@ cdist-type__package_dpkg(7) ========================== -Tomas Pospisek +Tomas Pospisek NAME From 8b53003a16d1f80a6e3031a58f29b7bb60b264cd Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Tue, 9 Sep 2014 15:42:30 +0200 Subject: [PATCH 0007/1332] add __postgres_extension type --- .../type/__postgres_extension/gencode-remote | 39 ++++++++++++++ cdist/conf/type/__postgres_extension/man.text | 52 +++++++++++++++++++ .../parameter/default/state | 1 + .../__postgres_extension/parameter/optional | 1 + 4 files changed, 93 insertions(+) create mode 100755 cdist/conf/type/__postgres_extension/gencode-remote create mode 100644 cdist/conf/type/__postgres_extension/man.text create mode 100644 cdist/conf/type/__postgres_extension/parameter/default/state create mode 100644 cdist/conf/type/__postgres_extension/parameter/optional diff --git a/cdist/conf/type/__postgres_extension/gencode-remote b/cdist/conf/type/__postgres_extension/gencode-remote new file mode 100755 index 00000000..3408df86 --- /dev/null +++ b/cdist/conf/type/__postgres_extension/gencode-remote @@ -0,0 +1,39 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2013 Tomas Pospisek (tpo_deb at sourcepole.ch) +# +# This type was created by Tomas Pospisek based on the +#__postgres_role type by Steven Armstrong +# +# 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 . +# + +dbname=$( echo "$__object_id" | cut -d":" -f1 ) +extension=$( echo "$__object_id" | cut -d":" -f2 ) + +state_should=$( cat "$__object/parameter/state" ) + +case "$state_should" in + present) + cmd="CREATE EXTENSION IF NOT EXISTS $extension" + echo "su - postgres -c 'psql -c \"$cmd\" \"$dbname\"'" + ;; + absent) + cmd="DROP EXTENSION IF EXISTS $extenstion" + echo "su - postgres -c 'psql -c \"$cmd\" \"$dbname\"'" + ;; +esac diff --git a/cdist/conf/type/__postgres_extension/man.text b/cdist/conf/type/__postgres_extension/man.text new file mode 100644 index 00000000..6d722d68 --- /dev/null +++ b/cdist/conf/type/__postgres_extension/man.text @@ -0,0 +1,52 @@ +cdist-type__postgres_extension(7) +================================= +Tomas Pospisek + + +NAME +---- +cdist-type__postgres_extension - manage postgres extensions + + +DESCRIPTION +----------- +This cdist type allows you to create or drop postgres extensions. + +The object you need to pass to __postgres_extension consists of +the database name and the extension name joined by a colon in the +following form: + + dbname:extension + +f.ex. + + rails_test:unaccent + + +OPTIONAL PARAMETERS +------------------- +state:: + Either "present" or "absent", defaults to "present" + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postgres_extension rails_test:unaccent +__postgres_extension --present rails_test:unaccent +__postgres_extension --absent rails_test:unaccent +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__postgres_database(7) +- http://www.postgresql.org/docs/current/static/sql-createextension.html + + +COPYING +------- +Copyright \(C) 2014 Tomas Pospisek. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__postgres_extension/parameter/default/state b/cdist/conf/type/__postgres_extension/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__postgres_extension/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__postgres_extension/parameter/optional b/cdist/conf/type/__postgres_extension/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__postgres_extension/parameter/optional @@ -0,0 +1 @@ +state From 44941137d67d3a534b066bc4ddc93a466ca4e180 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Wed, 10 Sep 2014 11:21:09 +0200 Subject: [PATCH 0008/1332] change implementation and API of __package_dpkg __package_dpkg wasn't working as intended - being a singleton meant that it could only install one package. Now we missuse /var/cache/apt/archives to copy our package into and `dpkg -i` from there --- .../{gencode-local => gencode-remote} | 29 +--------------- cdist/conf/type/__package_dpkg/man.text | 21 +++++------- cdist/conf/type/__package_dpkg/manifest | 34 +++++++++++++++++++ .../type/__package_dpkg/parameter/required | 2 +- cdist/conf/type/__package_dpkg/singleton | 0 5 files changed, 45 insertions(+), 41 deletions(-) rename cdist/conf/type/__package_dpkg/{gencode-local => gencode-remote} (62%) create mode 100644 cdist/conf/type/__package_dpkg/manifest delete mode 100644 cdist/conf/type/__package_dpkg/singleton diff --git a/cdist/conf/type/__package_dpkg/gencode-local b/cdist/conf/type/__package_dpkg/gencode-remote similarity index 62% rename from cdist/conf/type/__package_dpkg/gencode-local rename to cdist/conf/type/__package_dpkg/gencode-remote index 9704c46c..d4186e66 100755 --- a/cdist/conf/type/__package_dpkg/gencode-local +++ b/cdist/conf/type/__package_dpkg/gencode-remote @@ -27,31 +27,4 @@ # do any checks or --force'ing. # -local_package_path=$( cat "$__object/parameter/install" ) -package=$( basename "$local_package_path" ) - -if [ ! -f "$local_package_path" ]; then - echo "Package \"$local_package_path\" does not exist." >&2 - exit 1 -fi - -# upload package to temp directory -temp_dir="cdist.XXXXXXXXXX" -cat << DONE -destination_dir="\$($__remote_exec $__target_host "mktemp -d $temp_dir")" -DONE - -cat << DONE -$__remote_copy $local_package_path ${__target_host}:\$destination_dir -DONE - -# install package -echo "3" >&2 -cat << DONE -$__remote_exec $__target_host "dpkg -i \"\$destination_dir/$package\"" -DONE - -# clean up: remove tmp_dir and contents on remote host -cat << DONE -$__remote_exec $__target_host "rm -rf \"\$destination_dir\"" -DONE +echo "dpkg -i /var/cache/apt/archives/$__object_id" diff --git a/cdist/conf/type/__package_dpkg/man.text b/cdist/conf/type/__package_dpkg/man.text index 6dc07c41..ae98be99 100644 --- a/cdist/conf/type/__package_dpkg/man.text +++ b/cdist/conf/type/__package_dpkg/man.text @@ -10,27 +10,24 @@ cdist-type__package_dpkg - Manage packages with dpkg DESCRIPTION ----------- -dpkg is usually used on Debian and variants (like Ubuntu) to -install packages. +__package_dpkg is used on Debian and variants (like Ubuntu) to +install packages that are provided locally as *.deb files. + +The object given to __package_dpkg must be the name of the deb package. REQUIRED PARAMETERS ------------------- -install:: - Specifies the local path to the *.deb package to be installed - - -OPTIONAL PARAMETERS -------------------- -None - +source:: + path to the *.deb package EXAMPLES -------- -------------------------------------------------------------------------------- -# Install foo package -__package_dpkg --install /tmp/foo_0.1_all.deb +# Install foo and bar packages +__package_dpkg --source /tmp/foo_0.1_all.deb foo_0.1_all.deb +__package_dpkg --source $__type/files/bar_1.4.deb bar_1.4.deb -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__package_dpkg/manifest b/cdist/conf/type/__package_dpkg/manifest new file mode 100644 index 00000000..ff477c2d --- /dev/null +++ b/cdist/conf/type/__package_dpkg/manifest @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 2013 Tomas Pospisek (tpo_deb sourcepole.ch) +# +# 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 . +# +# +# This __package_dpkg type does not check whether a *.deb package is +# allready installed. It just copies the *.deb package over to the +# destination and installs it. We could use __package_apt to check +# whether a *.deb package is allready installed and only install it +# if we're given a --force argument or similar (would be clever not +# to conflict with dpkg's --force options). But currently we don't +# do any checks or --force'ing. + + +package_path=$( cat "$__object/parameter/source" ) +package=$( basename "$__object_id" ) + +__file "/var/cache/apt/archives/$package" \ + --source "$package_path" \ + --state present + diff --git a/cdist/conf/type/__package_dpkg/parameter/required b/cdist/conf/type/__package_dpkg/parameter/required index 7c32f559..5a18cd2f 100644 --- a/cdist/conf/type/__package_dpkg/parameter/required +++ b/cdist/conf/type/__package_dpkg/parameter/required @@ -1 +1 @@ -install +source diff --git a/cdist/conf/type/__package_dpkg/singleton b/cdist/conf/type/__package_dpkg/singleton deleted file mode 100644 index e69de29b..00000000 From 73c77dd2d33e38f4cac6939f7a2739930db20502 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Mar 2015 15:02:26 +0100 Subject: [PATCH 0009/1332] Let core use random .cdist directory for objects Signed-off-by: Nico Schottelius --- cdist/__init__.py | 4 +--- cdist/config.py | 5 ++-- cdist/core/__init__.py | 2 +- cdist/core/cdist_object.py | 28 +++++++++++++---------- cdist/emulator.py | 14 ++++++++---- cdist/exec/local.py | 21 +++++++++++++++-- cdist/shell.py | 2 +- docs/dev/logs/2015-02-22.allow_dot_cdist | 29 ++++++++++++++++++++++++ 8 files changed, 79 insertions(+), 26 deletions(-) create mode 100644 docs/dev/logs/2015-02-22.allow_dot_cdist diff --git a/cdist/__init__.py b/cdist/__init__.py index 20c76b31..4454a3ac 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2015 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -41,8 +41,6 @@ BANNER = """ "P' "" "" """ -DOT_CDIST = ".cdist" - REMOTE_COPY = "scp -o User=root -q" REMOTE_EXEC = "ssh -o User=root -q" diff --git a/cdist/config.py b/cdist/config.py index a0c787ac..bba9bfcb 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2014 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2015 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -162,7 +162,8 @@ class Config(object): def object_list(self): """Short name for object list retrieval""" for cdist_object in core.CdistObject.list_objects(self.local.object_path, - self.local.type_path): + self.local.type_path, + self.local.object_marker_name): if cdist_object.cdist_type.is_install: self.log.debug("Running in config mode, ignoring install object: {0}".format(cdist_object)) else: diff --git a/cdist/core/__init__.py b/cdist/core/__init__.py index 5dafd061..d773fc01 100644 --- a/cdist/core/__init__.py +++ b/cdist/core/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2014 Nico Schottelius (nico-cdist at schottelius.org) +# 2014-2015 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index d13c33dd..ba0fdf11 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2015 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. @@ -63,7 +63,7 @@ class CdistObject(object): STATE_RUNNING = "running" STATE_DONE = "done" - def __init__(self, cdist_type, base_path, object_marker=".cdist", object_id=''): + def __init__(self, cdist_type, base_path, object_marker, object_id): self.cdist_type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id @@ -75,30 +75,34 @@ class CdistObject(object): self.name = self.join_name(self.cdist_type.name, self.object_id) self.path = os.path.join(self.cdist_type.path, self.object_id, self.object_marker) + self.absolute_path = os.path.join(self.base_path, self.path) self.code_local_path = os.path.join(self.path, "code-local") self.code_remote_path = os.path.join(self.path, "code-remote") self.parameter_path = os.path.join(self.path, "parameter") @classmethod - def list_objects(cls, object_base_path, type_base_path): + def list_objects(cls, object_base_path, type_base_path, object_marker): """Return a list of object instances""" - for object_name in cls.list_object_names(object_base_path): + for object_name in cls.list_object_names(object_base_path, object_marker): type_name, object_id = cls.split_name(object_name) - yield cls(cdist.core.CdistType(type_base_path, type_name), object_base_path, object_id=object_id) + yield cls(cdist.core.CdistType(type_base_path, type_name), + base_path=object_base_path, + object_marker=object_marker, + object_id=object_id) + + @classmethod + def list_object_names(cls, object_base_path, object_marker): + """Return a list of object names""" + for path, dirs, files in os.walk(object_base_path): + if object_marker in dirs: + yield os.path.relpath(path, object_base_path) @classmethod def list_type_names(cls, object_base_path): """Return a list of type names""" return os.listdir(object_base_path) - @classmethod - def list_object_names(cls, object_base_path): - """Return a list of object names""" - for path, dirs, files in os.walk(object_base_path): - if self.object_marker in dirs: - yield os.path.relpath(path, object_base_path) - @staticmethod def split_name(object_name): """split_name('__type_name/the/object_id') -> ('__type_name', 'the/object_id') diff --git a/cdist/emulator.py b/cdist/emulator.py index 41834fbf..abd8c884 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2015 Nico Schottelius (nico-cdist at schottelius.org) # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # 2014 Daniel Heule (hda at sfs.biz) # @@ -64,9 +64,10 @@ class Emulator(object): self.global_path = self.env['__global'] self.target_host = self.env['__target_host'] - # Internally only + # Internal variables self.object_source = self.env['__cdist_manifest'] self.type_base_path = self.env['__cdist_type_base_path'] + self.object_marker = self.env['__cdist_object_marker'] except KeyError as e: raise MissingRequiredEnvironmentVariableError(e.args[0]) @@ -131,13 +132,16 @@ class Emulator(object): self.log.debug('Args: %s' % self.args) def setup_object(self): - # Setup object_id - FIXME: unset / do not setup anymore! - if not self.cdist_type.is_singleton: + # Setup object - and ensure it is not in args + if self.cdist_type.is_singleton: + self.object_id = False + else: self.object_id = self.args.object_id[0] del self.args.object_id # Instantiate the cdist object we are defining - self.cdist_object = core.CdistObject(self.cdist_type, self.object_base_path, self.object_id) + self.cdist_object = core.CdistObject(self.cdist_type, + self.object_base_path, self.object_marker, self.object_id) # Create object with given parameters self.parameters = {} diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 2f75ffd4..40f34e25 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2015 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -66,9 +66,9 @@ class Local(object): self._init_log() self._init_permissions() self._init_paths() + self._init_object_marker() self._init_conf_dirs() - @property def dist_conf_dir(self): return os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")) @@ -103,6 +103,12 @@ class Local(object): self.type_path = os.path.join(self.conf_path, "type") + def _init_object_marker(self): + self.object_marker_file = os.path.join(self.base_path, "object_marker") + + # Does not need to be secure - just randomly different from .cdist + self.object_marker_name = tempfile.mktemp(prefix='.cdist-', dir='') + def _init_conf_dirs(self): self.conf_dirs = [] @@ -125,6 +131,7 @@ class Local(object): def _init_directories(self): self.mkdir(self.conf_path) self.mkdir(self.global_explorer_out_path) + self.mkdir(self.object_path) self.mkdir(self.bin_path) def create_files_dirs(self): @@ -132,6 +139,13 @@ class Local(object): self._create_conf_path_and_link_conf_dirs() self._create_messages() self._link_types_for_emulator() + self._setup_object_marker_file() + + def _setup_object_marker_file(self): + with open(self.object_marker_file, 'w') as fd: + fd.write("%s\n" % self.object_marker_name) + + self.log.debug("Object marker %s saved in %s" % (self.object_marker_name, self.object_marker_file)) def _init_cache_dir(self, cache_dir): @@ -166,6 +180,9 @@ class Local(object): # Export __target_host for use in __remote_{copy,exec} scripts env['__target_host'] = self.target_host + # Export for emulator + env['__cdist_object_marker'] = self.object_marker_name + if message_prefix: message = cdist.message.Message(message_prefix, self.messages_path) env.update(message.env) diff --git a/cdist/shell.py b/cdist/shell.py index 8ca68115..d0921bc9 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013-2015 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # diff --git a/docs/dev/logs/2015-02-22.allow_dot_cdist b/docs/dev/logs/2015-02-22.allow_dot_cdist new file mode 100644 index 00000000..58a1b041 --- /dev/null +++ b/docs/dev/logs/2015-02-22.allow_dot_cdist @@ -0,0 +1,29 @@ +- locate code that references .cdist + - cdist_object.py +- need to change code that handles objects? + - setup object marker + exec/local.py + - cdist/emulator.py + - need to know the marker name + - shell.py + - test/manifest/__init__.py + - core/code.py: + - core/manifest.py: + - core/manifest.py: + - list_object_names() needs to know the marker -- used BY: + - list_objects + - cdist/test/cdist_object/__init__.py + - cdist/config.py + - cdist/test/cdist_object/__init__.py + + - list_object_names + - needs to have object_marker + +- or modify object code to load name +- setup a per-run random name + - local.py +- use the per-run random name +- create test + + def __init__(self, cdist_type, base_path, object_marker=".cdist", object_id=''): + From fa6e389fdd7da946a633a4b3bfa46361adc44129 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Mar 2015 15:23:53 +0100 Subject: [PATCH 0010/1332] cannot use False for object id, as it is being used for os.path.join() in object Signed-off-by: Nico Schottelius --- cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index abd8c884..3f553412 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -134,7 +134,7 @@ class Emulator(object): def setup_object(self): # Setup object - and ensure it is not in args if self.cdist_type.is_singleton: - self.object_id = False + self.object_id = '' else: self.object_id = self.args.object_id[0] del self.args.object_id From d08c29b581545ce5751c6ed7d579193c873e589b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Mar 2015 18:32:47 +0100 Subject: [PATCH 0011/1332] fix most test cases broken by no-dot-cdist change Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 3 +- cdist/test/cdist_object/__init__.py | 98 +++++++++++++------ .../fixtures/object/__first/.keep | 0 .../object/__first/child/.cdist/.keep | 0 .../fixtures/object/__first/dog/.cdist/.keep | 0 .../fixtures/object/__first/man/.cdist/.keep | 0 .../object/__first/woman/.cdist/.keep | 0 .../fixtures/object/__second/.keep | 0 .../object/__second/on-the/.cdist/.keep | 0 .../object/__second/under-the/.cdist/.keep | 0 .../fixtures/object/__third/.keep | 0 .../fixtures/object/__third/moon/.cdist/.keep | 0 .../object/__third/moon/.cdist/parameter/name | 1 - .../__third/moon/.cdist/parameter/planet | 1 - cdist/test/code/__init__.py | 4 +- cdist/test/config/__init__.py | 4 +- cdist/test/emulator/__init__.py | 31 +++--- cdist/test/explorer/__init__.py | 6 +- cdist/test/manifest/__init__.py | 2 +- 19 files changed, 97 insertions(+), 53 deletions(-) delete mode 100644 cdist/test/cdist_object/fixtures/object/__first/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__first/child/.cdist/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__first/dog/.cdist/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__first/man/.cdist/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__first/woman/.cdist/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__second/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__second/on-the/.cdist/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__second/under-the/.cdist/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__third/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/.keep delete mode 100644 cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/name delete mode 100644 cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/planet diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index ba0fdf11..8c6ee9c9 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -158,12 +158,13 @@ class CdistObject(object): base_path = self.base_path type_path = self.cdist_type.base_path + object_marker = self.object_marker type_name, object_id = self.split_name(object_name) cdist_type = self.cdist_type.__class__(type_path, type_name) - return self.__class__(cdist_type, base_path, object_id=object_id) + return self.__class__(cdist_type, base_path, object_marker, object_id=object_id) def __repr__(self): return '' % self.name diff --git a/cdist/test/cdist_object/__init__.py b/cdist/test/cdist_object/__init__.py index 3c25a959..9c075acb 100644 --- a/cdist/test/cdist_object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2015 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. @@ -23,6 +23,7 @@ import os import shutil +import tempfile from cdist import test from cdist import core @@ -32,37 +33,48 @@ import cdist import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') -object_base_path = op.join(fixtures, 'object') type_base_path = op.join(fixtures, 'type') +OBJECT_MARKER_NAME = '.cdist-pseudo-random' + +expected_object_names = sorted([ + '__first/child', + '__first/dog', + '__first/man', + '__first/woman', + '__second/on-the', + '__second/under-the', + '__third/moon']) + + class ObjectClassTestCase(test.CdistTestCase): def setUp(self): - self.expected_object_names = sorted([ - '__first/child', - '__first/dog', - '__first/man', - '__first/woman', - '__second/on-the', - '__second/under-the', - '__third/moon']) + + self.tempdir = tempfile.mkdtemp(prefix="cdist.test") + self.object_base_path = self.tempdir self.expected_objects = [] - for cdist_object_name in self.expected_object_names: + for cdist_object_name in expected_object_names: cdist_type, cdist_object_id = cdist_object_name.split("/", 1) - cdist_object = core.CdistObject(core.CdistType(type_base_path, cdist_type), object_base_path, cdist_object_id) + cdist_object = core.CdistObject(core.CdistType(type_base_path, cdist_type), self.object_base_path, + OBJECT_MARKER_NAME, cdist_object_id) + cdist_object.create() self.expected_objects.append(cdist_object) + def tearDown(self): + shutil.rmtree(self.tempdir) + def test_list_object_names(self): - found_object_names = sorted(list(core.CdistObject.list_object_names(object_base_path))) - self.assertEqual(found_object_names, self.expected_object_names) + found_object_names = sorted(list(core.CdistObject.list_object_names(self.object_base_path, OBJECT_MARKER_NAME))) + self.assertEqual(found_object_names, expected_object_names) def test_list_type_names(self): - type_names = list(cdist.core.CdistObject.list_type_names(object_base_path)) + type_names = list(cdist.core.CdistObject.list_type_names(self.object_base_path)) self.assertEqual(sorted(type_names), ['__first', '__second', '__third']) def test_list_objects(self): - found_objects = sorted(list(core.CdistObject.list_objects(object_base_path, type_base_path))) + found_objects = sorted(list(core.CdistObject.list_objects(self.object_base_path, type_base_path, OBJECT_MARKER_NAME))) self.assertEqual(found_objects, self.expected_objects) def test_create_singleton(self): @@ -77,41 +89,65 @@ class ObjectClassTestCase(test.CdistTestCase): self.expected_objects[0].object_from_name("__first") class ObjectIdTestCase(test.CdistTestCase): + + def setUp(self): + self.tempdir = tempfile.mkdtemp(prefix="cdist.test") + self.object_base_path = self.tempdir + + self.expected_objects = [] + for cdist_object_name in expected_object_names: + cdist_type, cdist_object_id = cdist_object_name.split("/", 1) + cdist_object = core.CdistObject(core.CdistType(type_base_path, cdist_type), self.object_base_path, + OBJECT_MARKER_NAME, cdist_object_id) + cdist_object.create() + self.expected_objects.append(cdist_object) + + def tearDown(self): + shutil.rmtree(self.tempdir) + def test_object_id_contains_double_slash(self): cdist_type = core.CdistType(type_base_path, '__third') illegal_object_id = '/object_id//may/not/contain/double/slash' with self.assertRaises(core.IllegalObjectIdError): - core.CdistObject(cdist_type, object_base_path, illegal_object_id) + core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) def test_object_id_contains_object_marker(self): cdist_type = core.CdistType(type_base_path, '__third') - illegal_object_id = 'object_id/may/not/contain/%s/anywhere' % core.OBJECT_MARKER + illegal_object_id = 'object_id/may/not/contain/%s/anywhere' % OBJECT_MARKER_NAME with self.assertRaises(core.IllegalObjectIdError): - core.CdistObject(cdist_type, object_base_path, illegal_object_id) + core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) def test_object_id_contains_object_marker_string(self): cdist_type = core.CdistType(type_base_path, '__third') - illegal_object_id = 'object_id/may/contain_%s_in_filename' % core.OBJECT_MARKER - core.CdistObject(cdist_type, object_base_path, illegal_object_id) + illegal_object_id = 'object_id/may/contain_%s_in_filename' % OBJECT_MARKER_NAME + core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) # if we get here, the test passed def test_object_id_contains_only_dot(self): cdist_type = core.CdistType(type_base_path, '__third') illegal_object_id = '.' with self.assertRaises(core.IllegalObjectIdError): - core.CdistObject(cdist_type, object_base_path, illegal_object_id) + core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) def test_object_id_on_singleton_type(self): cdist_type = core.CdistType(type_base_path, '__test_singleton') illegal_object_id = 'object_id' with self.assertRaises(core.IllegalObjectIdError): - core.CdistObject(cdist_type, object_base_path, illegal_object_id) + core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) class ObjectTestCase(test.CdistTestCase): def setUp(self): + self.tempdir = tempfile.mkdtemp(prefix="cdist.test") + self.object_base_path = self.tempdir + self.cdist_type = core.CdistType(type_base_path, '__third') - self.cdist_object = core.CdistObject(self.cdist_type, object_base_path, 'moon') + self.cdist_object = core.CdistObject(self.cdist_type, self.object_base_path, OBJECT_MARKER_NAME, 'moon') + self.cdist_object.create() + + self.cdist_object.parameters['planet'] = 'Saturn' + self.cdist_object.parameters['name'] = 'Prometheus' + def tearDown(self): self.cdist_object.prepared = False @@ -121,6 +157,8 @@ class ObjectTestCase(test.CdistTestCase): self.cdist_object.code_remote = '' self.cdist_object.state = '' + shutil.rmtree(self.tempdir) + def test_name(self): self.assertEqual(self.cdist_object.name, '__third/moon') @@ -128,22 +166,22 @@ class ObjectTestCase(test.CdistTestCase): self.assertEqual(self.cdist_object.object_id, 'moon') def test_path(self): - self.assertEqual(self.cdist_object.path, '__third/moon/.cdist') + self.assertEqual(self.cdist_object.path, "__third/moon/%s" % OBJECT_MARKER_NAME) def test_absolute_path(self): - self.assertEqual(self.cdist_object.absolute_path, os.path.join(object_base_path, '__third/moon/.cdist')) + self.assertEqual(self.cdist_object.absolute_path, os.path.join(self.object_base_path, "__third/moon/%s" % OBJECT_MARKER_NAME)) def test_code_local_path(self): - self.assertEqual(self.cdist_object.code_local_path, '__third/moon/.cdist/code-local') + self.assertEqual(self.cdist_object.code_local_path, "__third/moon/%s/code-local" % OBJECT_MARKER_NAME) def test_code_remote_path(self): - self.assertEqual(self.cdist_object.code_remote_path, '__third/moon/.cdist/code-remote') + self.assertEqual(self.cdist_object.code_remote_path, "__third/moon/%s/code-remote" % OBJECT_MARKER_NAME) def test_parameter_path(self): - self.assertEqual(self.cdist_object.parameter_path, '__third/moon/.cdist/parameter') + self.assertEqual(self.cdist_object.parameter_path, "__third/moon/%s/parameter" % OBJECT_MARKER_NAME) def test_explorer_path(self): - self.assertEqual(self.cdist_object.explorer_path, '__third/moon/.cdist/explorer') + self.assertEqual(self.cdist_object.explorer_path, "__third/moon/%s/explorer" % OBJECT_MARKER_NAME) def test_parameters(self): expected_parameters = {'planet': 'Saturn', 'name': 'Prometheus'} diff --git a/cdist/test/cdist_object/fixtures/object/__first/.keep b/cdist/test/cdist_object/fixtures/object/__first/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__first/child/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__first/child/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__first/dog/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__first/man/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__first/man/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__first/woman/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__second/.keep b/cdist/test/cdist_object/fixtures/object/__second/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__second/on-the/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__second/under-the/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__third/.keep b/cdist/test/cdist_object/fixtures/object/__third/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/name deleted file mode 100644 index 4129a761..00000000 --- a/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/name +++ /dev/null @@ -1 +0,0 @@ -Prometheus diff --git a/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/planet deleted file mode 100644 index 8e6ee422..00000000 --- a/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/planet +++ /dev/null @@ -1 +0,0 @@ -Saturn diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 796e8a51..689fcff6 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2015 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -61,7 +61,7 @@ class CodeTestCase(test.CdistTestCase): self.code = code.Code(self.target_host, self.local, self.remote) self.cdist_type = core.CdistType(self.local.type_path, '__dump_environment') - self.cdist_object = core.CdistObject(self.cdist_type, self.local.object_path, 'whatever') + self.cdist_object = core.CdistObject(self.cdist_type, self.local.object_path, 'whatever', self.local.object_marker_name) self.cdist_object.create() def tearDown(self): diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index 70501c89..452ce042 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2015 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. @@ -67,7 +67,7 @@ class ConfigRunTestCase(test.CdistTestCase): self.config = cdist.config.Config(self.local, self.remote) - self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) + self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path, self.local.object_marker_name)) self.object_index = dict((o.name, o) for o in self.objects) self.object_names = [o.name for o in self.objects] diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 870d6245..62000931 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -57,10 +57,15 @@ class EmulatorTestCase(test.CdistTestCase): self.manifest = core.Manifest(self.target_host, self.local) self.env = self.manifest.env_initial_manifest(self.script) + self.env['__cdist_object_marker'] = self.local.object_marker_name def tearDown(self): shutil.rmtree(self.temp_dir) +# def test_missing_object_marker_variable(self): +# del self.env['__cdist_object_marker'] +# self.assertRaises(KeyError, emulator.Emulator, argv, env=self.env) + def test_nonexistent_type_exec(self): argv = ['__does-not-exist'] self.assertRaises(core.cdist_type.NoSuchTypeError, emulator.Emulator, argv, env=self.env) @@ -73,7 +78,7 @@ class EmulatorTestCase(test.CdistTestCase): def test_illegal_object_id_requirement(self): argv = ['__file', '/tmp/foobar'] - self.env['require'] = '__file/bad/id/with/.cdist/inside' + self.env['require'] = "__file/bad/id/with/%s/inside" % self.local.object_marker_name emu = emulator.Emulator(argv, env=self.env) self.assertRaises(core.IllegalObjectIdError, emu.run) @@ -118,10 +123,10 @@ class EmulatorTestCase(test.CdistTestCase): emu.run() # now load the objects and verify the require parameter of the objects cdist_type = core.CdistType(self.local.type_path, '__planet') - erde_object = core.CdistObject(cdist_type, self.local.object_path, 'erde') - mars_object = core.CdistObject(cdist_type, self.local.object_path, 'mars') + erde_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'erde') + mars_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'mars') cdist_type = core.CdistType(self.local.type_path, '__file') - file_object = core.CdistObject(cdist_type, self.local.object_path, '/tmp/cdisttest') + file_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, '/tmp/cdisttest') # now test the recorded requirements self.assertTrue(len(erde_object.requirements) == 0) self.assertEqual(list(mars_object.requirements), ['__planet/erde']) @@ -150,7 +155,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): initial_manifest = os.path.join(self.local.manifest_path, "init") self.manifest.run_initial_manifest(initial_manifest) cdist_type = core.CdistType(self.local.type_path, '__saturn') - cdist_object = core.CdistObject(cdist_type, self.local.object_path) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, '') self.manifest.run_type_manifest(cdist_object) expected = ['__planet/Saturn', '__moon/Prometheus'] self.assertEqual(sorted(cdist_object.autorequire), sorted(expected)) @@ -172,6 +177,7 @@ class OverrideTestCase(test.CdistTestCase): self.manifest = core.Manifest(self.target_host, self.local) self.env = self.manifest.env_initial_manifest(self.script) + self.env['__cdist_object_marker'] = self.local.object_marker_name def tearDown(self): shutil.rmtree(self.temp_dir) @@ -211,6 +217,7 @@ class ArgumentsTestCase(test.CdistTestCase): self.manifest = core.Manifest(self.target_host, self.local) self.env = self.manifest.env_initial_manifest(self.script) + self.env['__cdist_object_marker'] = self.local.object_marker_name def tearDown(self): shutil.rmtree(self.temp_dir) @@ -222,7 +229,7 @@ class ArgumentsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, '__arguments_with_dashes') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'some-id') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'some-id') self.assertTrue('with-dash' in cdist_object.parameters) def test_boolean(self): @@ -234,7 +241,7 @@ class ArgumentsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) self.assertTrue('boolean1' in cdist_object.parameters) self.assertFalse('boolean2' in cdist_object.parameters) # empty file -> True @@ -242,17 +249,17 @@ class ArgumentsTestCase(test.CdistTestCase): def test_required_arguments(self): """check whether assigning required parameter works""" + type_name = '__arguments_required' object_id = 'some-id' value = 'some value' argv = [type_name, object_id, '--required1', value, '--required2', value] -# print(self.env) os.environ.update(self.env) emu = emulator.Emulator(argv) emu.run() cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) self.assertTrue('required1' in cdist_object.parameters) self.assertTrue('required2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['required1'], value) @@ -278,7 +285,7 @@ class ArgumentsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) self.assertTrue('optional1' in cdist_object.parameters) self.assertFalse('optional2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['optional1'], value) @@ -293,7 +300,7 @@ class ArgumentsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) self.assertTrue('optional1' in cdist_object.parameters) self.assertFalse('optional2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['optional1'], value) @@ -346,7 +353,7 @@ class StdinTestCase(test.CdistTestCase): ###################################################################### # Create path where stdin should reside at cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) stdin_out_path = os.path.join(cdist_object.absolute_path, 'stdin') ###################################################################### diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 92ef75a3..335d0e32 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -127,7 +127,7 @@ class ExplorerClassTestCase(test.CdistTestCase): def test_transfer_object_parameters(self): cdist_type = core.CdistType(self.local.type_path, '__test_type') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'whatever') cdist_object.create() cdist_object.parameters = {'first': 'first value', 'second': 'second value'} self.explorer.transfer_object_parameters(cdist_object) @@ -137,14 +137,14 @@ class ExplorerClassTestCase(test.CdistTestCase): def test_run_type_explorer(self): cdist_type = core.CdistType(self.local.type_path, '__test_type') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'whatever') self.explorer.transfer_type_explorers(cdist_type) output = self.explorer.run_type_explorer('world', cdist_object) self.assertEqual(output, 'hello\n') def test_run_type_explorers(self): cdist_type = core.CdistType(self.local.type_path, '__test_type') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'whatever') cdist_object.create() self.explorer.run_type_explorers(cdist_object) self.assertEqual(cdist_object.explorers, {'world': 'hello'}) diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index c375a80f..cc60c844 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -84,7 +84,7 @@ class ManifestTestCase(test.CdistTestCase): def test_type_manifest_environment(self): cdist_type = core.CdistType(self.local.type_path, '__dump_environment') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'whatever') handle, output_file = self.mkstemp(dir=self.temp_dir) os.close(handle) os.environ['__cdist_test_out'] = output_file From b51e9daccc993532fee6619b53f0ade987410ea0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Mar 2015 18:51:25 +0100 Subject: [PATCH 0012/1332] fix all tests besides one Signed-off-by: Nico Schottelius --- cdist/test/config/__init__.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index 452ce042..a36567de 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -23,6 +23,7 @@ import os import shutil +import tempfile from cdist import test from cdist import core @@ -35,10 +36,14 @@ import cdist.core.cdist_object import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') -object_base_path = op.join(fixtures, 'object') type_base_path = op.join(fixtures, 'type') add_conf_dir = op.join(fixtures, 'conf') +expected_object_names = sorted([ + '__first/man', + '__second/on-the', + '__third/moon']) + class ConfigRunTestCase(test.CdistTestCase): def setUp(self): @@ -54,6 +59,20 @@ class ConfigRunTestCase(test.CdistTestCase): target_host=self.target_host, base_path=self.local_dir) + # Setup test objects + self.object_base_path = op.join(self.temp_dir, 'object') + + self.objects = [] + for cdist_object_name in expected_object_names: + cdist_type, cdist_object_id = cdist_object_name.split("/", 1) + cdist_object = core.CdistObject(core.CdistType(type_base_path, cdist_type), self.object_base_path, + self.local.object_marker_name, cdist_object_id) + cdist_object.create() + self.objects.append(cdist_object) + + self.object_index = dict((o.name, o) for o in self.objects) + self.object_names = [o.name for o in self.objects] + self.remote_dir = os.path.join(self.temp_dir, "remote") os.mkdir(self.remote_dir) self.remote = cdist.exec.remote.Remote( @@ -62,15 +81,11 @@ class ConfigRunTestCase(test.CdistTestCase): remote_exec=self.remote_exec, base_path=self.remote_dir) - self.local.object_path = object_base_path + self.local.object_path = self.object_base_path self.local.type_path = type_base_path self.config = cdist.config.Config(self.local, self.remote) - self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path, self.local.object_marker_name)) - self.object_index = dict((o.name, o) for o in self.objects) - self.object_names = [o.name for o in self.objects] - def tearDown(self): for o in self.objects: o.requirements = [] From b0321895a7e9810c8f9b5fab6016a835aaed511e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Mar 2015 19:20:06 +0100 Subject: [PATCH 0013/1332] fix all tests Signed-off-by: Nico Schottelius --- cdist/test/emulator/__init__.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 62000931..f90e5320 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2015 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. @@ -323,10 +323,6 @@ class StdinTestCase(test.CdistTestCase): self.local.create_files_dirs() - self.manifest = core.Manifest( - target_host=self.target_host, - local = self.local) - def tearDown(self): os.environ = self.orig_environ shutil.rmtree(self.temp_dir) @@ -347,8 +343,11 @@ class StdinTestCase(test.CdistTestCase): object_id = "cdist-test-id" argv = [type_name, object_id] - initial_manifest_path = "/cdist-test/path/that/does/not/exist" - env = self.manifest.env_initial_manifest(initial_manifest_path) + env = os.environ.copy() + env['__cdist_manifest'] = "/cdist-test/path/that/does/not/exist" + env['__cdist_object_marker'] = self.local.object_marker_name + env['__cdist_type_base_path'] = self.local.type_path + env['__global'] = self.local.base_path ###################################################################### # Create path where stdin should reside at From e225ec3f77b483c0d5238449ff84a7424e7fbf2b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Mar 2015 19:45:41 +0100 Subject: [PATCH 0014/1332] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index f55a01ac..31a23505 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,8 @@ Changelog next: * New type: __firewalld_rule (Nico Schottelius) + * Type __consul_agent: add support for acl options (Steven Armstrong) + * Core: Support object ids '.cdist' (Nico Schottelius) 3.1.11: 2015-02-27 * New type: __staged_file: Manage staged files (Steven Armstrong) From 94e059a29387506ce94af3b395da27a9b5df23e7 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Tue, 12 May 2015 14:26:38 +0200 Subject: [PATCH 0015/1332] Added types __pacman_integrate: converts normal pacman.conf to cdist conform __pacman_conf: Manage pacman.conf with cdist --- cdist/conf/type/__pacman_conf/man.text | 72 ++++ cdist/conf/type/__pacman_conf/manifest | 111 ++++++ .../type/__pacman_conf/parameter/optional | 2 + .../type/__pacman_conf/parameter/required | 3 + .../type/__pacman_integrate/files/mirrorlist | 344 ++++++++++++++++++ .../type/__pacman_integrate/files/options | 6 + .../files/pacman.conf.cdist | 6 + .../files/pacman.conf.pacman | 99 +++++ cdist/conf/type/__pacman_integrate/man.text | 48 +++ cdist/conf/type/__pacman_integrate/manifest | 46 +++ .../__pacman_integrate/parameter/optional | 1 + 11 files changed, 738 insertions(+) create mode 100644 cdist/conf/type/__pacman_conf/man.text create mode 100644 cdist/conf/type/__pacman_conf/manifest create mode 100644 cdist/conf/type/__pacman_conf/parameter/optional create mode 100644 cdist/conf/type/__pacman_conf/parameter/required create mode 100644 cdist/conf/type/__pacman_integrate/files/mirrorlist create mode 100644 cdist/conf/type/__pacman_integrate/files/options create mode 100644 cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist create mode 100644 cdist/conf/type/__pacman_integrate/files/pacman.conf.pacman create mode 100644 cdist/conf/type/__pacman_integrate/man.text create mode 100644 cdist/conf/type/__pacman_integrate/manifest create mode 100644 cdist/conf/type/__pacman_integrate/parameter/optional diff --git a/cdist/conf/type/__pacman_conf/man.text b/cdist/conf/type/__pacman_conf/man.text new file mode 100644 index 00000000..b4905111 --- /dev/null +++ b/cdist/conf/type/__pacman_conf/man.text @@ -0,0 +1,72 @@ +cdist-type__pacman_conf(7) +=================== +Dominique Roux + + +NAME +---- +cdist-type__pacman_conf - Manage pacman configuration + + +DESCRIPTION +----------- +The type allows you to configure options section, add or delete repositories and manage mirrorlists + + +REQUIRED PARAMETERS +------------------- +section:: + 'options' for configure options section + + Otherwise it specifies a repository or a plain file + +key:: + Specifies the key which will be set + + If section = 'options' or file is not set the key will + be checked against available keys from pacman.conf + +value:: + Specifies the value which will be set against the key + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to 'present' + +file:: + Specifies the filename. + + The managed file will be named like 'plain_file_filename' + + If supplied the key will not be checked. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Manage options section in pacman.conf +__pacman_conf options_Architecture --section options --key Architecture --value auto + +# Add new repository +__pacman_conf localrepo_Server --section localrepo --key Server --value "file:///var/cache/pacman/pkg" + +# Add mirror to a mirrorlist +__pacman_conf customlist_Server --file customlist --section customlist --key Server\ + --value "file:///var/cache/pacman/pkg" + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- grep(1) + + +COPYING +------- +Copyright \(C) 2015 Dominique Roux. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest new file mode 100644 index 00000000..f817b2ca --- /dev/null +++ b/cdist/conf/type/__pacman_conf/manifest @@ -0,0 +1,111 @@ +#get params +section=$(cat "$__object/parameter/section") +key=$(cat "$__object/parameter/key") +value=$(cat "$__object/parameter/value") +file=$(cat "$__object/parameter/file" 2>/dev/null || echo "") +state=$(cat "$__object/parameter/state" 2>/dev/null || echo "present" ) + +#path variable default /etc/pacman.d +sec_path="/etc/pacman.d" + +#allowed keys (from man pacman.conf) +allowed_option_keys=( "RootDir" "DBPath" "CacheDir" "GPGDir" "LogFile" "HoldPkg" "IgnorePkg" "IgnoreGroup" "Include" "Architecture" "XferCommand" "NoUpgrade" "NoExtract" "CleanMethod" "SigLevel" "LocalFileSigLevel" "RemoteFileSigLevel" ) +boolean_option_keys=( "UseSyslog" "Color" "UseDelta" "TotalDownload" "CheckSpace" "VerbosePkgLists" ) +allowed_repo_keys=( "Include" "Server" "SigLevel" "Usage" ) + +#set global variables +MATH=1 + +#function for check if array contain string +contains_element() { + + MATCH=1 + + local passed_array + passed_array=(`echo "$2"`) + + for e in "${passed_array[@]}"; do + if [ "${e}" == "${1}" ]; then + MATCH=0 + return 0 + fi + done + MATCH=1 +} + +if [ "${file}" != "" ]; then + __file "${sec_path}/plain_file_${file}"\ + --state exists --mode 666 + + if [ "${state}" == "present" ]; then + + require="__file/${sec_path}/plain_file_${file}" __key_value ${file}_${key}\ + --file ${sec_path}/plain_file_${file} --key ${key} --value ${value} --delimiter ' = ' + + exit 0 + + elif [ "${state}" == "absent" ]; then + require="__file/${sec_path}/plain_file_${file}" __key_value ${file}_${key}\ + --state absent + + else + echo "ERROR: State not found" >&2 + fi +fi + +if [ "${section}" == "options" ]; then + + __file "${sec_path}/${section}"\ + --state exists --mode 666 --source - << eof +[${section}] +eof + #check if key is valid + #check for boolean value + contains_element "${key}" "$(echo ${boolean_option_keys[@]})" + + if [ "${MATCH}" -eq 0 ]; then + if [ "${value}" == "on" ]; then + require="__file/${sec_path}/${section}" __line ${key}_${value}\ + --file ${sec_path}/${section} --line ${key} + elif [ "${value}" == "off" ]; then + require="__file/${sec_path}/${section}" __line ${key}_${value}\ + --file ${sec_path}/${section} --line ${key} --state absent + fi + + else + contains_element "${key}" "$(echo ${allowed_option_keys[@]})" + + if [ "${MATCH}" -eq 0 ]; then + require="__file/${sec_path}/${section}" __key_value ${section}_${key}\ + --file ${sec_path}/${section} --key ${key} --value ${value} --delimiter ' = ' + else + echo "Key is not valid. Have a look at man pacman.conf" >&2 + fi + fi + +else + __file "${sec_path}/repo_${section}"\ + --state exists --mode 666 --source - << eof +[${section}] +eof + if [ "${state}" == "present" ]; then + + #check if key is valid + contains_element "${key}" "$(echo ${allowed_repo_keys[@]})" + if [ ${MATCH} -eq 1 ]; then + exit + fi + + require="__file/${sec_path}/repo_${section}" __key_value ${section}_${key}\ + --file ${sec_path}/repo_${section} --key ${key} --value ${value} --delimiter ' = ' + + elif [ "${state}" == "absent" ]; then + + require="__file/${sec_path}/repo_${section}" __key_value ${section}_${key}\ + --state absent + + else + echo "ERROR: State not found" >&2 + fi + +fi diff --git a/cdist/conf/type/__pacman_conf/parameter/optional b/cdist/conf/type/__pacman_conf/parameter/optional new file mode 100644 index 00000000..5d52aa2e --- /dev/null +++ b/cdist/conf/type/__pacman_conf/parameter/optional @@ -0,0 +1,2 @@ +file +state diff --git a/cdist/conf/type/__pacman_conf/parameter/required b/cdist/conf/type/__pacman_conf/parameter/required new file mode 100644 index 00000000..2f9d59e0 --- /dev/null +++ b/cdist/conf/type/__pacman_conf/parameter/required @@ -0,0 +1,3 @@ +section +key +value diff --git a/cdist/conf/type/__pacman_integrate/files/mirrorlist b/cdist/conf/type/__pacman_integrate/files/mirrorlist new file mode 100644 index 00000000..a378fb50 --- /dev/null +++ b/cdist/conf/type/__pacman_integrate/files/mirrorlist @@ -0,0 +1,344 @@ +## +## Arch Linux repository mirrorlist +## Generated on 2015-03-15 +## + +## Worldwide +#Server = http://mirror.rackspace.com/archlinux/$repo/os/$arch + +## Australia +#Server = http://mirror.aarnet.edu.au/pub/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch +#Server = http://ftp.iinet.net.au/pub/archlinux/$repo/os/$arch +#Server = http://mirror.internode.on.net/pub/archlinux/$repo/os/$arch +#Server = http://mirror.rackcentral.com.au/archlinux/$repo/os/$arch +#Server = http://ftp.swin.edu.au/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.uber.com.au/$repo/os/$arch + +## Austria +#Server = http://mirror.easyname.at/archlinux/$repo/os/$arch +#Server = http://mirror1.htu.tugraz.at/archlinux/$repo/os/$arch + +## Bangladesh +#Server = http://mirrors.ispros.com.bd/archlinux/$repo/os/$arch + +## Belarus +#Server = http://ftp.byfly.by/pub/archlinux/$repo/os/$arch +#Server = http://mirror.datacenter.by/pub/archlinux/$repo/os/$arch + +## Belgium +#Server = http://archlinux.cu.be/$repo/os/$arch +#Server = http://archlinux.mirror.kangaroot.net/$repo/os/$arch + +## Brazil +#Server = http://archlinux.c3sl.ufpr.br/$repo/os/$arch +#Server = http://www.las.ic.unicamp.br/pub/archlinux/$repo/os/$arch +#Server = http://pet.inf.ufsc.br/mirrors/archlinux/$repo/os/$arch + +## Bulgaria +#Server = http://mirror.telepoint.bg/archlinux/$repo/os/$arch + +## Canada +#Server = http://archlinux.dropswitch.net/archlinux/$repo/os/$arch +#Server = http://mirror.clibre.uqam.ca/archlinux/$repo/os/$arch +#Server = http://mirror.csclub.uwaterloo.ca/archlinux/$repo/os/$arch +#Server = http://mirror.its.dal.ca/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.rafal.ca/$repo/os/$arch +#Server = http://archlinux.mirror.vexxhost.com/$repo/os/$arch + +## Chile +#Server = http://mirror.archlinux.cl/$repo/os/$arch + +## China +#Server = http://mirrors.163.com/archlinux/$repo/os/$arch +#Server = http://mirror.bjtu.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.cqu.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.hust.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.hustunique.com/archlinux/$repo/os/$arch +#Server = http://mirrors.neusoft.edu.cn/archlinux/$repo/os/$arch +#Server = http://run.hit.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch +#Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch +#Server = http://mirrors.zju.edu.cn/archlinux/$repo/os/$arch + +## Colombia +#Server = http://mirror.edatel.net.co/archlinux/$repo/os/$arch +#Server = http://www.laqee.unal.edu.co/archlinux/$repo/os/$arch + +## Croatia +#Server = http://archlinux.iskon.hr/$repo/os/$arch + +## Czech Republic +#Server = http://archlinux.mirror.dkm.cz/pub/archlinux/$repo/os/$arch +#Server = http://gluttony.sin.cvut.cz/arch/$repo/os/$arch +#Server = http://mirror.oss.maxcdn.com/archlinux/$repo/os/$arch +#Server = http://mirrors.nic.cz/archlinux/$repo/os/$arch +#Server = http://mirror.vpsfree.cz/archlinux/$repo/os/$arch + +## Denmark +#Server = http://mirrors.dotsrc.org/archlinux/$repo/os/$arch +#Server = http://mirror.one.com/archlinux/$repo/os/$arch + +## Ecuador +#Server = http://mirror.cedia.org.ec/archlinux/$repo/os/$arch +#Server = http://mirror.espoch.edu.ec/archlinux/$repo/os/$arch +#Server = http://mirror.uta.edu.ec/archlinux/$repo/os/$arch + +## Estonia +#Server = http://ftp.eenet.ee/pub/archlinux/$repo/os/$arch + +## France +#Server = http://archlinux.aubrac-medical.fr/$repo/os/$arch +#Server = http://mirror.archlinux.ikoula.com/archlinux/$repo/os/$arch +#Server = http://archlinux.vi-di.fr/$repo/os/$arch +#Server = http://mir.art-software.fr/arch/$repo/os/$arch +#Server = http://fooo.biz/archlinux/$repo/os/$arch +#Server = https://fooo.biz/archlinux/$repo/os/$arch +#Server = http://mirror.lastmikoi.net/archlinux/$repo/os/$arch +#Server = http://mirror.lightcone.eu/archlinux/$repo/os/$arch +#Server = http://archlinux.mailtunnel.eu/$repo/os/$arch +#Server = https://www.mailtunnel.eu/archlinux/$repo/os/$arch +#Server = http://mir.archlinux.fr/$repo/os/$arch +#Server = http://arch.nimukaito.net/$repo/os/$arch +#Server = http://archlinux.mirrors.ovh.net/archlinux/$repo/os/$arch +#Server = http://archlinux.mirror.pkern.at/$repo/os/$arch +#Server = https://archlinux.mirror.pkern.at/$repo/os/$arch +#Server = http://archlinux.polymorf.fr/$repo/os/$arch +#Server = http://arch.static.lu/$repo/os/$arch +#Server = https://arch.static.lu/$repo/os/$arch +#Server = http://arch.tamcore.eu/$repo/os/$arch +#Server = http://mirror.tyborek.pl/arch/$repo/os/$arch +#Server = http://ftp.u-strasbg.fr/linux/distributions/archlinux/$repo/os/$arch +#Server = http://arch.yourlabs.org/$repo/os/$arch + +## Germany +#Server = http://mirror.23media.de/archlinux/$repo/os/$arch +#Server = http://archlinux.limun.org/$repo/os/$arch +#Server = https://archlinux.limun.org/$repo/os/$arch +#Server = http://artfiles.org/archlinux.org/$repo/os/$arch +#Server = http://ftp.fau.de/archlinux/$repo/os/$arch +#Server = https://ftp.fau.de/archlinux/$repo/os/$arch +#Server = http://mirror.flipez.de/archlinux/$repo/os/$arch +#Server = http://mirror.fluxent.de/archlinux/$repo/os/$arch +#Server = http://mirror.gnomus.de/$repo/os/$arch +#Server = http://arch.packages.gnp-tec.net/$repo/os/$arch +#Server = http://ftp5.gwdg.de/pub/linux/archlinux/$repo/os/$arch +#Server = http://mirror.hactar.bz/$repo/os/$arch +#Server = http://ftp.hawo.stw.uni-erlangen.de/archlinux/$repo/os/$arch +#Server = http://ftp.hosteurope.de/mirror/ftp.archlinux.org/$repo/os/$arch +#Server = http://ftp-stud.hs-esslingen.de/pub/Mirrors/archlinux/$repo/os/$arch +#Server = http://mirror.js-webcoding.de/pub/archlinux/$repo/os/$arch +#Server = http://mirror.k42.ch/archlinux/$repo/os/$arch +#Server = http://mirror.de.leaseweb.net/archlinux/$repo/os/$arch +#Server = http://mirror.metalgamer.eu/archlinux/$repo/os/$arch +#Server = http://mirror.michael-eckert.net/archlinux/$repo/os/$arch +#Server = http://archlinux.my-universe.com/$repo/os/$arch +#Server = https://archlinux.my-universe.com/$repo/os/$arch +#Server = http://mirrors.n-ix.net/archlinux/$repo/os/$arch +#Server = http://mirror.netcologne.de/archlinux/$repo/os/$arch +#Server = http://mirrors.niyawe.de/archlinux/$repo/os/$arch +#Server = http://ftp.halifax.rwth-aachen.de/archlinux/$repo/os/$arch +#Server = http://linux.rz.rub.de/archlinux/$repo/os/$arch +#Server = http://mirror.selfnet.de/archlinux/$repo/os/$arch +#Server = http://ftp.spline.inf.fu-berlin.de/mirrors/archlinux/$repo/os/$arch +#Server = http://ftp.tu-chemnitz.de/pub/linux/archlinux/$repo/os/$arch +#Server = http://ftp.tuxdroid.org/archlinux/$repo/os/$arch +#Server = http://ftp.uni-bayreuth.de/linux/archlinux/$repo/os/$arch +#Server = http://ftp.uni-hannover.de/archlinux/$repo/os/$arch +#Server = http://ftp.uni-kl.de/pub/linux/archlinux/$repo/os/$arch +#Server = http://mirror.united-gameserver.de/archlinux/$repo/os/$arch + +## Greece +#Server = http://ftp.cc.uoc.gr/mirrors/linux/archlinux/$repo/os/$arch +#Server = http://foss.aueb.gr/mirrors/linux/archlinux/$repo/os/$arch +#Server = https://foss.aueb.gr/mirrors/linux/archlinux/$repo/os/$arch +#Server = http://mirrors.myaegean.gr/linux/archlinux/$repo/os/$arch +#Server = http://ftp.ntua.gr/pub/linux/archlinux/$repo/os/$arch +#Server = http://ftp.otenet.gr/linux/archlinux/$repo/os/$arch + +## Hungary +#Server = http://ftp.mfa.kfki.hu/pub/mirrors/ftp.archlinux.org/$repo/os/$arch + +## Iceland +#Server = http://mirror.system.is/arch/$repo/os/$arch +#Server = https://mirror.system.is/arch/$repo/os/$arch + +## India +#Server = http://mirror.cse.iitk.ac.in/archlinux/$repo/os/$arch +#Server = http://ftp.iitm.ac.in/archlinux/$repo/os/$arch + +## Indonesia +#Server = http://mirror.kavalinux.com/archlinux/$repo/os/$arch +#Server = http://mirror.poliwangi.ac.id/archlinux/$repo/os/$arch +#Server = http://suro.ubaya.ac.id/archlinux/$repo/os/$arch + +## Iran +#Server = http://mirror.yazd.ac.ir/arch/$repo/os/$arch + +## Ireland +#Server = http://ftp.heanet.ie/mirrors/ftp.archlinux.org/$repo/os/$arch + +## Israel +#Server = http://mirror.isoc.org.il/pub/archlinux/$repo/os/$arch + +## Italy +#Server = http://archlinux.openlabto.org/archlinux/$repo/os/$arch +#Server = http://archlinux.beccacervello.it/archlinux/$repo/os/$arch +#Server = http://mirrors.prometeus.net/archlinux/$repo/os/$arch + +## Japan +#Server = http://ftp.tsukuba.wide.ad.jp/Linux/archlinux/$repo/os/$arch +#Server = http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/$repo/os/$arch + +## Kazakhstan +#Server = http://mirror.neolabs.kz/archlinux/$repo/os/$arch + +## Latvia +#Server = http://archlinux.koyanet.lv/archlinux/$repo/os/$arch + +## Lithuania +#Server = http://archlinux.akmc.lt/$repo/os/$arch +#Server = http://atviras.lt/veidrodziai/archlinux/$repo/os/$arch + +## Luxembourg +#Server = http://archlinux.mirror.root.lu/$repo/os/$arch + +## Macedonia +#Server = http://arch.softver.org.mk/archlinux/$repo/os/$arch +#Server = http://mirror.t-home.mk/archlinux/$repo/os/$arch + +## Netherlands +#Server = http://arch.apt-get.eu/$repo/os/$arch +#Server = http://mirror.i3d.net/pub/archlinux/$repo/os/$arch +#Server = https://mirror.i3d.net/pub/archlinux/$repo/os/$arch +#Server = http://mirror.nl.leaseweb.net/archlinux/$repo/os/$arch +#Server = http://ftp.nluug.nl/os/Linux/distr/archlinux/$repo/os/$arch +#Server = http://ftp.snt.utwente.nl/pub/os/linux/archlinux/$repo/os/$arch + +## New Caledonia +#Server = http://mirror.lagoon.nc/pub/archlinux/$repo/os/$arch +#Server = http://archlinux.nautile.nc/archlinux/$repo/os/$arch + +## New Zealand +#Server = http://mirror.xnet.co.nz/pub/archlinux/$repo/os/$arch + +## Norway +#Server = http://mirror.archlinux.no/$repo/os/$arch +#Server = http://archlinux.uib.no/$repo/os/$arch +#Server = http://archlinux.neuf.no/$repo/os/$arch + +## Philippines +#Server = http://mirror.pregi.net/pub/Linux/archlinux/$repo/os/$arch + +## Poland +#Server = http://mirror.chmuri.net/archmirror/$repo/os/$arch +#Server = http://arch.midov.pl/arch/$repo/os/$arch +#Server = http://piotrkosoft.net/pub/mirrors/ftp.archlinux.org/$repo/os/$arch +#Server = http://ftp.vectranet.pl/archlinux/$repo/os/$arch + +## Portugal +#Server = http://archlinux.dcc.fc.up.pt/$repo/os/$arch +#Server = http://ftp.rnl.tecnico.ulisboa.pt/pub/archlinux/$repo/os/$arch + +## Romania +#Server = http://mirror.archlinux.ro/archlinux/$repo/os/$arch +#Server = http://archlinux.mirrors.linux.ro/$repo/os/$arch + +## Russia +#Server = http://mirror.rol.ru/archlinux/$repo/os/$arch +#Server = http://mirror.yandex.ru/archlinux/$repo/os/$arch + +## Serbia +#Server = http://mirror.pmf.kg.ac.rs/archlinux/$repo/os/$arch + +## Singapore +#Server = http://download.nus.edu.sg/mirror/arch/$repo/os/$arch +#Server = http://mirror.nus.edu.sg/archlinux/$repo/os/$arch + +## Slovakia +#Server = http://mirror.lnx.sk/pub/linux/archlinux/$repo/os/$arch +#Server = http://tux.rainside.sk/archlinux/$repo/os/$arch + +## South Africa +#Server = http://ftp.wa.co.za/pub/archlinux/$repo/os/$arch + +## South Korea +#Server = http://ftp.kaist.ac.kr/ArchLinux/$repo/os/$arch +#Server = http://mirror.premi.st/archlinux/$repo/os/$arch + +## Spain +#Server = http://osl.ugr.es/archlinux/$repo/os/$arch +#Server = http://sunsite.rediris.es/mirror/archlinux/$repo/os/$arch + +## Sweden +#Server = http://ftp.df.lth.se/pub/archlinux/$repo/os/$arch +#Server = http://ftp.lysator.liu.se/pub/archlinux/$repo/os/$arch +#Server = https://ftp.lysator.liu.se/pub/archlinux/$repo/os/$arch +#Server = http://ftp.myrveln.se/pub/linux/archlinux/$repo/os/$arch +#Server = http://ftp.portlane.com/pub/os/linux/archlinux/$repo/os/$arch + +## Switzerland +#Server = http://archlinux.puzzle.ch/$repo/os/$arch + +## Taiwan +#Server = http://archlinux.cs.nctu.edu.tw/$repo/os/$arch +#Server = http://shadow.ind.ntou.edu.tw/archlinux/$repo/os/$arch +#Server = http://ftp.tku.edu.tw/Linux/ArchLinux/$repo/os/$arch +#Server = http://ftp.yzu.edu.tw/Linux/archlinux/$repo/os/$arch + +## Turkey +#Server = http://ftp.linux.org.tr/archlinux/$repo/os/$arch + +## Ukraine +#Server = http://mirrors.nix.org.ua/linux/archlinux/$repo/os/$arch + +## United Kingdom +#Server = http://mirror.bytemark.co.uk/archlinux/$repo/os/$arch +#Server = http://mirror.cinosure.com/archlinux/$repo/os/$arch +#Server = http://mirrors.manchester.m247.com/arch-linux/$repo/os/$arch +#Server = http://www.mirrorservice.org/sites/ftp.archlinux.org/$repo/os/$arch +#Server = http://arch.serverspace.co.uk/arch/$repo/os/$arch +#Server = http://archlinux.mirrors.uk2.net/$repo/os/$arch + +## United States +#Server = http://mirrors.abscission.net/archlinux/$repo/os/$arch +#Server = http://mirrors.acm.wpi.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.advancedhosters.com/archlinux/$repo/os/$arch +#Server = http://mirrors.aggregate.org/archlinux/$repo/os/$arch +#Server = http://archlinux.surlyjake.com/archlinux/$repo/os/$arch +#Server = http://mirrors.cat.pdx.edu/archlinux/$repo/os/$arch +#Server = http://mirror.cc.columbia.edu/pub/linux/archlinux/$repo/os/$arch +#Server = http://mirrors.cdndepo.com/archlinux/$repo/os/$arch +#Server = https://mirrors.cdndepo.com/archlinux/$repo/os/$arch +#Server = http://mirrors.cecsresearch.org/archlinux/$repo/os/$arch +#Server = http://cosmos.cites.illinois.edu/pub/archlinux/$repo/os/$arch +#Server = http://mirror.cs.pitt.edu/archlinux/$repo/os/$arch +#Server = http://mirror.es.its.nyu.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.gigenet.com/archlinux/$repo/os/$arch +#Server = http://mirror.grig.io/archlinux/$repo/os/$arch +#Server = http://www.gtlib.gatech.edu/pub/archlinux/$repo/os/$arch +#Server = http://mirror.ancl.hawaii.edu/linux/archlinux/$repo/os/$arch +#Server = http://mirror.jmu.edu/pub/archlinux/$repo/os/$arch +#Server = http://mirrors.kernel.org/archlinux/$repo/os/$arch +#Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch +#Server = http://mirror.us.leaseweb.net/archlinux/$repo/os/$arch +#Server = http://mirrors.liquidweb.com/archlinux/$repo/os/$arch +#Server = http://arch.localmsp.org/arch/$repo/os/$arch +#Server = https://arch.localmsp.org/arch/$repo/os/$arch +#Server = http://lug.mtu.edu/archlinux/$repo/os/$arch +#Server = http://mirror.metrocast.net/archlinux/$repo/os/$arch +#Server = http://mirror.nexcess.net/archlinux/$repo/os/$arch +#Server = http://ftp.osuosl.org/pub/archlinux/$repo/os/$arch +#Server = http://archlinux.pallissard.net/archlinux/$repo/os/$arch +#Server = http://mirror.rit.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.rutgers.edu/archlinux/$repo/os/$arch +#Server = http://mirror.umd.edu/archlinux/$repo/os/$arch +#Server = http://mirror.vtti.vt.edu/archlinux/$repo/os/$arch +#Server = http://mirrors.xmission.com/archlinux/$repo/os/$arch +#Server = http://mirror.yellowfiber.net/archlinux/$repo/os/$arch + +## Vietnam +#Server = http://f.archlinuxvn.org/archlinux/$repo/os/$arch +#Server = http://mirror-fpt-telecom.fpt.net/archlinux/$repo/os/$arch + diff --git a/cdist/conf/type/__pacman_integrate/files/options b/cdist/conf/type/__pacman_integrate/files/options new file mode 100644 index 00000000..68273e49 --- /dev/null +++ b/cdist/conf/type/__pacman_integrate/files/options @@ -0,0 +1,6 @@ +[options] +HoldPkg = pacman glibc +Architecture = auto +CheckSpace +SigLevel = Required DatabaseOptional +LocalFileSigLevel = Optional diff --git a/cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist b/cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist new file mode 100644 index 00000000..b0d116bc --- /dev/null +++ b/cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist @@ -0,0 +1,6 @@ +# +# cdist managed - do not change +# +Include = /etc/pacman.d/options +Include = /etc/pacman.d/repo_* +Include = /etc/plain_file_* diff --git a/cdist/conf/type/__pacman_integrate/files/pacman.conf.pacman b/cdist/conf/type/__pacman_integrate/files/pacman.conf.pacman new file mode 100644 index 00000000..f43fe397 --- /dev/null +++ b/cdist/conf/type/__pacman_integrate/files/pacman.conf.pacman @@ -0,0 +1,99 @@ +# +# /etc/pacman.conf +# +# See the pacman.conf(5) manpage for option and repository directives + +# +# GENERAL OPTIONS +# +[options] +# The following paths are commented out with their default values listed. +# If you wish to use different paths, uncomment and update the paths. +#RootDir = / +#DBPath = /var/lib/pacman/ +#CacheDir = /var/cache/pacman/pkg/ +#LogFile = /var/log/pacman.log +#GPGDir = /etc/pacman.d/gnupg/ +HoldPkg = pacman glibc +#XferCommand = /usr/bin/curl -C - -f %u > %o +#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u +#CleanMethod = KeepInstalled +#UseDelta = 0.7 +Architecture = auto + +# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup +#IgnorePkg = +#IgnoreGroup = + +#NoUpgrade = +#NoExtract = + +# Misc options +#UseSyslog +#Color +#TotalDownload +CheckSpace +#VerbosePkgLists + +# By default, pacman accepts packages signed by keys that its local keyring +# trusts (see pacman-key and its man page), as well as unsigned packages. +SigLevel = Required DatabaseOptional +LocalFileSigLevel = Optional +#RemoteFileSigLevel = Required + +# NOTE: You must run `pacman-key --init` before first using pacman; the local +# keyring can then be populated with the keys of all official Arch Linux +# packagers with `pacman-key --populate archlinux`. + +# +# REPOSITORIES +# - can be defined here or included from another file +# - pacman will search repositories in the order defined here +# - local/custom mirrors can be added here or in separate files +# - repositories listed first will take precedence when packages +# have identical names, regardless of version number +# - URLs will have $repo replaced by the name of the current repo +# - URLs will have $arch replaced by the name of the architecture +# +# Repository entries are of the format: +# [repo-name] +# Server = ServerName +# Include = IncludePath +# +# The header [repo-name] is crucial - it must be present and +# uncommented to enable the repo. +# + +# The testing repositories are disabled by default. To enable, uncomment the +# repo name header and Include lines. You can add preferred servers immediately +# after the header, and they will be used before the default mirrors. + +#[testing] +#Include = /etc/pacman.d/mirrorlist + +[core] +Include = /etc/pacman.d/mirrorlist + +[extra] +Include = /etc/pacman.d/mirrorlist + +#[community-testing] +#Include = /etc/pacman.d/mirrorlist + +[community] +Include = /etc/pacman.d/mirrorlist + +# If you want to run 32 bit applications on your x86_64 system, +# enable the multilib repositories as required here. + +#[multilib-testing] +#Include = /etc/pacman.d/mirrorlist + +#[multilib] +#Include = /etc/pacman.d/mirrorlist + +# An example of a custom package repository. See the pacman manpage for +# tips on creating your own repositories. +#[custom] +#SigLevel = Optional TrustAll +#Server = file:///home/custompkgs diff --git a/cdist/conf/type/__pacman_integrate/man.text b/cdist/conf/type/__pacman_integrate/man.text new file mode 100644 index 00000000..d2cf88c1 --- /dev/null +++ b/cdist/conf/type/__pacman_integrate/man.text @@ -0,0 +1,48 @@ +cdist-type__pacman_integrate(7) +=================== +Dominique Roux + + +NAME +---- +cdist-type__pacman_integrate - Integrate default pacman.conf to cdist conform and vice versa + + +DESCRIPTION +----------- +The type allows you to convert the default pacman.conf to a cdist conform one and vice versa + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to 'present' + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Convert normal to cdist conform +__pacman_integrate convert + +# Convert cdist conform to normal +__pacman_integrate convert --state absent + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- grep(1) + + +COPYING +------- +Copyright \(C) 2015 Dominique Roux. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__pacman_integrate/manifest b/cdist/conf/type/__pacman_integrate/manifest new file mode 100644 index 00000000..9f0c69c7 --- /dev/null +++ b/cdist/conf/type/__pacman_integrate/manifest @@ -0,0 +1,46 @@ +state=$(cat $__object/parameter/state 2>/dev/null || echo "present" ) + +if [ "${state}" == "present" ]; then + #__rsync /etc/pacman.conf\ + __file /home/rouxdo/Documents/Work/cdist-dev/pacman.conf\ + --owner root --group root --mode 644 --source $__type/files/pacman.conf.cdist + + #__rsync /etc/pacman.d/options\ + __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/options\ + --owner root --group root --mode 644 --source $__type/files/options + + #__file /etc/pacman.d/repo_empty_placeholder\ + __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/repo_empty_placeholder\ + --owner root --group root --mode 644 + + #__file /etc/pacman.d/plain_file_empty_placeholder\ + __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/plain_file_empty_placeholder\ + --owner root --group root --mode 644 + +elif [ "${state}" == "absent" ]; then + + #__rsync /etc/pacman.conf\ + __file /home/rouxdo/Documents/Work/cdist-dev/pacman.conf\ + --owner root --group root --mode 644 --source $__type/files/pacman.conf.pacman + + #__rsync /etc/pacman.d/mirrorlist\ + __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/mirrorlist\ + --owner root --group root --mode 644 --source $__type/files/mirrorlist + + #__rsync /etc/pacman.d/options\ + __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/options\ + --state absent + + #__file /etc/pacman.d/repo_empty_placeholder\ + __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/repo_empty_placeholder\ + --state absent + + #__file /etc/pacman.d/plain_file_empty_placeholder\ + __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/plain_file_empty_placeholder\ + --state absent + +else + + echo "ERROR: State not found" >&2 + +fi diff --git a/cdist/conf/type/__pacman_integrate/parameter/optional b/cdist/conf/type/__pacman_integrate/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__pacman_integrate/parameter/optional @@ -0,0 +1 @@ +state From 1690c9d8ff0919fc3c0afec5fe09b9b3d20bc380 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Tue, 12 May 2015 19:12:49 +0200 Subject: [PATCH 0016/1332] Bugfixes: -Added GPLv3 header -Set correct '=' in man.text -Now uses default values cdist-like -Replace arrays with plain variables -Rewrote the error message --- cdist/conf/type/__pacman_conf/man.text | 2 +- cdist/conf/type/__pacman_conf/manifest | 65 ++++++++++++------- .../type/__pacman_conf/parameter/default/file | 2 + .../__pacman_conf/parameter/default/state | 1 + cdist/conf/type/__pacman_integrate/man.text | 2 +- cdist/conf/type/__pacman_integrate/manifest | 53 +++++++++------ .../parameter/default/state | 1 + 7 files changed, 82 insertions(+), 44 deletions(-) create mode 100644 cdist/conf/type/__pacman_conf/parameter/default/file create mode 100644 cdist/conf/type/__pacman_conf/parameter/default/state create mode 100644 cdist/conf/type/__pacman_integrate/parameter/default/state diff --git a/cdist/conf/type/__pacman_conf/man.text b/cdist/conf/type/__pacman_conf/man.text index b4905111..9762837f 100644 --- a/cdist/conf/type/__pacman_conf/man.text +++ b/cdist/conf/type/__pacman_conf/man.text @@ -1,5 +1,5 @@ cdist-type__pacman_conf(7) -=================== +========================== Dominique Roux diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest index f817b2ca..591218b8 100644 --- a/cdist/conf/type/__pacman_conf/manifest +++ b/cdist/conf/type/__pacman_conf/manifest @@ -1,36 +1,57 @@ +#!/bin/sh +# +# 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 . +# + #get params section=$(cat "$__object/parameter/section") key=$(cat "$__object/parameter/key") value=$(cat "$__object/parameter/value") -file=$(cat "$__object/parameter/file" 2>/dev/null || echo "") -state=$(cat "$__object/parameter/state" 2>/dev/null || echo "present" ) +file=$(cat "$__object/parameter/file" 2>/dev/null) +state=$(cat "$__object/parameter/state" 2>/dev/null) #path variable default /etc/pacman.d sec_path="/etc/pacman.d" #allowed keys (from man pacman.conf) -allowed_option_keys=( "RootDir" "DBPath" "CacheDir" "GPGDir" "LogFile" "HoldPkg" "IgnorePkg" "IgnoreGroup" "Include" "Architecture" "XferCommand" "NoUpgrade" "NoExtract" "CleanMethod" "SigLevel" "LocalFileSigLevel" "RemoteFileSigLevel" ) -boolean_option_keys=( "UseSyslog" "Color" "UseDelta" "TotalDownload" "CheckSpace" "VerbosePkgLists" ) -allowed_repo_keys=( "Include" "Server" "SigLevel" "Usage" ) +allowed_option_keys="RootDir DBPath CacheDir GPGDir LogFile HoldPkg IgnorePkg IgnoreGroup Include Architecture XferCommand NoUpgrade NoExtract CleanMethod SigLevel LocalFileSigLevel RemoteFileSigLevel" +boolean_option_keys="UseSyslog Color UseDelta TotalDownload CheckSpace VerbosePkgLists" +allowed_repo_keys="Include Server SigLevel Usage" #set global variables -MATH=1 +MATCH=0 #function for check if array contain string contains_element() { - MATCH=1 + MATCH=0 - local passed_array - passed_array=(`echo "$2"`) + target=$1 + keys="${@:2}" - for e in "${passed_array[@]}"; do - if [ "${e}" == "${1}" ]; then - MATCH=0 + + for key in "${keys}"; do + if [ "${key}" == "${target}" ]; then + MATCH=1 return 0 fi done - MATCH=1 + MATCH=0 } if [ "${file}" != "" ]; then @@ -49,7 +70,7 @@ if [ "${file}" != "" ]; then --state absent else - echo "ERROR: State not found" >&2 + echo "ERROR: Unknown state: ${state}" >&2 fi fi @@ -61,9 +82,9 @@ if [ "${section}" == "options" ]; then eof #check if key is valid #check for boolean value - contains_element "${key}" "$(echo ${boolean_option_keys[@]})" + contains_element "${key}" "${boolean_option_keys}" - if [ "${MATCH}" -eq 0 ]; then + if [ "${MATCH}" -eq 1 ]; then if [ "${value}" == "on" ]; then require="__file/${sec_path}/${section}" __line ${key}_${value}\ --file ${sec_path}/${section} --line ${key} @@ -73,13 +94,13 @@ eof fi else - contains_element "${key}" "$(echo ${allowed_option_keys[@]})" + contains_element "${key}" "${allowed_option_keys}" - if [ "${MATCH}" -eq 0 ]; then + if [ "${MATCH}" -eq 1 ]; then require="__file/${sec_path}/${section}" __key_value ${section}_${key}\ --file ${sec_path}/${section} --key ${key} --value ${value} --delimiter ' = ' else - echo "Key is not valid. Have a look at man pacman.conf" >&2 + echo "Key: ${key} is not valid. Have a look at man pacman.conf" >&2 fi fi @@ -91,8 +112,8 @@ eof if [ "${state}" == "present" ]; then #check if key is valid - contains_element "${key}" "$(echo ${allowed_repo_keys[@]})" - if [ ${MATCH} -eq 1 ]; then + contains_element "${key}" "${allowed_repo_keys}" + if [ ${MATCH} -eq 0 ]; then exit fi @@ -105,7 +126,7 @@ eof --state absent else - echo "ERROR: State not found" >&2 + echo "ERROR: Unknown state: ${state}" >&2 fi fi diff --git a/cdist/conf/type/__pacman_conf/parameter/default/file b/cdist/conf/type/__pacman_conf/parameter/default/file new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/cdist/conf/type/__pacman_conf/parameter/default/file @@ -0,0 +1,2 @@ + + diff --git a/cdist/conf/type/__pacman_conf/parameter/default/state b/cdist/conf/type/__pacman_conf/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__pacman_conf/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__pacman_integrate/man.text b/cdist/conf/type/__pacman_integrate/man.text index d2cf88c1..f65e30ce 100644 --- a/cdist/conf/type/__pacman_integrate/man.text +++ b/cdist/conf/type/__pacman_integrate/man.text @@ -1,5 +1,5 @@ cdist-type__pacman_integrate(7) -=================== +=============================== Dominique Roux diff --git a/cdist/conf/type/__pacman_integrate/manifest b/cdist/conf/type/__pacman_integrate/manifest index 9f0c69c7..5f398c19 100644 --- a/cdist/conf/type/__pacman_integrate/manifest +++ b/cdist/conf/type/__pacman_integrate/manifest @@ -1,46 +1,59 @@ -state=$(cat $__object/parameter/state 2>/dev/null || echo "present" ) +#!/bin/sh +# +# 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 . +# + +state=$(cat $__object/parameter/state 2>/dev/null) + +path="/etc/" if [ "${state}" == "present" ]; then - #__rsync /etc/pacman.conf\ - __file /home/rouxdo/Documents/Work/cdist-dev/pacman.conf\ + __file /etc/pacman.conf\ --owner root --group root --mode 644 --source $__type/files/pacman.conf.cdist - #__rsync /etc/pacman.d/options\ - __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/options\ + __file /etc/pacman.d/options\ --owner root --group root --mode 644 --source $__type/files/options - #__file /etc/pacman.d/repo_empty_placeholder\ - __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/repo_empty_placeholder\ + __file /etc/pacman.d/repo_empty_placeholder\ --owner root --group root --mode 644 - #__file /etc/pacman.d/plain_file_empty_placeholder\ - __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/plain_file_empty_placeholder\ + __file /etc/pacman.d/plain_file_empty_placeholder\ --owner root --group root --mode 644 elif [ "${state}" == "absent" ]; then - #__rsync /etc/pacman.conf\ - __file /home/rouxdo/Documents/Work/cdist-dev/pacman.conf\ + __file /etc/pacman.conf\ --owner root --group root --mode 644 --source $__type/files/pacman.conf.pacman - #__rsync /etc/pacman.d/mirrorlist\ - __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/mirrorlist\ + __file /etc/pacman.d/mirrorlist\ --owner root --group root --mode 644 --source $__type/files/mirrorlist - #__rsync /etc/pacman.d/options\ - __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/options\ + __file /etc/pacman.d/options\ --state absent - #__file /etc/pacman.d/repo_empty_placeholder\ - __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/repo_empty_placeholder\ + __file /etc/pacman.d/repo_empty_placeholder\ --state absent - #__file /etc/pacman.d/plain_file_empty_placeholder\ - __file /home/rouxdo/Documents/Work/cdist-dev/pacman.d/plain_file_empty_placeholder\ + __file /etc/pacman.d/plain_file_empty_placeholder\ --state absent else - echo "ERROR: State not found" >&2 + echo "ERROR: Unknown state: ${state}" >&2 fi diff --git a/cdist/conf/type/__pacman_integrate/parameter/default/state b/cdist/conf/type/__pacman_integrate/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__pacman_integrate/parameter/default/state @@ -0,0 +1 @@ +present From f0fd3e460812dc7ceb87e2b81de7274d10ef8527 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Wed, 13 May 2015 12:55:18 +0200 Subject: [PATCH 0017/1332] small bugfixes --- cdist/conf/type/__pacman_conf/manifest | 2 +- cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest index 591218b8..4e48758b 100644 --- a/cdist/conf/type/__pacman_conf/manifest +++ b/cdist/conf/type/__pacman_conf/manifest @@ -45,7 +45,7 @@ contains_element() { keys="${@:2}" - for key in "${keys}"; do + for key in ${keys}; do if [ "${key}" == "${target}" ]; then MATCH=1 return 0 diff --git a/cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist b/cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist index b0d116bc..88e6e623 100644 --- a/cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist +++ b/cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist @@ -3,4 +3,4 @@ # Include = /etc/pacman.d/options Include = /etc/pacman.d/repo_* -Include = /etc/plain_file_* +Include = /etc/pacman.d/plain_file_* From 1ad4125a3bc703727127ecb2ee8843d6f62bdf50 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Wed, 13 May 2015 13:12:25 +0200 Subject: [PATCH 0018/1332] Add exit if file is specified --- cdist/conf/type/__pacman_conf/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest index 4e48758b..7074bb1a 100644 --- a/cdist/conf/type/__pacman_conf/manifest +++ b/cdist/conf/type/__pacman_conf/manifest @@ -71,6 +71,7 @@ if [ "${file}" != "" ]; then else echo "ERROR: Unknown state: ${state}" >&2 + exit 0 fi fi From 672aa13316b5ba3df4ecb4ed14aa210ea26a33a7 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Wed, 13 May 2015 13:28:48 +0200 Subject: [PATCH 0019/1332] Second forgotten exit --- cdist/conf/type/__pacman_conf/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest index 7074bb1a..726074d4 100644 --- a/cdist/conf/type/__pacman_conf/manifest +++ b/cdist/conf/type/__pacman_conf/manifest @@ -68,6 +68,7 @@ if [ "${file}" != "" ]; then elif [ "${state}" == "absent" ]; then require="__file/${sec_path}/plain_file_${file}" __key_value ${file}_${key}\ --state absent + exit 0 else echo "ERROR: Unknown state: ${state}" >&2 From 62e1ecdd0817c98bf349a9143ab98b3c8bdfaee1 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Tue, 19 May 2015 08:18:33 +0200 Subject: [PATCH 0020/1332] changed if statement: from if [ != ]; to if [ ]; --- cdist/conf/type/__pacman_conf/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest index 726074d4..19e232a7 100644 --- a/cdist/conf/type/__pacman_conf/manifest +++ b/cdist/conf/type/__pacman_conf/manifest @@ -54,7 +54,7 @@ contains_element() { MATCH=0 } -if [ "${file}" != "" ]; then +if [ "${file}" ]; then __file "${sec_path}/plain_file_${file}"\ --state exists --mode 666 From b68091e032848c8a1164d593ebc0c2b0c59b4669 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 20 May 2015 17:00:35 +0200 Subject: [PATCH 0021/1332] integrate __pacman_conf_integrate Signed-off-by: Nico Schottelius --- .../files/mirrorlist | 0 .../files/options | 0 .../files/pacman.conf.cdist | 0 .../files/pacman.conf.pacman | 0 .../man.text | 10 +++++----- .../manifest | 0 .../parameter/default/state | 0 .../parameter/optional | 0 docs/changelog | 3 +++ 9 files changed, 8 insertions(+), 5 deletions(-) rename cdist/conf/type/{__pacman_integrate => __pacman_conf_integrate}/files/mirrorlist (100%) rename cdist/conf/type/{__pacman_integrate => __pacman_conf_integrate}/files/options (100%) rename cdist/conf/type/{__pacman_integrate => __pacman_conf_integrate}/files/pacman.conf.cdist (100%) rename cdist/conf/type/{__pacman_integrate => __pacman_conf_integrate}/files/pacman.conf.pacman (100%) rename cdist/conf/type/{__pacman_integrate => __pacman_conf_integrate}/man.text (75%) rename cdist/conf/type/{__pacman_integrate => __pacman_conf_integrate}/manifest (100%) rename cdist/conf/type/{__pacman_integrate => __pacman_conf_integrate}/parameter/default/state (100%) rename cdist/conf/type/{__pacman_integrate => __pacman_conf_integrate}/parameter/optional (100%) diff --git a/cdist/conf/type/__pacman_integrate/files/mirrorlist b/cdist/conf/type/__pacman_conf_integrate/files/mirrorlist similarity index 100% rename from cdist/conf/type/__pacman_integrate/files/mirrorlist rename to cdist/conf/type/__pacman_conf_integrate/files/mirrorlist diff --git a/cdist/conf/type/__pacman_integrate/files/options b/cdist/conf/type/__pacman_conf_integrate/files/options similarity index 100% rename from cdist/conf/type/__pacman_integrate/files/options rename to cdist/conf/type/__pacman_conf_integrate/files/options diff --git a/cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist b/cdist/conf/type/__pacman_conf_integrate/files/pacman.conf.cdist similarity index 100% rename from cdist/conf/type/__pacman_integrate/files/pacman.conf.cdist rename to cdist/conf/type/__pacman_conf_integrate/files/pacman.conf.cdist diff --git a/cdist/conf/type/__pacman_integrate/files/pacman.conf.pacman b/cdist/conf/type/__pacman_conf_integrate/files/pacman.conf.pacman similarity index 100% rename from cdist/conf/type/__pacman_integrate/files/pacman.conf.pacman rename to cdist/conf/type/__pacman_conf_integrate/files/pacman.conf.pacman diff --git a/cdist/conf/type/__pacman_integrate/man.text b/cdist/conf/type/__pacman_conf_integrate/man.text similarity index 75% rename from cdist/conf/type/__pacman_integrate/man.text rename to cdist/conf/type/__pacman_conf_integrate/man.text index f65e30ce..8eb01d5f 100644 --- a/cdist/conf/type/__pacman_integrate/man.text +++ b/cdist/conf/type/__pacman_conf_integrate/man.text @@ -1,11 +1,11 @@ -cdist-type__pacman_integrate(7) -=============================== +cdist-type__pacman_conf_integrate(7) +==================================== Dominique Roux NAME ---- -cdist-type__pacman_integrate - Integrate default pacman.conf to cdist conform and vice versa +cdist-type__pacman_conf_integrate - Integrate default pacman.conf to cdist conform and vice versa DESCRIPTION @@ -28,10 +28,10 @@ EXAMPLES -------------------------------------------------------------------------------- # Convert normal to cdist conform -__pacman_integrate convert +__pacman_conf_integrate convert # Convert cdist conform to normal -__pacman_integrate convert --state absent +__pacman_conf_integrate convert --state absent -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__pacman_integrate/manifest b/cdist/conf/type/__pacman_conf_integrate/manifest similarity index 100% rename from cdist/conf/type/__pacman_integrate/manifest rename to cdist/conf/type/__pacman_conf_integrate/manifest diff --git a/cdist/conf/type/__pacman_integrate/parameter/default/state b/cdist/conf/type/__pacman_conf_integrate/parameter/default/state similarity index 100% rename from cdist/conf/type/__pacman_integrate/parameter/default/state rename to cdist/conf/type/__pacman_conf_integrate/parameter/default/state diff --git a/cdist/conf/type/__pacman_integrate/parameter/optional b/cdist/conf/type/__pacman_conf_integrate/parameter/optional similarity index 100% rename from cdist/conf/type/__pacman_integrate/parameter/optional rename to cdist/conf/type/__pacman_conf_integrate/parameter/optional diff --git a/docs/changelog b/docs/changelog index 5487d580..034b5342 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,9 @@ Changelog next: * Documentation: Fix spelling in manual pages (Dmitry Bogatov) + * New type: __pacman_conf: Manage pacman.conf (Dominique Roux) + * New type: __pacman_conf_integrate: cdist compatible pacman.conf (Dominique Roux) + 3.1.13: 2015-05-16 * Type __block: Fix support for non stdin blocks (Dominique Roux) From 47daae1aa2d9285bb4c51344f99b6a7f54fd816b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 22 May 2015 21:09:03 +0200 Subject: [PATCH 0022/1332] Revert "__consul type requires unzip to be installed" This reverts commit 45df8dca119e3004596f290ce423843163cb145b. --- cdist/conf/type/__consul/manifest | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cdist/conf/type/__consul/manifest b/cdist/conf/type/__consul/manifest index ea1a728f..1cbc5413 100755 --- a/cdist/conf/type/__consul/manifest +++ b/cdist/conf/type/__consul/manifest @@ -43,9 +43,7 @@ if [ ! -d "$version_dir" ]; then exit 1 fi -__package unzip - -require="__package/unzip" __staged_file /usr/local/bin/consul \ +__staged_file /usr/local/bin/consul \ --source "$(cat "$version_dir/source")" \ --cksum "$(cat "$version_dir/cksum")" \ --fetch-command 'curl -s -L "%s"' \ From 8062fd9d6c6d33027b1231ca72892e40c6cb936e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 22 May 2015 21:10:16 +0200 Subject: [PATCH 0023/1332] changes++ Signed-off-by: Steven Armstrong --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 034b5342..410cd3a3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Documentation: Fix spelling in manual pages (Dmitry Bogatov) * New type: __pacman_conf: Manage pacman.conf (Dominique Roux) * New type: __pacman_conf_integrate: cdist compatible pacman.conf (Dominique Roux) + * Type __consul: Do not install unused package unzip (Steven Armstrong) 3.1.13: 2015-05-16 From a1f1b3540dafaab6b3359ef9551c06d648b8b4b2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 22 May 2015 21:13:55 +0200 Subject: [PATCH 0024/1332] +consul 0.5.2 Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul/files/versions/0.5.2/cksum | 1 + cdist/conf/type/__consul/files/versions/0.5.2/source | 1 + 2 files changed, 2 insertions(+) create mode 100644 cdist/conf/type/__consul/files/versions/0.5.2/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.5.2/source diff --git a/cdist/conf/type/__consul/files/versions/0.5.2/cksum b/cdist/conf/type/__consul/files/versions/0.5.2/cksum new file mode 100644 index 00000000..1c077266 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.5.2/cksum @@ -0,0 +1 @@ +2207534901 18245010 consul diff --git a/cdist/conf/type/__consul/files/versions/0.5.2/source b/cdist/conf/type/__consul/files/versions/0.5.2/source new file mode 100644 index 00000000..991034ce --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.5.2/source @@ -0,0 +1 @@ +https://dl.bintray.com/mitchellh/consul/0.5.2_linux_amd64.zip From 414542cd8279357ea5e573e48441afee85375185 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 22 May 2015 21:14:41 +0200 Subject: [PATCH 0025/1332] changes++ Signed-off-by: Steven Armstrong --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 410cd3a3..96496052 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * New type: __pacman_conf: Manage pacman.conf (Dominique Roux) * New type: __pacman_conf_integrate: cdist compatible pacman.conf (Dominique Roux) * Type __consul: Do not install unused package unzip (Steven Armstrong) + * Type __consul: Add source & cksum for 0.5.2 (Steven Armstrong) 3.1.13: 2015-05-16 From 085a7c8ce1e3ce05cf4cce69d163d17f434ba0c2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 28 May 2015 22:26:51 +0200 Subject: [PATCH 0026/1332] work in progress: start upgrading consul-template to 0.9.0 Signed-off-by: Steven Armstrong --- .../files/versions/0.9.0/cksum | 1 + .../files/versions/0.9.0/source | 1 + cdist/conf/type/__consul_template/man.text | 22 ++++- cdist/conf/type/__consul_template/notes | 93 +++++++++++++++++++ .../type/__consul_template/parameter/boolean | 1 + .../parameter/default/log-level | 1 + .../parameter/default/syslog-facility | 1 + .../type/__consul_template/parameter/optional | 7 +- 8 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 cdist/conf/type/__consul_template/files/versions/0.9.0/cksum create mode 100644 cdist/conf/type/__consul_template/files/versions/0.9.0/source create mode 100644 cdist/conf/type/__consul_template/notes create mode 100644 cdist/conf/type/__consul_template/parameter/default/log-level create mode 100644 cdist/conf/type/__consul_template/parameter/default/syslog-facility diff --git a/cdist/conf/type/__consul_template/files/versions/0.9.0/cksum b/cdist/conf/type/__consul_template/files/versions/0.9.0/cksum new file mode 100644 index 00000000..0f86f500 --- /dev/null +++ b/cdist/conf/type/__consul_template/files/versions/0.9.0/cksum @@ -0,0 +1 @@ +4037434610 8901128 consul-template diff --git a/cdist/conf/type/__consul_template/files/versions/0.9.0/source b/cdist/conf/type/__consul_template/files/versions/0.9.0/source new file mode 100644 index 00000000..25fd18e9 --- /dev/null +++ b/cdist/conf/type/__consul_template/files/versions/0.9.0/source @@ -0,0 +1 @@ +https://github.com/hashicorp/consul-template/releases/download/v0.9.0/consul-template_0.9.0_linux_amd64.tar.gz diff --git a/cdist/conf/type/__consul_template/man.text b/cdist/conf/type/__consul_template/man.text index 9db958eb..876690ee 100644 --- a/cdist/conf/type/__consul_template/man.text +++ b/cdist/conf/type/__consul_template/man.text @@ -24,13 +24,19 @@ None. OPTIONAL PARAMETERS ------------------- -auth:: - specify a username (and password) for basic authentication. +auth-username:: + specify a username for basic authentication. +auth-password:: + specify a password for basic authentication. batch-size:: the size of the batch when polling multiple dependencies. consul:: the location of the Consul instance to query (may be an IP address or FQDN) with port. Defaults to 'localhost:8500'. +log-level:: + The log level for output. This applies to the stdout/stderr logging as well + as syslog logging (if enabled). Valid values are "debug", "info", "warn", + and "err". The default value is "warn". max-stale:: the maximum staleness of a query. If specified, Consul will distribute work among all servers instead of just the leader. @@ -39,6 +45,16 @@ retry:: with the API. state:: either 'present' or 'absent'. Defaults to 'present' +ssl-cert:: + Path to an SSL client certificate to use to authenticate to the consul server. + Useful if the consul server "verify_incoming" option is set. +ssl-ca-cert:: + Path to a CA certificate file, containing one or more CA certificates to + use to validate the certificate sent by the consul server to us. This is a + handy alternative to setting --ssl-no-verify if you are using your own CA. +syslog-facility:: + The facility to use when sending to syslog. This requires the use of --syslog. + The default value is LOCAL0. token:: the Consul API token. version:: @@ -56,6 +72,8 @@ ssl:: use HTTPS while talking to Consul. Requires the Consul server to be configured to serve secure connections. ssl-no-verify:: ignore certificate warnings. Only used if ssl is enabled. +syslog:: + Send log output to syslog (in addition to stdout and stderr). EXAMPLES diff --git a/cdist/conf/type/__consul_template/notes b/cdist/conf/type/__consul_template/notes new file mode 100644 index 00000000..fc7cca11 --- /dev/null +++ b/cdist/conf/type/__consul_template/notes @@ -0,0 +1,93 @@ +# < 0.7.0 +ssl = true +ssl_no_verify = true + +# >= 0.7.0 +ssl { + enabled = true + verify = false +} + +# >= 0.9.0 +ssl-cert +ssl-ca-cert + + + +-------------------------------------------------------------------------------- +### from docs + + +ssl { + enabled = true + verify = false + cert = "/path/to/client/cert.pem" + ca_cert = "/path/to/ca/cert.pem" +} + + +ssl + Use HTTPS while talking to Consul. Requires the Consul server to be configured to serve secure connections. The default value is false. + +ssl-verify + Verify certificates when connecting via SSL. This requires the use of -ssl. The default value is true. + +ssl-cert + Path to an SSL client certificate to use to authenticate to the consul server. Useful if the consul server "verify_incoming" option is set. + +ssl-ca-cert + Path to a CA certificate file, containing one or more CA certificates to use to validate the certificate sent by the consul server to us. This is a handy alternative to setting --ssl-verify=false if you are using your own CA. + +-------------------------------------------------------------------------------- + +### example config file from docs + +consul = "127.0.0.1:8500" +token = "abcd1234" // May also be specified via the envvar CONSUL_TOKEN +retry = "10s" +max_stale = "10m" +log_level = "warn" +pid_file = "/path/to/pid" + +vault { + address = "https://vault.service.consul:8200" + token = "abcd1234" // May also be specified via the envvar VAULT_TOKEN + ssl { + enabled = true + verify = true + cert = "/path/to/client/cert.pem" + ca_cert = "/path/to/ca/cert.pem" + } +} + + +--auth-username +--auth-password +# if any are given enabled = true +auth { + enabled = true + username = "test" + password = "test" +} + +ssl { + enabled = true + verify = false + cert = "/path/to/client/cert.pem" + ca_cert = "/path/to/ca/cert.pem" +} + +syslog { + enabled = true + facility = "LOCAL5" +} + +template { + source = "/path/on/disk/to/template" + destination = "/path/on/disk/where/template/will/render" + command = "optional command to run when the template is updated" +} + +template { + // Multiple template definitions are supported +} diff --git a/cdist/conf/type/__consul_template/parameter/boolean b/cdist/conf/type/__consul_template/parameter/boolean index 5e17dcd7..696f66ee 100644 --- a/cdist/conf/type/__consul_template/parameter/boolean +++ b/cdist/conf/type/__consul_template/parameter/boolean @@ -1,2 +1,3 @@ ssl ssl-no-verify +syslog diff --git a/cdist/conf/type/__consul_template/parameter/default/log-level b/cdist/conf/type/__consul_template/parameter/default/log-level new file mode 100644 index 00000000..1ef71804 --- /dev/null +++ b/cdist/conf/type/__consul_template/parameter/default/log-level @@ -0,0 +1 @@ +warn diff --git a/cdist/conf/type/__consul_template/parameter/default/syslog-facility b/cdist/conf/type/__consul_template/parameter/default/syslog-facility new file mode 100644 index 00000000..f32df182 --- /dev/null +++ b/cdist/conf/type/__consul_template/parameter/default/syslog-facility @@ -0,0 +1 @@ +LOCAL0 diff --git a/cdist/conf/type/__consul_template/parameter/optional b/cdist/conf/type/__consul_template/parameter/optional index 2848edb9..5ad9679d 100644 --- a/cdist/conf/type/__consul_template/parameter/optional +++ b/cdist/conf/type/__consul_template/parameter/optional @@ -1,9 +1,14 @@ -auth +auth-username +auth-password batch-size consul +log-level max-stale retry state +ssl-cert +ssl-ca-cert +syslog-facility token version wait From 4f375a03c13a7c8e00312a4ce57ff35d0d40bc5e Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Wed, 10 Jun 2015 16:50:18 +0200 Subject: [PATCH 0027/1332] - added COPYING info - added parameter rsync-opts work need to be done: - the rsync-opts gets ignored by cdist since the opts are --[OPTS] like and cdist takes this as a own parameter --- cdist/conf/type/__rsync/gencode-local | 22 ++++++++++++++++++- cdist/conf/type/__rsync/gencode-remote | 20 +++++++++++++++++ cdist/conf/type/__rsync/manifest | 20 +++++++++++++++++ .../type/__rsync/parameter/optional_multiple | 1 + 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 cdist/conf/type/__rsync/parameter/optional_multiple diff --git a/cdist/conf/type/__rsync/gencode-local b/cdist/conf/type/__rsync/gencode-local index 7d688115..f11f6c90 100644 --- a/cdist/conf/type/__rsync/gencode-local +++ b/cdist/conf/type/__rsync/gencode-local @@ -1,3 +1,23 @@ +#!/bin/sh +# +# 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") @@ -11,7 +31,7 @@ set -- if [ -f "$__object/parameter/rsync-opts" ]; then while read opts; do set -- "$@" "$opts" - done + done < $__object/parameter/rsync-opts fi echo rsync -a \ diff --git a/cdist/conf/type/__rsync/gencode-remote b/cdist/conf/type/__rsync/gencode-remote index f8d85313..56268389 100644 --- a/cdist/conf/type/__rsync/gencode-remote +++ b/cdist/conf/type/__rsync/gencode-remote @@ -1,3 +1,23 @@ +#!/bin/sh +# +# 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 diff --git a/cdist/conf/type/__rsync/manifest b/cdist/conf/type/__rsync/manifest index d25df45b..0e4cc1f4 100644 --- a/cdist/conf/type/__rsync/manifest +++ b/cdist/conf/type/__rsync/manifest @@ -1 +1,21 @@ +#!/bin/sh +# +# 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/optional_multiple b/cdist/conf/type/__rsync/parameter/optional_multiple new file mode 100644 index 00000000..fdb7cd88 --- /dev/null +++ b/cdist/conf/type/__rsync/parameter/optional_multiple @@ -0,0 +1 @@ +rsync-opts From 036f90165ea158d627a148c93c3158616dd87475 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Thu, 11 Jun 2015 08:52:12 +0200 Subject: [PATCH 0028/1332] updated man.txt inserted beginning "--" in front of every rsync-opts --- cdist/conf/type/__rsync/gencode-local | 2 +- cdist/conf/type/__rsync/man.text | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__rsync/gencode-local b/cdist/conf/type/__rsync/gencode-local index f11f6c90..8d268d7e 100644 --- a/cdist/conf/type/__rsync/gencode-local +++ b/cdist/conf/type/__rsync/gencode-local @@ -30,7 +30,7 @@ fi set -- if [ -f "$__object/parameter/rsync-opts" ]; then while read opts; do - set -- "$@" "$opts" + set -- "$@" "--$opts" done < $__object/parameter/rsync-opts fi diff --git a/cdist/conf/type/__rsync/man.text b/cdist/conf/type/__rsync/man.text index 744b4bc2..1b787dfa 100644 --- a/cdist/conf/type/__rsync/man.text +++ b/cdist/conf/type/__rsync/man.text @@ -47,6 +47,13 @@ destination:: remote-user:: Use this user instead of the default "root" for rsync operations. +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 @@ -73,6 +80,11 @@ __rsync otherstuff \ --destination /usr/local/bin \ --source "$__type/files/package2" +# Use rsync option --exclude +__rsync /tmp/testdir \ + --source /etc \ + --rsync-opts exclude=sshd_conf + -------------------------------------------------------------------------------- From d91b478ae06d75ba34560663519b16f19732a889 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Thu, 11 Jun 2015 08:54:34 +0200 Subject: [PATCH 0029/1332] added rsync(1) in see also --- cdist/conf/type/__rsync/man.text | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__rsync/man.text b/cdist/conf/type/__rsync/man.text index 1b787dfa..0079a1c6 100644 --- a/cdist/conf/type/__rsync/man.text +++ b/cdist/conf/type/__rsync/man.text @@ -91,6 +91,7 @@ __rsync /tmp/testdir \ SEE ALSO -------- - cdist-type(7) +- rsync(1) COPYING From 879ddefbdf9211167795b40cd9676bce0f1a5563 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Thu, 11 Jun 2015 11:06:24 +0200 Subject: [PATCH 0030/1332] added second example for additional rsync options --- cdist/conf/type/__rsync/man.text | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cdist/conf/type/__rsync/man.text b/cdist/conf/type/__rsync/man.text index 0079a1c6..b5b287e9 100644 --- a/cdist/conf/type/__rsync/man.text +++ b/cdist/conf/type/__rsync/man.text @@ -85,6 +85,12 @@ __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 + -------------------------------------------------------------------------------- From 97dc358dc65b94846c8deb8357de5f5f1ddd9b1c Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Mon, 15 Jun 2015 15:57:11 +0200 Subject: [PATCH 0031/1332] added new section --- cdist/conf/type/__rsync/man.text | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cdist/conf/type/__rsync/man.text b/cdist/conf/type/__rsync/man.text index b5b287e9..af39b9c5 100644 --- a/cdist/conf/type/__rsync/man.text +++ b/cdist/conf/type/__rsync/man.text @@ -47,6 +47,9 @@ destination:: remote-user:: Use this user instead of the default "root" for rsync operations. + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- rsync-opts:: Use this option to give rsync options with. See rsync(1) for available options. @@ -54,6 +57,7 @@ rsync-opts:: Write the options without the beginning "--" Can be specified multiple times. + MESSAGES -------- NONE From 9ad28406002855cde33b7abdd0a816b8af3ed0ac Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Jun 2015 21:57:48 +0200 Subject: [PATCH 0032/1332] Working PreOS without SSH Signed-off-by: Nico Schottelius --- hacking/v3-busybox/all.sh | 25 +++++++++++++- hacking/v3-busybox/create_initramfs.sh | 14 +++++--- hacking/v3-busybox/init | 47 ++++---------------------- 3 files changed, 40 insertions(+), 46 deletions(-) diff --git a/hacking/v3-busybox/all.sh b/hacking/v3-busybox/all.sh index 65a3706b..563d093a 100755 --- a/hacking/v3-busybox/all.sh +++ b/hacking/v3-busybox/all.sh @@ -3,7 +3,30 @@ rm -rf preos mkdir -p preos/boot -./create_initramfs.sh > preos/boot/initramfs +initramfs=preos/boot/initramfs + +./create_initramfs.sh > "$initramfs" ./add_kernel_isolinux.sh preos ./copy_bin_with_libs.sh preos ./create_iso.sh preos preos.iso + +exit 0 + +run_earlyhook() { + kmod static-nodes --format=tmpfiles --output=/run/tmpfiles.d/kmod.conf + systemd-tmpfiles --prefix=/dev --create --boot + /usr/lib/systemd/systemd-udevd --daemon --resolve-names=never + udevd_running=1 +} + +run_hook() { + msg ":: Triggering uevents..." + udevadm trigger --action=add --type=subsystems + udevadm trigger --action=add --type=devices + udevadm settle +} + +run_cleanuphook() { + udevadm control --exit + udevadm info --cleanup-db +} diff --git a/hacking/v3-busybox/create_initramfs.sh b/hacking/v3-busybox/create_initramfs.sh index f87a7ef6..77606374 100755 --- a/hacking/v3-busybox/create_initramfs.sh +++ b/hacking/v3-busybox/create_initramfs.sh @@ -18,15 +18,19 @@ for link in sh mount; do done cd "${initramfs_dir}" -find . | cpio -H newc -o | gzip -rm -rf "${initramfs_dir}" - -exit 0 +# Add Arch Linux initramfs with kernel modules included +zcat /boot/initramfs-linux-fallback.img | cpio -i # TODO: -# - Kernel modules # - ssh # - various mkfs # - libs +# Create new initramfs +find . | cpio -H newc -o | gzip + +# echo ${initramfs_dir} +rm -rf "${initramfs_dir}" + +exit 0 diff --git a/hacking/v3-busybox/init b/hacking/v3-busybox/init index a961526f..2c6d747a 100755 --- a/hacking/v3-busybox/init +++ b/hacking/v3-busybox/init @@ -16,46 +16,13 @@ mknod /dev/null c 1 3 mknod /dev/tty c 5 0 mdev -s -#Function for parsing command line options with "=" in them -# get_opt("init=/sbin/init") will return "/sbin/init" -get_opt() { - echo "$@" | cut -d "=" -f 2 -} - -#Defaults -init="/sbin/init" -root="/dev/hda1" - -#Process command line options -for i in $(cat /proc/cmdline); do - case $i in - root\=*) - root=$(get_opt $i) - ;; - init\=*) - init=$(get_opt $i) - ;; - esac -done +# udev stuff +kmod static-nodes --format=tmpfiles --output=/run/tmpfiles.d/kmod.conf +systemd-tmpfiles --prefix=/dev --create --boot +/usr/lib/systemd/systemd-udevd --daemon --resolve-names=never +udevadm trigger --action=add --type=subsystems +udevadm trigger --action=add --type=devices +udevadm settle exec sh - -# Skipping the rest - -#Mount the root device -mount "${root}" /newroot - -#Check if $init exists and is executable -if [[ -x "/newroot/${init}" ]] ; then - #Unmount all other mounts so that the ram used by - #the initramfs can be cleared after switch_root - umount /sys /proc - - #Switch to the new root and execute init - exec switch_root /newroot "${init}" -fi - -#This will only be run if the exec above failed -echo "Failed to switch_root, dropping to a shell" -exec sh From 9d35be6acd7c5c6bef72e07382501910aad3ce4b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 16 Jun 2015 10:11:16 +0200 Subject: [PATCH 0033/1332] add script to configure sshd Signed-off-by: Nico Schottelius --- hacking/v3-busybox/sshd_config.sh | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100755 hacking/v3-busybox/sshd_config.sh diff --git a/hacking/v3-busybox/sshd_config.sh b/hacking/v3-busybox/sshd_config.sh new file mode 100755 index 00000000..10a8f465 --- /dev/null +++ b/hacking/v3-busybox/sshd_config.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +if [ "$#" -ne 1 ]; then + echo "$0: output directory" + exit 1 +fi + +dir=$1 + +mkdir -p "$dir/etc/ssh" +mkdir -p "$dir/root/.ssh" + +cat << eof > "$dir/etc/ssh/sshd_config" +# cdist generated - do not modify +PermitRootLogin without-password +eof + +cat << eof > "$dir/etc/passwd" +root:x:0:0:root:/root:/bin/bash +nobody:x:99:99:nobody:/:/bin/false +eof + +cat << eof > "$dir/etc/group" +root:x:0:root +nobody:x:99: +eof + +#cat << eof > "$dir/etc/shadow" +#root:x:0:0:root:/root:/bin/bash +#nobody:x:1:::::: +#eof + From cc144d9e8fee33faf86675fa1887ece14a061d05 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 16 Jun 2015 11:14:50 +0200 Subject: [PATCH 0034/1332] generate ssh keys Signed-off-by: Nico Schottelius --- hacking/v3-busybox/all.sh | 19 -------------- hacking/v3-busybox/copy_bin_with_libs.sh | 32 ++++++------------------ hacking/v3-busybox/create_initramfs.sh | 11 ++++---- hacking/v3-busybox/init | 14 +++++++---- hacking/v3-busybox/sshd_config.sh | 15 +++++++++++ 5 files changed, 38 insertions(+), 53 deletions(-) diff --git a/hacking/v3-busybox/all.sh b/hacking/v3-busybox/all.sh index 563d093a..e16e9c55 100755 --- a/hacking/v3-busybox/all.sh +++ b/hacking/v3-busybox/all.sh @@ -11,22 +11,3 @@ initramfs=preos/boot/initramfs ./create_iso.sh preos preos.iso exit 0 - -run_earlyhook() { - kmod static-nodes --format=tmpfiles --output=/run/tmpfiles.d/kmod.conf - systemd-tmpfiles --prefix=/dev --create --boot - /usr/lib/systemd/systemd-udevd --daemon --resolve-names=never - udevd_running=1 -} - -run_hook() { - msg ":: Triggering uevents..." - udevadm trigger --action=add --type=subsystems - udevadm trigger --action=add --type=devices - udevadm settle -} - -run_cleanuphook() { - udevadm control --exit - udevadm info --cleanup-db -} diff --git a/hacking/v3-busybox/copy_bin_with_libs.sh b/hacking/v3-busybox/copy_bin_with_libs.sh index ee2b532e..d850eb59 100755 --- a/hacking/v3-busybox/copy_bin_with_libs.sh +++ b/hacking/v3-busybox/copy_bin_with_libs.sh @@ -13,13 +13,17 @@ fi out_dir=$1 +# TODO: +# - various mkfs + #bin_list="udevadm bash fdisk mount syslinux umount rm mv" -bin_list="udevadm fdisk" +bin_list="udevadm fdisk sshd ssh-keygen" + +# debug tools +bin_list="$bin_list strace less" libs=$(mktemp /tmp/cdist-preos-libs.XXXXXXXXXXXXX) -mkdir -p "$out_dir/bin" "$out_dir/lib" - ( for bin in $bin_list; do src=$(which "$bin") @@ -31,30 +35,10 @@ mkdir -p "$out_dir/bin" "$out_dir/lib" while read lib; do - if echo $lib | grep '^/'; then + if echo $lib | grep -q '^/'; then # echo "Copying fqdn lib $lib ..." cp "$lib" "$out_dir/lib" - else - echo "How to copy $lib ?" fi done < "$libs" - rm -f "$libs" - -exit 0 - - -bin=$1 - -# Not used alternatives -# new_list=$(objdump -p /usr/bin/ls | awk '$1 ~ /NEEDED/ { print $2 }') -# ldconfig -p | grep 'libBrokenLocale.so.1$' | sed 's/.* => //' - - -for new_item in $new_list; do - - -done - -ldconfig -p | diff --git a/hacking/v3-busybox/create_initramfs.sh b/hacking/v3-busybox/create_initramfs.sh index 77606374..70bc77ed 100755 --- a/hacking/v3-busybox/create_initramfs.sh +++ b/hacking/v3-busybox/create_initramfs.sh @@ -1,6 +1,7 @@ #!/bin/sh -set -ex +set -e +here=$(pwd -P) initramfs_dir=$(mktemp -d /tmp/cdist-preos.XXXXXXX) # initramfs_dir=$1 @@ -22,10 +23,10 @@ cd "${initramfs_dir}" # Add Arch Linux initramfs with kernel modules included zcat /boot/initramfs-linux-fallback.img | cpio -i -# TODO: -# - ssh -# - various mkfs -# - libs +# Add helper binaries +"$here/copy_bin_with_libs.sh" "$initramfs_dir" >/dev/null 2>&1 +"$here/sshd_config.sh" "$initramfs_dir" + # Create new initramfs find . | cpio -H newc -o | gzip diff --git a/hacking/v3-busybox/init b/hacking/v3-busybox/init index 2c6d747a..bf6011f9 100755 --- a/hacking/v3-busybox/init +++ b/hacking/v3-busybox/init @@ -1,17 +1,16 @@ #!/bin/sh -#Create all the symlinks to /bin/busybox +# Create all the symlinks to /bin/busybox /bin/busybox --install -s -#Mount things needed by this script +# Mount things needed by this script mount -t proc proc /proc mount -t sysfs sysfs /sys -#Disable kernel messages from popping onto the screen +# Disable kernel messages from popping onto the screen echo 0 > /proc/sys/kernel/printk - -#Create device nodes +# Create device nodes mknod /dev/null c 1 3 mknod /dev/tty c 5 0 mdev -s @@ -24,5 +23,10 @@ udevadm trigger --action=add --type=subsystems udevadm trigger --action=add --type=devices udevadm settle +# /bin/sshd + +# Generate keys for sshd +echo "Generating keys for sshd" +ssh-keygen -A exec sh diff --git a/hacking/v3-busybox/sshd_config.sh b/hacking/v3-busybox/sshd_config.sh index 10a8f465..090aae8c 100755 --- a/hacking/v3-busybox/sshd_config.sh +++ b/hacking/v3-busybox/sshd_config.sh @@ -9,6 +9,7 @@ dir=$1 mkdir -p "$dir/etc/ssh" mkdir -p "$dir/root/.ssh" +mkdir -p "$dir/lib" cat << eof > "$dir/etc/ssh/sshd_config" # cdist generated - do not modify @@ -25,6 +26,20 @@ root:x:0:root nobody:x:99: eof +# libpam not found +# /etc/ssl/openssl.cnf +# /etc/gai.conf +# no nscd socket +# /etc/nsswitch.conf +# libnss_compat.so.2 +# libnss_files.so.2 + +# Fixes the user problem +cp /lib/libnss* "$dir/lib" + +# Required by sshd +mkdir -p "$dir/var/empty" + #cat << eof > "$dir/etc/shadow" #root:x:0:0:root:/root:/bin/bash #nobody:x:1:::::: From edf01900f3d0490fcc380b49e9a364496774f40a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 16 Jun 2015 11:16:33 +0200 Subject: [PATCH 0035/1332] fix permissions for /var/empty Signed-off-by: Nico Schottelius --- hacking/v3-busybox/sshd_config.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/hacking/v3-busybox/sshd_config.sh b/hacking/v3-busybox/sshd_config.sh index 090aae8c..f801abc9 100755 --- a/hacking/v3-busybox/sshd_config.sh +++ b/hacking/v3-busybox/sshd_config.sh @@ -39,6 +39,7 @@ cp /lib/libnss* "$dir/lib" # Required by sshd mkdir -p "$dir/var/empty" +chmod 0700 "$dir/var/empty" #cat << eof > "$dir/etc/shadow" #root:x:0:0:root:/root:/bin/bash From c829be2d40d110dcdccb043df82f0ae95cffb181 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 16 Jun 2015 11:21:36 +0200 Subject: [PATCH 0036/1332] change owner to root in initramfs Signed-off-by: Nico Schottelius --- hacking/v3-busybox/create_initramfs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hacking/v3-busybox/create_initramfs.sh b/hacking/v3-busybox/create_initramfs.sh index 70bc77ed..61171d0d 100755 --- a/hacking/v3-busybox/create_initramfs.sh +++ b/hacking/v3-busybox/create_initramfs.sh @@ -29,7 +29,7 @@ zcat /boot/initramfs-linux-fallback.img | cpio -i # Create new initramfs -find . | cpio -H newc -o | gzip +find . | cpio -H newc -R root -o | gzip # echo ${initramfs_dir} rm -rf "${initramfs_dir}" From b515601c9c8d49b415fe7f98baf2110475fecaec Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 23 Jul 2015 22:05:55 +0200 Subject: [PATCH 0037/1332] create /var/run/consul with permissions suitable for storing unix sockets Signed-off-by: Steven Armstrong --- .../type/__consul_agent/files/consul-prepare.upstart | 9 +++++++++ cdist/conf/type/__consul_agent/files/consul.systemd | 5 +++++ cdist/conf/type/__consul_agent/files/consul.sysv-debian | 7 ++++++- cdist/conf/type/__consul_agent/files/consul.sysv-redhat | 4 +++- cdist/conf/type/__consul_agent/manifest | 9 +++++++-- 5 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 cdist/conf/type/__consul_agent/files/consul-prepare.upstart diff --git a/cdist/conf/type/__consul_agent/files/consul-prepare.upstart b/cdist/conf/type/__consul_agent/files/consul-prepare.upstart new file mode 100644 index 00000000..569220d1 --- /dev/null +++ b/cdist/conf/type/__consul_agent/files/consul-prepare.upstart @@ -0,0 +1,9 @@ +start on starting consul + +task + +script + mkdir -p /var/run/consul + chown consul:consul /var/run/consul + chmod 2770 /var/run/consul +end script diff --git a/cdist/conf/type/__consul_agent/files/consul.systemd b/cdist/conf/type/__consul_agent/files/consul.systemd index db624fd1..8d5fd323 100644 --- a/cdist/conf/type/__consul_agent/files/consul.systemd +++ b/cdist/conf/type/__consul_agent/files/consul.systemd @@ -7,6 +7,11 @@ After=basic.target network.target User=consul Group=consul Environment="GOMAXPROCS=2" +# Run ExecStartPre with root-permissions +PermissionsStartOnly=true +ExecStartPre=/usr/bin/mkdir -p /var/run/consul +ExecStartPre=/usr/bin/chown consul:consul /var/run/consul +ExecStartPre=/usr/bin/chmod 2770 /var/run/consul ExecStart=/usr/local/bin/consul agent -config-dir /etc/consul/conf.d ExecReload=/bin/kill -HUP $MAINPID KillMode=process diff --git a/cdist/conf/type/__consul_agent/files/consul.sysv-debian b/cdist/conf/type/__consul_agent/files/consul.sysv-debian index f4498041..a75c555d 100644 --- a/cdist/conf/type/__consul_agent/files/consul.sysv-debian +++ b/cdist/conf/type/__consul_agent/files/consul.sysv-debian @@ -1,6 +1,7 @@ #!/bin/sh # # 2015 Nico Schottelius (nico-cdist at schottelius.org) +# 2015 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -29,6 +30,10 @@ CONSUL=/usr/local/bin/consul CONFIG=/etc/$NAME/conf.d PID_FILE=/var/run/$NAME/pidfile +mkdir -p /var/run/$NAME +chown consul:consul /var/run/$NAME +chmod 2770 /var/run/$NAME + export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" case "$1" in @@ -51,7 +56,7 @@ case "$1" in log_end_msg 1 || true fi ;; - + reload) log_daemon_msg "Reloading consul agent" "consul" || true if start-stop-daemon --stop --signal HUP --quiet --oknodo --pidfile $PID_FILE --exec $CONSUL; then diff --git a/cdist/conf/type/__consul_agent/files/consul.sysv-redhat b/cdist/conf/type/__consul_agent/files/consul.sysv-redhat index 9a2aaeb2..44fd8737 100644 --- a/cdist/conf/type/__consul_agent/files/consul.sysv-redhat +++ b/cdist/conf/type/__consul_agent/files/consul.sysv-redhat @@ -22,7 +22,9 @@ LOG_FILE=/var/log/$NAME export GOMAXPROCS=${GOMAXPROCS:-2} mkdir -p /var/run/$NAME -chown consul /var/run/$NAME +chown consul:consul /var/run/$NAME +chmod 2770 /var/run/$NAME + start() { echo -n "Starting $NAME: " diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index f8cace94..053c9e80 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -160,10 +160,15 @@ init_systemd() init_upstart() { - __file /etc/init/consul.conf \ + __file /etc/init/consul-prepare.conf \ --owner root --group root --mode 0644 \ --state "$state" \ - --source "$__type/files/consul.upstart" + --source "$__type/files/consul-prepare.upstart" + require="__file/etc/init/consul-prepare.conf" \ + __file /etc/init/consul.conf \ + --owner root --group root --mode 0644 \ + --state "$state" \ + --source "$__type/files/consul.upstart" require="__file/etc/init/consul.conf" __start_on_boot consul } From c4aef429c2c5f2a407f66ecd034af7e2a79d966f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 23 Jul 2015 23:19:33 +0200 Subject: [PATCH 0038/1332] dont use `consul leave` to shutdown, just kill instead If all servers in a cluster leave, the cluster is basically destroyed. Servers are supposed to just die without leaving, otherwise rejoin no longer works and manual recovery is required. Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_agent/files/consul.sysv-redhat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__consul_agent/files/consul.sysv-redhat b/cdist/conf/type/__consul_agent/files/consul.sysv-redhat index 44fd8737..13dafd2e 100644 --- a/cdist/conf/type/__consul_agent/files/consul.sysv-redhat +++ b/cdist/conf/type/__consul_agent/files/consul.sysv-redhat @@ -38,7 +38,7 @@ start() { stop() { echo -n "Shutting down $NAME: " - "$CONSUL" leave + killproc -p "$PID_FILE" $NAME retcode=$? rm -f /var/lock/subsys/$NAME return $retcode @@ -88,7 +88,7 @@ case "$1" in fi ;; *) - echo "Usage: $NAME {start|stop|status|reload|restart}" + echo "Usage: $NAME {start|stop|status|reload|restart|condrestart|info}" exit 1 ;; esac From a2349124063ba3fa5596238f5fd09cd77f41d1c9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 23 Jul 2015 23:33:52 +0200 Subject: [PATCH 0039/1332] support version 0.10.0 Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_template/files/versions/0.10.0/cksum | 1 + cdist/conf/type/__consul_template/files/versions/0.10.0/source | 1 + cdist/conf/type/__consul_template/todo | 2 -- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 cdist/conf/type/__consul_template/files/versions/0.10.0/cksum create mode 100644 cdist/conf/type/__consul_template/files/versions/0.10.0/source delete mode 100644 cdist/conf/type/__consul_template/todo diff --git a/cdist/conf/type/__consul_template/files/versions/0.10.0/cksum b/cdist/conf/type/__consul_template/files/versions/0.10.0/cksum new file mode 100644 index 00000000..bbf394db --- /dev/null +++ b/cdist/conf/type/__consul_template/files/versions/0.10.0/cksum @@ -0,0 +1 @@ +3401777891 9273880 consul-template diff --git a/cdist/conf/type/__consul_template/files/versions/0.10.0/source b/cdist/conf/type/__consul_template/files/versions/0.10.0/source new file mode 100644 index 00000000..7fa074b5 --- /dev/null +++ b/cdist/conf/type/__consul_template/files/versions/0.10.0/source @@ -0,0 +1 @@ +https://github.com/hashicorp/consul-template/releases/download/v0.10.0/consul-template_0.10.0_linux_amd64.tar.gz diff --git a/cdist/conf/type/__consul_template/todo b/cdist/conf/type/__consul_template/todo deleted file mode 100644 index a3786501..00000000 --- a/cdist/conf/type/__consul_template/todo +++ /dev/null @@ -1,2 +0,0 @@ -- add support for latest version 0.7.0 - - config file format has changed From 6fb35c7d90e9598ac8891244d047757986db81d4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 23 Jul 2015 23:36:20 +0200 Subject: [PATCH 0040/1332] make 0.10.0 the default version Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_template/parameter/default/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul_template/parameter/default/version b/cdist/conf/type/__consul_template/parameter/default/version index ef5e4454..78bc1abd 100644 --- a/cdist/conf/type/__consul_template/parameter/default/version +++ b/cdist/conf/type/__consul_template/parameter/default/version @@ -1 +1 @@ -0.6.5 +0.10.0 From 543d79a7b54610690906a7ff66c09524f56363ca Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 24 Jul 2015 00:21:08 +0200 Subject: [PATCH 0041/1332] drop support for <0.10.0 Signed-off-by: Steven Armstrong --- .../files/versions/0.6.5/cksum | 1 - .../files/versions/0.6.5/source | 1 - .../files/versions/0.9.0/cksum | 1 - .../files/versions/0.9.0/source | 1 - cdist/conf/type/__consul_template/man.text | 13 ++++ cdist/conf/type/__consul_template/manifest | 63 ++++++++++++++++--- 6 files changed, 68 insertions(+), 12 deletions(-) delete mode 100644 cdist/conf/type/__consul_template/files/versions/0.6.5/cksum delete mode 100644 cdist/conf/type/__consul_template/files/versions/0.6.5/source delete mode 100644 cdist/conf/type/__consul_template/files/versions/0.9.0/cksum delete mode 100644 cdist/conf/type/__consul_template/files/versions/0.9.0/source diff --git a/cdist/conf/type/__consul_template/files/versions/0.6.5/cksum b/cdist/conf/type/__consul_template/files/versions/0.6.5/cksum deleted file mode 100644 index 2dcac994..00000000 --- a/cdist/conf/type/__consul_template/files/versions/0.6.5/cksum +++ /dev/null @@ -1 +0,0 @@ -1356006333 8496656 consul-template diff --git a/cdist/conf/type/__consul_template/files/versions/0.6.5/source b/cdist/conf/type/__consul_template/files/versions/0.6.5/source deleted file mode 100644 index 09a1ce3a..00000000 --- a/cdist/conf/type/__consul_template/files/versions/0.6.5/source +++ /dev/null @@ -1 +0,0 @@ -https://github.com/hashicorp/consul-template/releases/download/v0.6.5/consul-template_0.6.5_linux_amd64.tar.gz diff --git a/cdist/conf/type/__consul_template/files/versions/0.9.0/cksum b/cdist/conf/type/__consul_template/files/versions/0.9.0/cksum deleted file mode 100644 index 0f86f500..00000000 --- a/cdist/conf/type/__consul_template/files/versions/0.9.0/cksum +++ /dev/null @@ -1 +0,0 @@ -4037434610 8901128 consul-template diff --git a/cdist/conf/type/__consul_template/files/versions/0.9.0/source b/cdist/conf/type/__consul_template/files/versions/0.9.0/source deleted file mode 100644 index 25fd18e9..00000000 --- a/cdist/conf/type/__consul_template/files/versions/0.9.0/source +++ /dev/null @@ -1 +0,0 @@ -https://github.com/hashicorp/consul-template/releases/download/v0.9.0/consul-template_0.9.0_linux_amd64.tar.gz diff --git a/cdist/conf/type/__consul_template/man.text b/cdist/conf/type/__consul_template/man.text index 876690ee..0d86aee8 100644 --- a/cdist/conf/type/__consul_template/man.text +++ b/cdist/conf/type/__consul_template/man.text @@ -57,6 +57,15 @@ syslog-facility:: The default value is LOCAL0. token:: the Consul API token. +vault-address:: + the location of the Vault instance to query (may be an IP address or FQDN) with port. +vault-token:: + the Vault API token. +vault-ssl-cert:: + Path to an SSL client certificate to use to authenticate to the vault server. +vault-ssl-ca-cert:: + Path to a CA certificate file, containing one or more CA certificates to + use to validate the certificate sent by the vault server to us. version:: which version of consul-template to install. See ./files/versions for a list of supported versions. Defaults to the latest known version. @@ -74,6 +83,10 @@ ssl-no-verify:: ignore certificate warnings. Only used if ssl is enabled. syslog:: Send log output to syslog (in addition to stdout and stderr). +vault-ssl:: + use HTTPS while talking to Vault. Requires the Vault server to be configured to serve secure connections. +vault-ssl-no-verify:: + ignore certificate warnings. Only used if vault is enabled. EXAMPLES diff --git a/cdist/conf/type/__consul_template/manifest b/cdist/conf/type/__consul_template/manifest index edeca89c..cedcb413 100755 --- a/cdist/conf/type/__consul_template/manifest +++ b/cdist/conf/type/__consul_template/manifest @@ -77,17 +77,64 @@ require="__directory/etc/consul-template" \ ( for param in $(ls "$__object/parameter/"); do case "$param" in - ssl|ssl-no-verify) # boolean - key="$(echo "$param" | tr '-' '_')" - printf '%s = true\n' "$key" + auth-password|state|ssl-*|syslog-*|version|vault-token|vault-ssl*) continue ;; + auth-username) + printf 'auth {\n' + printf ' enabled = true\n' + printf ' username = "%s"\n' "$(cat "$__object/parameter/auth-username")" + if [ -f "$__object/parameter/auth-password" ]; then + printf ' password = %s\n' "$(cat "$__object/parameter/auth-password")" + fi + printf '}\n' ;; - auth|batch-size|consul|max-stale|retry|token|wait) - key="$(echo "$param" | tr '-' '_')" - printf '%s = "%s"\n' "$key" "$(cat "$__object/parameter/$param")" + ssl) + printf 'ssl {\n' + printf ' enabled = true\n' + if [ -f "$__object/parameter/ssl-no-verify" ]; then + printf ' verify = false\n' + fi + if [ -f "$__object/parameter/ssl-cert" ]; then + printf ' cert = "%s"\n' "$(cat "$__object/parameter/ssl-cert")" + fi + if [ -f "$__object/parameter/ssl-ca-cert" ]; then + printf ' ca_cert = "%s"\n' "$(cat "$__object/parameter/ssl-ca-cert")" + fi + printf '}\n' + ;; + syslog) + printf 'syslog {\n' + printf ' enabled = true\n' + if [ -f "$__object/parameter/syslog-facility" ]; then + printf ' facility = "%s"\n' "$(cat "$__object/parameter/syslog-facility")" + fi + printf '}\n' + ;; + vault-address) + printf 'vault {\n' + printf ' address = "%s"\n' "$(cat "$__object/parameter/vault-address")" + if [ -f "$__object/parameter/vault-token" ]; then + printf ' token = "%s"\n' "$(cat "$__object/parameter/vault-token")" + fi + if [ -f "$__object/parameter/vault-ssl" ]; then + printf ' ssl {\n' + printf ' enabled = true\n' + if [ -f "$__object/parameter/vault-ssl-no-verify" ]; then + printf ' verify = false\n' + fi + if [ -f "$__object/parameter/vault-ssl-cert" ]; then + printf ' cert = "%s"\n' "$(cat "$__object/parameter/vault-ssl-cert")" + fi + if [ -f "$__object/parameter/vault-ssl-ca-cert" ]; then + printf ' ca_cert = "%s"\n' "$(cat "$__object/parameter/vault-ssl-ca-cert")" + fi + printf ' }\n' + fi + printf '}\n' ;; *) - # ignore unknown parameters - : + # string key=value parameters + key="$(echo "$param" | tr '-' '_')" + printf '%s = "%s"\n' "$key" "$(cat "$__object/parameter/$param")" ;; esac done From 31dddca0db19defea55d03120004f948694a9b11 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 24 Jul 2015 00:24:10 +0200 Subject: [PATCH 0042/1332] update params Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_template/parameter/boolean | 2 ++ cdist/conf/type/__consul_template/parameter/optional | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/cdist/conf/type/__consul_template/parameter/boolean b/cdist/conf/type/__consul_template/parameter/boolean index 696f66ee..10057e46 100644 --- a/cdist/conf/type/__consul_template/parameter/boolean +++ b/cdist/conf/type/__consul_template/parameter/boolean @@ -1,3 +1,5 @@ ssl ssl-no-verify syslog +vault-ssl +vault-ssl-no-verify diff --git a/cdist/conf/type/__consul_template/parameter/optional b/cdist/conf/type/__consul_template/parameter/optional index 5ad9679d..8bc528ac 100644 --- a/cdist/conf/type/__consul_template/parameter/optional +++ b/cdist/conf/type/__consul_template/parameter/optional @@ -10,5 +10,9 @@ ssl-cert ssl-ca-cert syslog-facility token +vault-address +vault-token +vault-ssl-cert +vault-ssl-ca-cert version wait From 7d6990d9332dc8c6d1056678a918568dd95ca2c3 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Wed, 29 Jul 2015 11:13:07 +0200 Subject: [PATCH 0043/1332] By default, package is not autoremoved, if it either suggested or recommened, but not is dependency for some other. With this change, either package is dependency of manually installed, either is is subject to autoremove. --- cdist/conf/type/__apt_norecommends/manifest | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__apt_norecommends/manifest b/cdist/conf/type/__apt_norecommends/manifest index 881c2427..6fdc2d93 100755 --- a/cdist/conf/type/__apt_norecommends/manifest +++ b/cdist/conf/type/__apt_norecommends/manifest @@ -30,6 +30,8 @@ case "$os" in --source - << DONE APT::Install-Recommends "0"; APT::Install-Suggests "0"; +APT::AutoRemove::RecommendsImportant "0"; +APT::AutoRemove::SuggestsImportant "0"; DONE ;; *) From 56e51f834fd68249762fb1a4e70bf239ef07bd09 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 29 Jul 2015 12:54:30 +0200 Subject: [PATCH 0044/1332] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 52b5d03a..0189ed99 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * New type: __pacman_conf: Manage pacman.conf (Dominique Roux) * New type: __pacman_conf_integrate: cdist compatible pacman.conf (Dominique Roux) * Core: Support object ids '.cdist' (Nico Schottelius) + * Type __apt_norecommends: Also setup autoremove options (Dmitry Bogatov) 3.1.13: 2015-05-16 From c3bf4c7b610df27a2ba5a206456584b7914fcf4f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Aug 2015 20:45:31 +0200 Subject: [PATCH 0045/1332] correctly merge and reformat custom json into generated config Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_agent/manifest | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index 053c9e80..76bd6032 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -126,10 +126,10 @@ if [ -f "$__object/parameter/json-config" ]; then if [ "$json_config" = "-" ]; then json_config="$__object/stdin" fi - printf ',' - # remove trailing , - json=$(cat "$json_config") - echo "${json%*,}" + # remove leading and trailing whitespace and commas from first and last line + # indent each line with 3 spaces for consistency + json=$(sed -e 's/^[ \t]*/ /' -e '1s/^[ \t,]*//' -e '$s/[ \t,]*$//' "$json_config") + printf ' ,%s\n' "$json" fi echo "}" ) | \ From ef98c54989cc8577e49582e7d7f3a6e529ce11dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=BCrlimann?= Date: Fri, 14 Aug 2015 22:54:55 +0200 Subject: [PATCH 0046/1332] Added retry-join-wan to consul parameters --- cdist/conf/type/__consul_agent/manifest | 6 ++++++ cdist/conf/type/__consul_agent/parameter/optional_multiple | 1 + 2 files changed, 7 insertions(+) diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index f8cace94..9dd51b28 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -109,6 +109,12 @@ for param in $(ls "$__object/parameter/"); do # remove trailing , printf ' ,"retry_join": [%s]\n' "${retry_join%*,}" ;; + retry-join-wan) + # join multiple parameters into json array over wan + retry_join_wan="$(awk '{printf "\""$1"\","}' "$__object/parameter/retry-join-wan")" + # remove trailing , + printf ' ,"retry_join_wan": [%s]\n' "${retry_join_wan%*,}" + ;; bootstrap-expect) # integer key=value parameters key="$(echo "$param" | tr '-' '_')" diff --git a/cdist/conf/type/__consul_agent/parameter/optional_multiple b/cdist/conf/type/__consul_agent/parameter/optional_multiple index 12cd064c..740e4d7f 100644 --- a/cdist/conf/type/__consul_agent/parameter/optional_multiple +++ b/cdist/conf/type/__consul_agent/parameter/optional_multiple @@ -1 +1,2 @@ retry-join +retry-join-wan From 0057ee5558327342ff6cbd4048474cbe6cb5fdd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=BCrlimann?= Date: Sat, 15 Aug 2015 22:04:27 +0200 Subject: [PATCH 0047/1332] Added new version for consul --- cdist/conf/type/__consul/files/versions/0.5.2/cksum | 1 + cdist/conf/type/__consul/files/versions/0.5.2/source | 1 + 2 files changed, 2 insertions(+) create mode 100644 cdist/conf/type/__consul/files/versions/0.5.2/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.5.2/source diff --git a/cdist/conf/type/__consul/files/versions/0.5.2/cksum b/cdist/conf/type/__consul/files/versions/0.5.2/cksum new file mode 100644 index 00000000..1c077266 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.5.2/cksum @@ -0,0 +1 @@ +2207534901 18245010 consul diff --git a/cdist/conf/type/__consul/files/versions/0.5.2/source b/cdist/conf/type/__consul/files/versions/0.5.2/source new file mode 100644 index 00000000..991034ce --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.5.2/source @@ -0,0 +1 @@ +https://dl.bintray.com/mitchellh/consul/0.5.2_linux_amd64.zip From 7de303147c972a7432cdf3178d56e1a0f23dc8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=BCrlimann?= Date: Fri, 14 Aug 2015 22:54:55 +0200 Subject: [PATCH 0048/1332] Added retry-join-wan to consul parameters From 90f3f81c390492d558d08e746fe8a43d3f2f686f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=BCrlimann?= Date: Fri, 28 Aug 2015 01:25:05 +0200 Subject: [PATCH 0049/1332] Added advertise-wan as optional parameter for consul --- cdist/conf/type/__consul_agent/parameter/optional | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__consul_agent/parameter/optional b/cdist/conf/type/__consul_agent/parameter/optional index 8940023d..37aad8c1 100644 --- a/cdist/conf/type/__consul_agent/parameter/optional +++ b/cdist/conf/type/__consul_agent/parameter/optional @@ -17,3 +17,4 @@ key-file-source node-name user state +advertise-wan From ed75374b9509b948e320cf6442a629df2b33dee9 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Thu, 15 Oct 2015 10:12:11 -0500 Subject: [PATCH 0050/1332] support NetBSD in __timezone type --- cdist/conf/type/__timezone/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index 3bcb05c6..9b0cce73 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -34,7 +34,7 @@ case "$os" in __package timezone export require="__package/timezone" ;; - freebsd) + freebsd|netbsd) # whitelist : ;; From 185d7f593a01bd62dcec0c3f358103fba9ec9890 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Thu, 15 Oct 2015 10:22:46 -0500 Subject: [PATCH 0051/1332] Treat NetBSD the same as FreeBSD and OpenBSD in 'stat' explorers --- cdist/conf/type/__ccollect_source/explorer/stat | 2 +- cdist/conf/type/__directory/explorer/stat | 2 +- cdist/conf/type/__file/explorer/stat | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__ccollect_source/explorer/stat b/cdist/conf/type/__ccollect_source/explorer/stat index 7c86d94f..9b5ad75b 100755 --- a/cdist/conf/type/__ccollect_source/explorer/stat +++ b/cdist/conf/type/__ccollect_source/explorer/stat @@ -25,7 +25,7 @@ destination="/$__object_id" os=$("$__explorer/os") case "$os" in - "freebsd"|"openbsd") + "freebsd"|"netbsd"|"openbsd") # FIXME: should be something like this based on man page, but can not test stat -f "type: %ST owner: %Du %Su diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat index 077aa43b..41bc8b04 100755 --- a/cdist/conf/type/__directory/explorer/stat +++ b/cdist/conf/type/__directory/explorer/stat @@ -25,7 +25,7 @@ destination="/$__object_id" os=$("$__explorer/os") case "$os" in - "freebsd"|"openbsd") + "freebsd"|"netbsd"|"openbsd") # FIXME: should be something like this based on man page, but can not test stat -f "type: %ST owner: %Du %Su diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat index 00e34cca..8a917556 100755 --- a/cdist/conf/type/__file/explorer/stat +++ b/cdist/conf/type/__file/explorer/stat @@ -25,7 +25,7 @@ destination="/$__object_id" os=$("$__explorer/os") case "$os" in - "freebsd"|"openbsd") + "freebsd"|"netbsd"|"openbsd") # FIXME: should be something like this based on man page, but can not test stat -f "type: %ST owner: %Du %Su From cef2b32663edc4d6902a5d5016578061b3501d62 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Thu, 15 Oct 2015 10:42:11 -0500 Subject: [PATCH 0052/1332] don't use the non-existant gshadow database on NetBSD either --- cdist/conf/type/__group/explorer/gshadow | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__group/explorer/gshadow b/cdist/conf/type/__group/explorer/gshadow index 8d40e9e0..2e2ab29d 100755 --- a/cdist/conf/type/__group/explorer/gshadow +++ b/cdist/conf/type/__group/explorer/gshadow @@ -24,9 +24,11 @@ name=$__object_id os="$($__explorer/os)" -if [ "$os" = "freebsd" ]; then - echo "FreeBSD does not have getent gshadow" - exit 0 -fi +case "$os" in + "freebsd"|"netbsd") + echo "$os does not have getent gshadow" + exit 0 + ;; +esac getent gshadow "$name" || true From cdd5f380c4bdafcade6964109a3c17718c9296cd Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Thu, 15 Oct 2015 10:44:22 -0500 Subject: [PATCH 0053/1332] use passwd database instead of shadow database on NetBSD too --- cdist/conf/type/__user/explorer/shadow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__user/explorer/shadow b/cdist/conf/type/__user/explorer/shadow index 59abaa8a..1a8fd809 100755 --- a/cdist/conf/type/__user/explorer/shadow +++ b/cdist/conf/type/__user/explorer/shadow @@ -27,7 +27,7 @@ os="$($__explorer/os)" database="shadow" case "$os" in - "freebsd"|"openbsd") database="passwd";; + "freebsd"|"netbsd"|"openbsd") database="passwd";; esac From 90fe1bf6c94f231d8a78fd7daaa6dd5dae313e30 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Thu, 15 Oct 2015 10:53:56 -0500 Subject: [PATCH 0054/1332] add some NetBSD support in __user_groups --- cdist/conf/type/__user_groups/explorer/group | 2 +- cdist/conf/type/__user_groups/explorer/oldusermod | 7 +++++++ cdist/conf/type/__user_groups/gencode-remote | 8 +++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__user_groups/explorer/group b/cdist/conf/type/__user_groups/explorer/group index a8cb63af..5bad9a0b 100755 --- a/cdist/conf/type/__user_groups/explorer/group +++ b/cdist/conf/type/__user_groups/explorer/group @@ -20,4 +20,4 @@ user="$(cat "$__object/parameter/user" 2>/dev/null || echo "$__object_id")" -(id --groups --name "$user" | tr ' ' '\n' | sort) 2>/dev/null || true +(id -G -n "$user" | tr ' ' '\n' | sort) 2>/dev/null || true diff --git a/cdist/conf/type/__user_groups/explorer/oldusermod b/cdist/conf/type/__user_groups/explorer/oldusermod index 6ef25b13..bf43fcec 100644 --- a/cdist/conf/type/__user_groups/explorer/oldusermod +++ b/cdist/conf/type/__user_groups/explorer/oldusermod @@ -18,4 +18,11 @@ # along with cdist. If not, see . # +os="$($__explorer/os)" + +if [ "$os" = "netbsd" ]; then + echo netbsd + exit +fi + usermod --help | grep -q -- '-A group' && echo true || echo false diff --git a/cdist/conf/type/__user_groups/gencode-remote b/cdist/conf/type/__user_groups/gencode-remote index 65404bfc..8b13f32c 100755 --- a/cdist/conf/type/__user_groups/gencode-remote +++ b/cdist/conf/type/__user_groups/gencode-remote @@ -21,8 +21,14 @@ user="$(cat "$__object/parameter/user" 2>/dev/null || echo "$__object_id")" state_should="$(cat "$__object/parameter/state")" oldusermod="$(cat "$__object/explorer/oldusermod")" +os=$(cat "$__global/explorer/os") -if [ "$oldusermod" = "true" ]; then +if [ "$os" = "netbsd" ]; then + # NetBSD does not have a command to remove a user from a group + oldusermod="true" + addparam="-G" + delparam=";;#" +elif [ "$oldusermod" = "true" ]; then addparam="-A" delparam="-R" else From d1d065a3e1519795fdd82a0ce285413b3ee6c1a4 Mon Sep 17 00:00:00 2001 From: Christian Kruse Date: Thu, 18 Feb 2016 11:02:32 +0100 Subject: [PATCH 0055/1332] fix: don't overwrite ownergroup but append --- cdist/conf/type/__rsync/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__rsync/gencode-remote b/cdist/conf/type/__rsync/gencode-remote index 56268389..a1135ea6 100644 --- a/cdist/conf/type/__rsync/gencode-remote +++ b/cdist/conf/type/__rsync/gencode-remote @@ -29,7 +29,7 @@ if [ -f "$__object/parameter/owner" ]; then ownergroup=$(cat "$__object/parameter/owner") fi if [ -f "$__object/parameter/group" ]; then - ownergroup=":$(cat "$__object/parameter/group")" + ownergroup="${ownergroup}:$(cat "$__object/parameter/group")" fi if [ "$ownergroup" ]; then From f0e07903b62f2c45ac6548dc0e0f3e6a1eec4af9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 20 Feb 2016 12:48:29 +0100 Subject: [PATCH 0056/1332] fix download url for consul 0.5.2 Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul/files/versions/0.5.2/source | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul/files/versions/0.5.2/source b/cdist/conf/type/__consul/files/versions/0.5.2/source index 991034ce..43b43d55 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.2/source +++ b/cdist/conf/type/__consul/files/versions/0.5.2/source @@ -1 +1 @@ -https://dl.bintray.com/mitchellh/consul/0.5.2_linux_amd64.zip +https://releases.hashicorp.com/consul/0.5.2/consul_0.5.2_linux_amd64.zip From 37fec8b3b550e4192a32646934bda897c3ff8b4b Mon Sep 17 00:00:00 2001 From: Stephan Leemburg Date: Tue, 23 Feb 2016 11:54:08 +0100 Subject: [PATCH 0057/1332] Added Mitel as a redhat derived OS --- cdist/conf/explorer/os | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index 053177eb..b9f3512b 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -77,6 +77,11 @@ if grep -q ^Fedora /etc/redhat-release 2>/dev/null; then exit 0 fi +if grep -q ^Mitel /etc/redhat-release 2>/dev/null; then + echo mitel + exit 0 +fi + if [ -f /etc/redhat-release ]; then echo redhat exit 0 From b03a4f2829c71f432e71fe27105e1fbb08c2a074 Mon Sep 17 00:00:00 2001 From: Stephan Leemburg Date: Tue, 23 Feb 2016 12:57:21 +0100 Subject: [PATCH 0058/1332] Added Mitel as a redhat derived OS --- cdist/conf/explorer/os_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/explorer/os_version b/cdist/conf/explorer/os_version index 50889429..8f092827 100755 --- a/cdist/conf/explorer/os_version +++ b/cdist/conf/explorer/os_version @@ -51,7 +51,7 @@ case "$($__explorer/os)" in owl) cat /etc/owl-release ;; - redhat|centos) + redhat|centos|mitel) cat /etc/redhat-release ;; slackware) From bf4ece76fde6a357f759ec27b723b9ea79ba9dc9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Feb 2016 07:17:27 +0100 Subject: [PATCH 0059/1332] update __consul with new URLs and new versions Signed-off-by: Nico Schottelius --- cdist/conf/type/__consul/files/versions/0.4.1/source | 2 +- cdist/conf/type/__consul/files/versions/0.5.0/source | 2 +- cdist/conf/type/__consul/files/versions/0.5.1/source | 2 +- cdist/conf/type/__consul/files/versions/0.5.2/source | 2 +- cdist/conf/type/__consul/files/versions/0.6.0/cksum | 1 + cdist/conf/type/__consul/files/versions/0.6.0/source | 1 + cdist/conf/type/__consul/files/versions/0.6.1/cksum | 1 + cdist/conf/type/__consul/files/versions/0.6.1/source | 1 + cdist/conf/type/__consul/files/versions/0.6.2/cksum | 1 + cdist/conf/type/__consul/files/versions/0.6.2/source | 1 + cdist/conf/type/__consul/files/versions/0.6.3/cksum | 1 + cdist/conf/type/__consul/files/versions/0.6.3/source | 1 + cdist/conf/type/__consul/manifest | 1 + 13 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 cdist/conf/type/__consul/files/versions/0.6.0/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.6.0/source create mode 100644 cdist/conf/type/__consul/files/versions/0.6.1/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.6.1/source create mode 100644 cdist/conf/type/__consul/files/versions/0.6.2/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.6.2/source create mode 100644 cdist/conf/type/__consul/files/versions/0.6.3/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.6.3/source diff --git a/cdist/conf/type/__consul/files/versions/0.4.1/source b/cdist/conf/type/__consul/files/versions/0.4.1/source index b1e9908d..7fb949c8 100644 --- a/cdist/conf/type/__consul/files/versions/0.4.1/source +++ b/cdist/conf/type/__consul/files/versions/0.4.1/source @@ -1 +1 @@ -https://dl.bintray.com/mitchellh/consul/0.4.1_linux_amd64.zip +https://releases.hashicorp.com/consul/0.4.1/consul_0.4.1_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.5.0/source b/cdist/conf/type/__consul/files/versions/0.5.0/source index 00a209a5..dc1c33c4 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.0/source +++ b/cdist/conf/type/__consul/files/versions/0.5.0/source @@ -1 +1 @@ -https://dl.bintray.com/mitchellh/consul/0.5.0_linux_amd64.zip +https://releases.hashicorp.com/consul/0.5.0/consul_0.5.0_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.5.1/source b/cdist/conf/type/__consul/files/versions/0.5.1/source index f02a1103..a47eb69c 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.1/source +++ b/cdist/conf/type/__consul/files/versions/0.5.1/source @@ -1 +1 @@ -https://dl.bintray.com/mitchellh/consul/0.5.1_linux_amd64.zip +https://releases.hashicorp.com/consul/0.5.1/consul_0.5.1_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.5.2/source b/cdist/conf/type/__consul/files/versions/0.5.2/source index 991034ce..43b43d55 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.2/source +++ b/cdist/conf/type/__consul/files/versions/0.5.2/source @@ -1 +1 @@ -https://dl.bintray.com/mitchellh/consul/0.5.2_linux_amd64.zip +https://releases.hashicorp.com/consul/0.5.2/consul_0.5.2_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.6.0/cksum b/cdist/conf/type/__consul/files/versions/0.6.0/cksum new file mode 100644 index 00000000..bf41a9b8 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.0/cksum @@ -0,0 +1 @@ +688442448 19798264 consul diff --git a/cdist/conf/type/__consul/files/versions/0.6.0/source b/cdist/conf/type/__consul/files/versions/0.6.0/source new file mode 100644 index 00000000..691f2a87 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.0/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/0.6.0/consul_0.6.0_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.6.1/cksum b/cdist/conf/type/__consul/files/versions/0.6.1/cksum new file mode 100644 index 00000000..aa354351 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.1/cksum @@ -0,0 +1 @@ +3100584780 20416856 consul diff --git a/cdist/conf/type/__consul/files/versions/0.6.1/source b/cdist/conf/type/__consul/files/versions/0.6.1/source new file mode 100644 index 00000000..3b20388f --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.1/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/0.6.1/consul_0.6.1_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.6.2/cksum b/cdist/conf/type/__consul/files/versions/0.6.2/cksum new file mode 100644 index 00000000..9c0b35c5 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.2/cksum @@ -0,0 +1 @@ +2124180907 20416920 consul diff --git a/cdist/conf/type/__consul/files/versions/0.6.2/source b/cdist/conf/type/__consul/files/versions/0.6.2/source new file mode 100644 index 00000000..b0c6eeed --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.2/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/0.6.2/consul_0.6.2_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.6.3/cksum b/cdist/conf/type/__consul/files/versions/0.6.3/cksum new file mode 100644 index 00000000..886d01bb --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.3/cksum @@ -0,0 +1 @@ +1832669072 20417720 consul diff --git a/cdist/conf/type/__consul/files/versions/0.6.3/source b/cdist/conf/type/__consul/files/versions/0.6.3/source new file mode 100644 index 00000000..fef668be --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.3/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/0.6.3/consul_0.6.3_linux_amd64.zip diff --git a/cdist/conf/type/__consul/manifest b/cdist/conf/type/__consul/manifest index ea1a728f..eec71d0b 100755 --- a/cdist/conf/type/__consul/manifest +++ b/cdist/conf/type/__consul/manifest @@ -1,6 +1,7 @@ #!/bin/sh # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) +# 2016 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # From f6678b931fc0264f31e66a53b450872045eb0cd3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Feb 2016 07:18:19 +0100 Subject: [PATCH 0060/1332] Remove zip package from __consul as it is required on the management host only Signed-off-by: Nico Schottelius --- cdist/conf/type/__consul/manifest | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cdist/conf/type/__consul/manifest b/cdist/conf/type/__consul/manifest index eec71d0b..0187d959 100755 --- a/cdist/conf/type/__consul/manifest +++ b/cdist/conf/type/__consul/manifest @@ -44,9 +44,7 @@ if [ ! -d "$version_dir" ]; then exit 1 fi -__package unzip - -require="__package/unzip" __staged_file /usr/local/bin/consul \ +__staged_file /usr/local/bin/consul \ --source "$(cat "$version_dir/source")" \ --cksum "$(cat "$version_dir/cksum")" \ --fetch-command 'curl -s -L "%s"' \ From fcb9e3edd96f3d4aee1092d4e3c886b7835d1be4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Feb 2016 07:18:27 +0100 Subject: [PATCH 0061/1332] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/changelog b/docs/changelog index 0189ed99..1002fbc2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,12 @@ next: * New type: __pacman_conf_integrate: cdist compatible pacman.conf (Dominique Roux) * Core: Support object ids '.cdist' (Nico Schottelius) * Type __apt_norecommends: Also setup autoremove options (Dmitry Bogatov) + * Type __user_groups: Add NetBSD support (Jonathan A. Kollasch) + * Type __timezone: Add NetBSD support (Jonathan A. Kollasch) + * Type __ccollect_source: Add NetBSD support (Jonathan A. Kollasch) + * Type __directory: Add NetBSD support (Jonathan A. Kollasch) + * Type __file: Add NetBSD support (Jonathan A. Kollasch) + * Type __group: Add NetBSD support (Jonathan A. Kollasch) 3.1.13: 2015-05-16 From 404f2051a829c325a4d43aec8c46f897af37fac5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 25 Feb 2016 07:19:32 +0100 Subject: [PATCH 0062/1332] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 1002fbc2..5e73bd2e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,7 @@ next: * Type __directory: Add NetBSD support (Jonathan A. Kollasch) * Type __file: Add NetBSD support (Jonathan A. Kollasch) * Type __group: Add NetBSD support (Jonathan A. Kollasch) + * Type __consul: Add new consul versions (Nico Schottelius) 3.1.13: 2015-05-16 From bb43a8f47f4436d424b4b4ba8eda6e7fabc0245f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 6 Mar 2016 08:20:16 +0100 Subject: [PATCH 0063/1332] Add ssh multiplexing options to default REMOTE_EXEC and REMOTE_COPY. --- cdist/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index 4454a3ac..28464710 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -41,8 +41,10 @@ BANNER = """ "P' "" "" """ -REMOTE_COPY = "scp -o User=root -q" -REMOTE_EXEC = "ssh -o User=root -q" +SSH_MUX_OPTS = ("-o ControlPath=~/.ssh/master-%l-%r@%h:%p" + " -o ControlMaster=auto -o ControlPersist=125") +REMOTE_COPY = "scp -o User=root -q " + SSH_MUX_OPTS +REMOTE_EXEC = "ssh -o User=root -q " + SSH_MUX_OPTS class Error(Exception): """Base exception class for this project""" From 2dfc30e3c45bda3cd5737d3b6064008256cd0d9b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 10 Mar 2016 20:01:08 +0100 Subject: [PATCH 0064/1332] Revert "Add ssh multiplexing options to default REMOTE_EXEC and REMOTE_COPY." This reverts commit bb43a8f47f4436d424b4b4ba8eda6e7fabc0245f. --- cdist/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index 28464710..4454a3ac 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -41,10 +41,8 @@ BANNER = """ "P' "" "" """ -SSH_MUX_OPTS = ("-o ControlPath=~/.ssh/master-%l-%r@%h:%p" - " -o ControlMaster=auto -o ControlPersist=125") -REMOTE_COPY = "scp -o User=root -q " + SSH_MUX_OPTS -REMOTE_EXEC = "ssh -o User=root -q " + SSH_MUX_OPTS +REMOTE_COPY = "scp -o User=root -q" +REMOTE_EXEC = "ssh -o User=root -q" class Error(Exception): """Base exception class for this project""" From 215e58eb388662945178bdf6f168b3bb46f589e9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 10 Mar 2016 20:20:41 +0100 Subject: [PATCH 0065/1332] Inspect and add by default ssh multiplexing options. --- scripts/cdist | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/scripts/cdist b/scripts/cdist index 39449666..d5737f9c 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # # 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2016 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -20,6 +21,32 @@ # # +def inspect_ssh_mux_opts(): + """Inspect whether or not ssh supports multiplexing options""" + wanted_mux_opts = { + "ControlPath":"~/.ssh/master-%l-%r@%h:%p", + "ControlMaster":"auto", + "ControlPersist":"125", + } + # if checked key option is present then this assumes + # all options in value are present + check = { + "ControlMaster": ("ControlMaster", "ControlPath"), + "ControlPersist": ("ControlPersist",), + } + mux_opts = {} + for x in check: + try: + subprocess.check_output("ssh -o {}".format(x), + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + foo = e.output.decode().lower() + if not "bad configuration option" in foo: + for o in check[x]: + mux_opts[o] = wanted_mux_opts[o] + foo = ["-o {}={}".format(x, mux_opts[x]) for x in mux_opts] + return " ".join(foo) + def commandline(): """Parse command line""" import argparse @@ -53,6 +80,11 @@ def commandline(): parser['banner'].set_defaults(func=cdist.banner.banner) # Config + # inspect multiplexing options for default remote copy/exec scp/ssh + MUX_OPTS = inspect_ssh_mux_opts() + cdist.REMOTE_EXEC += MUX_OPTS + cdist.REMOTE_COPY += MUX_OPTS + parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) parser['config'].add_argument('host', nargs='+', From b4ac23b4f81aea4ae00f77705100d498494f8ed7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 10 Mar 2016 20:40:37 +0100 Subject: [PATCH 0066/1332] Default ssh mux options fixes. --- scripts/cdist | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index d5737f9c..8aa998d2 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -22,6 +22,8 @@ # def inspect_ssh_mux_opts(): + import subprocess + """Inspect whether or not ssh supports multiplexing options""" wanted_mux_opts = { "ControlPath":"~/.ssh/master-%l-%r@%h:%p", @@ -38,13 +40,13 @@ def inspect_ssh_mux_opts(): for x in check: try: subprocess.check_output("ssh -o {}".format(x), - stderr=subprocess.STDOUT) + stderr=subprocess.STDOUT, shell=True) except subprocess.CalledProcessError as e: foo = e.output.decode().lower() if not "bad configuration option" in foo: for o in check[x]: mux_opts[o] = wanted_mux_opts[o] - foo = ["-o {}={}".format(x, mux_opts[x]) for x in mux_opts] + foo = [" -o {}={}".format(x, mux_opts[x]) for x in mux_opts] return " ".join(foo) def commandline(): From 8ed0c672b14f2fcb642c7511d64d839651049c59 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 11 Mar 2016 19:23:59 +0100 Subject: [PATCH 0067/1332] Fix error with args. --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 40f34e25..5aadce0c 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -195,7 +195,7 @@ class Local(object): except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: - raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + raise cdist.Error(" ".join((str(x) for x in error.args))) finally: if message_prefix: message.merge_messages() From afbb3df28083d5b91b972a2eb720b1d319e01c25 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 17 Mar 2016 23:34:30 +0100 Subject: [PATCH 0068/1332] remove legacy cruft Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_ppa/manifest | 5 ++--- docs/changelog | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__apt_ppa/manifest b/cdist/conf/type/__apt_ppa/manifest index 1d90e9c4..a67c7613 100755 --- a/cdist/conf/type/__apt_ppa/manifest +++ b/cdist/conf/type/__apt_ppa/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011-2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2016 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -21,9 +21,8 @@ name="$__object_id" __package software-properties-common -__package python-software-properties -require="__package/software-properties-common __package/python-software-properties" \ +require="__package/software-properties-common" \ __file /usr/local/bin/remove-apt-repository \ --source "$__type/files/remove-apt-repository" \ --mode 0755 diff --git a/docs/changelog b/docs/changelog index cf7e4e4b..e88b2198 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,8 @@ next: * Type __consul: Add source & cksum for 0.5.2 (Steven Armstrong) * Core: Support object ids '.cdist' (Nico Schottelius) * Type __apt_norecommends: Also setup autoremove options (Dmitry Bogatov) + * Type __apt_ppa: Do not install legacy package python-software-properties + (Steven Armstrong) 3.1.13: 2015-05-16 From 76a78f0d9b51d1f545d8dd7425a17a814782edd3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 17 Mar 2016 23:38:57 +0100 Subject: [PATCH 0069/1332] /spaces/tab/ Signed-off-by: Steven Armstrong --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index e88b2198..5a6fa726 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,7 +9,7 @@ next: * Type __consul: Add source & cksum for 0.5.2 (Steven Armstrong) * Core: Support object ids '.cdist' (Nico Schottelius) * Type __apt_norecommends: Also setup autoremove options (Dmitry Bogatov) - * Type __apt_ppa: Do not install legacy package python-software-properties + * Type __apt_ppa: Do not install legacy package python-software-properties (Steven Armstrong) From 3ae042f2cd9d468ce607344fe673cd90c0036d55 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 18 Mar 2016 12:27:23 +0100 Subject: [PATCH 0070/1332] Rverting manually (limited connectivity) to original. Will be fixed in a separate branch. --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 5aadce0c..dc7c02bc 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -195,7 +195,7 @@ class Local(object): except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: - raise cdist.Error(" ".join((str(x) for x in error.args))) + raise cdist.Error(" ".join(*args) + ": " + error.args[1]) finally: if message_prefix: message.merge_messages() From 6ae94df0a194e6314f3296567363ddb4987ec933 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 18 Mar 2016 12:29:16 +0100 Subject: [PATCH 0071/1332] Reset manually to original. Limited connectivity, but have extra time, so doing it online. Will be fixed in a separate branch. --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index dc7c02bc..40f34e25 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -195,7 +195,7 @@ class Local(object): except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: - raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + raise cdist.Error(" ".join(*args) + ": " + error.args[1]) finally: if message_prefix: message.merge_messages() From 4851197de2e4eb0657dfa5557edf3d5ca4030c0b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 18 Mar 2016 12:31:06 +0100 Subject: [PATCH 0072/1332] Reseting to original manually (limited connect). Limited connectivity, but have extra time, so reseting this to original. This new feature will be implemented in separate branch. --- scripts/cdist | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 8aa998d2..39449666 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -2,7 +2,6 @@ # -*- coding: utf-8 -*- # # 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) -# 2016 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -21,34 +20,6 @@ # # -def inspect_ssh_mux_opts(): - import subprocess - - """Inspect whether or not ssh supports multiplexing options""" - wanted_mux_opts = { - "ControlPath":"~/.ssh/master-%l-%r@%h:%p", - "ControlMaster":"auto", - "ControlPersist":"125", - } - # if checked key option is present then this assumes - # all options in value are present - check = { - "ControlMaster": ("ControlMaster", "ControlPath"), - "ControlPersist": ("ControlPersist",), - } - mux_opts = {} - for x in check: - try: - subprocess.check_output("ssh -o {}".format(x), - stderr=subprocess.STDOUT, shell=True) - except subprocess.CalledProcessError as e: - foo = e.output.decode().lower() - if not "bad configuration option" in foo: - for o in check[x]: - mux_opts[o] = wanted_mux_opts[o] - foo = [" -o {}={}".format(x, mux_opts[x]) for x in mux_opts] - return " ".join(foo) - def commandline(): """Parse command line""" import argparse @@ -82,11 +53,6 @@ def commandline(): parser['banner'].set_defaults(func=cdist.banner.banner) # Config - # inspect multiplexing options for default remote copy/exec scp/ssh - MUX_OPTS = inspect_ssh_mux_opts() - cdist.REMOTE_EXEC += MUX_OPTS - cdist.REMOTE_COPY += MUX_OPTS - parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) parser['config'].add_argument('host', nargs='+', From 5e5106479f55a184fff67ee89e3530680f8a9ec0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 18 Mar 2016 18:22:14 +0100 Subject: [PATCH 0073/1332] Fix old bug: join wrong arg for OSError. --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 40f34e25..0be803a9 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -195,7 +195,7 @@ class Local(object): except subprocess.CalledProcessError: raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: - raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + raise cdist.Error(" ".join(command) + ": " + error.args[1]) finally: if message_prefix: message.merge_messages() From d0d0c258d65a29e674e8cbe7530b4fa45da6c4c7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 18 Mar 2016 23:34:02 +0100 Subject: [PATCH 0074/1332] Add ssh mux options by default if available. --- docs/man/cdist-reference.text.sh | 6 ++++ docs/man/man1/cdist.text | 5 +++ scripts/cdist | 60 ++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 0a9d76ef..0aaaec0a 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -249,6 +249,12 @@ CDIST_OVERRIDE:: CDIST_ORDER_DEPENDENCY:: Create dependencies based on the execution order (see cdist-manifest(7)) +CDIST_REMOTE_EXEC:: + Use this command for remote execution (should behave like ssh) + +CDIST_REMOTE_COPY:: + Use this command for remote copy (should behave like scp) + SEE ALSO -------- - cdist(1) diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index c09d8f41..e29ae3ae 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -138,6 +138,11 @@ CDIST_LOCAL_SHELL:: CDIST_REMOTE_SHELL:: Selects shell for remote scirpt execution, defaults to /bin/sh +CDIST_REMOTE_EXEC:: + Use this command for remote execution (should behave like ssh) + +CDIST_REMOTE_COPY:: + Use this command for remote copy (should behave like scp) EXIT STATUS ----------- diff --git a/scripts/cdist b/scripts/cdist index 8aa998d2..f5629641 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -21,33 +21,27 @@ # # -def inspect_ssh_mux_opts(): - import subprocess - +def inspect_ssh_mux_opts(control_path_dir="~/.ssh/"): """Inspect whether or not ssh supports multiplexing options""" + import subprocess + import os + + control_path = os.path.join(control_path_dir, "cdist.master-%l-%r@%h:%p") wanted_mux_opts = { - "ControlPath":"~/.ssh/master-%l-%r@%h:%p", - "ControlMaster":"auto", - "ControlPersist":"125", + "ControlPath": control_path, + "ControlMaster": "auto", + "ControlPersist": "125", } - # if checked key option is present then this assumes - # all options in value are present - check = { - "ControlMaster": ("ControlMaster", "ControlPath"), - "ControlPersist": ("ControlPersist",), - } - mux_opts = {} - for x in check: - try: - subprocess.check_output("ssh -o {}".format(x), - stderr=subprocess.STDOUT, shell=True) - except subprocess.CalledProcessError as e: - foo = e.output.decode().lower() - if not "bad configuration option" in foo: - for o in check[x]: - mux_opts[o] = wanted_mux_opts[o] - foo = [" -o {}={}".format(x, mux_opts[x]) for x in mux_opts] - return " ".join(foo) + mux_opts = " ".join([" -o {}={}".format(x, + wanted_mux_opts[x]) for x in wanted_mux_opts]) + try: + subprocess.check_output("ssh {}".format(mux_opts), + stderr=subprocess.STDOUT, shell=True) + except subprocess.CalledProcessError as e: + subproc_output = e.output.decode().lower() + if "bad configuration option" in subproc_output: + return "" + return mux_opts def commandline(): """Parse command line""" @@ -56,6 +50,9 @@ def commandline(): import cdist.banner import cdist.config import cdist.shell + import tempfile + import shutil + import os # Construct parser others can reuse parser = {} @@ -83,9 +80,18 @@ def commandline(): # Config # inspect multiplexing options for default remote copy/exec scp/ssh - MUX_OPTS = inspect_ssh_mux_opts() - cdist.REMOTE_EXEC += MUX_OPTS - cdist.REMOTE_COPY += MUX_OPTS + # but not if env vars are present + has_env_remote_exec = "CDIST_REMOTE_EXEC" in os.environ + has_env_remote_copy = "CDIST_REMOTE_COPY" in os.environ + if not has_env_remote_exec or not has_env_remote_copy: + control_path_dir = tempfile.mkdtemp(prefix="cdist.control.path") + import atexit + atexit.register(lambda: shutil.rmtree(control_path_dir)) + MUX_OPTS = inspect_ssh_mux_opts(control_path_dir) + if not has_env_remote_exec: + cdist.REMOTE_EXEC += MUX_OPTS + if not has_env_remote_copy: + cdist.REMOTE_COPY += MUX_OPTS parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) From d329db05e117a2e2ea755c8827aa75e8b3eb2891 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 18 Mar 2016 23:52:24 +0100 Subject: [PATCH 0075/1332] Apply CDIST_REMOTE_EXEC/COPY env vars. --- scripts/cdist | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/cdist b/scripts/cdist index f5629641..33105061 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -92,6 +92,10 @@ def commandline(): cdist.REMOTE_EXEC += MUX_OPTS if not has_env_remote_copy: cdist.REMOTE_COPY += MUX_OPTS + if has_env_remote_exec: + cdist.REMOTE_EXEC = os.environ['CDIST_REMOTE_EXEC'] + if has_env_remote_copy: + cdist.REMOTE_COPY = os.environ['CDIST_REMOTE_COPY'] parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) From 4318d72524f4569addf7bd06fd85e74dc5b054df Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 22 Mar 2016 08:41:51 +0100 Subject: [PATCH 0076/1332] No subprocess if user enters remote_exec/copy. --- scripts/cdist | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 33105061..265d73f0 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -79,24 +79,6 @@ def commandline(): parser['banner'].set_defaults(func=cdist.banner.banner) # Config - # inspect multiplexing options for default remote copy/exec scp/ssh - # but not if env vars are present - has_env_remote_exec = "CDIST_REMOTE_EXEC" in os.environ - has_env_remote_copy = "CDIST_REMOTE_COPY" in os.environ - if not has_env_remote_exec or not has_env_remote_copy: - control_path_dir = tempfile.mkdtemp(prefix="cdist.control.path") - import atexit - atexit.register(lambda: shutil.rmtree(control_path_dir)) - MUX_OPTS = inspect_ssh_mux_opts(control_path_dir) - if not has_env_remote_exec: - cdist.REMOTE_EXEC += MUX_OPTS - if not has_env_remote_copy: - cdist.REMOTE_COPY += MUX_OPTS - if has_env_remote_exec: - cdist.REMOTE_EXEC = os.environ['CDIST_REMOTE_EXEC'] - if has_env_remote_copy: - cdist.REMOTE_COPY = os.environ['CDIST_REMOTE_COPY'] - parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) parser['config'].add_argument('host', nargs='+', @@ -117,14 +99,17 @@ def commandline(): parser['config'].add_argument('-s', '--sequential', help='Operate on multiple hosts sequentially (default)', action='store_false', dest='parallel') + # remote-copy and remote-exec defaults are environment variables + # if set; if not then None - these will be futher handled after + # parsing to determine implementation default parser['config'].add_argument('--remote-copy', help='Command to use for remote copy (should behave like scp)', action='store', dest='remote_copy', - default=cdist.REMOTE_COPY) + default=os.environ.get('CDIST_REMOTE_COPY')) parser['config'].add_argument('--remote-exec', help='Command to use for remote execution (should behave like ssh)', action='store', dest='remote_exec', - default=cdist.REMOTE_EXEC) + default=os.environ.get('CDIST_REMOTE_EXEC')) parser['config'].set_defaults(func=cdist.config.Config.commandline) # Shell @@ -145,6 +130,21 @@ def commandline(): logging.root.setLevel(logging.INFO) if args.debug: logging.root.setLevel(logging.DEBUG) + args_dict = vars(args) + # if command with remote_copy and remote_exec params + if 'remote_copy' in args_dict and 'remote_exec' in args_dict: + # if remote-exec and/or remote-copy args are None then user + # didn't specify command line options nor env vars: + # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC + if args_dict['remote_copy'] is None or args_dict['remote_exec'] is None: + control_path_dir = tempfile.mkdtemp(prefix="cdist.control.path") + import atexit + atexit.register(lambda: shutil.rmtree(control_path_dir)) + mux_opts = inspect_ssh_mux_opts(control_path_dir) + if args_dict['remote_exec'] is None: + args.remote_exec = cdist.REMOTE_EXEC + mux_opts + if args_dict['remote_copy'] is None: + args.remote_copy = cdist.REMOTE_COPY + mux_opts log.debug(args) log.info("version %s" % cdist.VERSION) From 017990467588ec81732d57c10607ed5403e1a986 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 22 Mar 2016 11:01:19 +0100 Subject: [PATCH 0077/1332] bugfix for newer zypper (SLES12SP1) releases, different column numbers in output --- cdist/conf/type/__zypper_service/explorer/service_uri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri index bcad4ec8..d57d2aa8 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_uri +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -27,4 +27,4 @@ else fi # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 7) -echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\<$uri\>" | cut -d'|' -f 7 ) +echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\<$uri\>" | awk '{print $NF}') From b749a4b88a982c347a212d95301e3b08e25a5126 Mon Sep 17 00:00:00 2001 From: Pierre Date: Wed, 23 Mar 2016 15:47:31 +0100 Subject: [PATCH 0078/1332] consul changes --- cdist/conf/type/__consul/files/versions/0.4.1/source | 2 +- cdist/conf/type/__consul/files/versions/0.5.0/source | 2 +- cdist/conf/type/__consul/files/versions/0.5.1/source | 2 +- cdist/conf/type/__consul/files/versions/0.6.4/cksum | 1 + cdist/conf/type/__consul/files/versions/0.6.4/source | 1 + cdist/conf/type/__consul/parameter/default/version | 2 +- 6 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 cdist/conf/type/__consul/files/versions/0.6.4/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.6.4/source diff --git a/cdist/conf/type/__consul/files/versions/0.4.1/source b/cdist/conf/type/__consul/files/versions/0.4.1/source index 7fb949c8..b1e9908d 100644 --- a/cdist/conf/type/__consul/files/versions/0.4.1/source +++ b/cdist/conf/type/__consul/files/versions/0.4.1/source @@ -1 +1 @@ -https://releases.hashicorp.com/consul/0.4.1/consul_0.4.1_linux_amd64.zip +https://dl.bintray.com/mitchellh/consul/0.4.1_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.5.0/source b/cdist/conf/type/__consul/files/versions/0.5.0/source index dc1c33c4..00a209a5 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.0/source +++ b/cdist/conf/type/__consul/files/versions/0.5.0/source @@ -1 +1 @@ -https://releases.hashicorp.com/consul/0.5.0/consul_0.5.0_linux_amd64.zip +https://dl.bintray.com/mitchellh/consul/0.5.0_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.5.1/source b/cdist/conf/type/__consul/files/versions/0.5.1/source index a47eb69c..f02a1103 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.1/source +++ b/cdist/conf/type/__consul/files/versions/0.5.1/source @@ -1 +1 @@ -https://releases.hashicorp.com/consul/0.5.1/consul_0.5.1_linux_amd64.zip +https://dl.bintray.com/mitchellh/consul/0.5.1_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.6.4/cksum b/cdist/conf/type/__consul/files/versions/0.6.4/cksum new file mode 100644 index 00000000..1124b7aa --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.4/cksum @@ -0,0 +1 @@ +3832641574 23002736 consul diff --git a/cdist/conf/type/__consul/files/versions/0.6.4/source b/cdist/conf/type/__consul/files/versions/0.6.4/source new file mode 100644 index 00000000..96879b8d --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.6.4/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/0.6.4/consul_0.6.4_linux_amd64.zip diff --git a/cdist/conf/type/__consul/parameter/default/version b/cdist/conf/type/__consul/parameter/default/version index 8f0916f7..d2b13eb6 100644 --- a/cdist/conf/type/__consul/parameter/default/version +++ b/cdist/conf/type/__consul/parameter/default/version @@ -1 +1 @@ -0.5.0 +0.6.4 From 14f3ee403aef85c8a31a1fef616aafba9f52cacf Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 23 Mar 2016 16:34:57 +0100 Subject: [PATCH 0079/1332] fix fo __start_on_boot for ALL systemd distros --- cdist/conf/explorer/init | 24 ++++ .../conf/type/__start_on_boot/explorer/state | 78 ++++++----- .../conf/type/__start_on_boot/gencode-remote | 131 ++++++++++-------- 3 files changed, 135 insertions(+), 98 deletions(-) create mode 100755 cdist/conf/explorer/init mode change 100755 => 100644 cdist/conf/type/__start_on_boot/explorer/state mode change 100755 => 100644 cdist/conf/type/__start_on_boot/gencode-remote diff --git a/cdist/conf/explorer/init b/cdist/conf/explorer/init new file mode 100755 index 00000000..3777b431 --- /dev/null +++ b/cdist/conf/explorer/init @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2016 Daniel Heule (hda at sfs.biz) +# +# 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 . +# +# +# Check whether the given name will be started on boot or not +# + +ps -o comm= --pid 1 diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state old mode 100755 new mode 100644 index 1906033c..1cad6602 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -24,47 +24,51 @@ os=$("$__explorer/os") runlevel=$("$__explorer/runlevel") +init=$("$__explorer/init") target_runlevel="$(cat "$__object/parameter/target_runlevel")" name="$__object_id" -case "$os" in - archlinux) - state=$(systemctl is-enabled "$name" >/dev/null 2>&1 \ - && echo present \ - || echo absent) - ;; +if [ "$init" == 'systemd' ]; then + # this handles ALL linux distros with systemd + # e.g. archlinux, gentoo, new RHEL and SLES versions + state=$(systemctl is-enabled "$name" >/dev/null 2>&1 \ + && echo present \ + || echo absent) - debian|openwrt) - state="present" - [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" - ;; - ubuntu) - state="absent" - [ -f "/etc/rc$runlevel.d/S"??"$name" ] && state="present" - [ -f "/etc/init/${name}.conf" ] && state="present" - ;; +else + case "$os" in + debian|openwrt) + state="present" + [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" + ;; + ubuntu) + state="absent" + [ -f "/etc/rc$runlevel.d/S"??"$name" ] && state="present" + [ -f "/etc/init/${name}.conf" ] && state="present" + ;; - amazon|centos|fedora|owl|redhat) - state=$(chkconfig --level "$runlevel" "$name" || echo absent) - [ "$state" ] || state="present" - ;; - suse) - # check for target if set, usable for boot. services in runlevel B - if [ "$target_runlevel" != 'default' ]; then - runlevel="$target_runlevel" - fi - # suses chkconfig has the same name, but works different ... - state=$(chkconfig --check "$name" "$runlevel" || echo absent) - [ "$state" ] || state="present" - ;; - gentoo) - state="present" - [ -f "/etc/runlevels/${target_runlevel}/${name}" ] || state="absent" - ;; - *) - echo "Unsupported os: $os" >&2 - exit 1 - ;; -esac + amazon|centos|fedora|owl|redhat) + state=$(chkconfig --level "$runlevel" "$name" || echo absent) + [ "$state" ] || state="present" + ;; + suse) + # check for target if set, usable for boot. services in runlevel B + if [ "$target_runlevel" != 'default' ]; then + runlevel="$target_runlevel" + fi + # suses chkconfig has the same name, but works different ... + state=$(chkconfig --check "$name" "$runlevel" || echo absent) + [ "$state" ] || state="present" + ;; + gentoo) + state="present" + [ -f "/etc/runlevels/${target_runlevel}/${name}" ] || state="absent" + ;; + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; + esac +fi echo $state diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote old mode 100755 new mode 100644 index 611e59fe..c8488e3a --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -1,7 +1,7 @@ #!/bin/sh # # 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) -# 2013 Daniel Heule (hda at sfs.biz) +# 2016 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -22,6 +22,7 @@ state_should="$(cat "$__object/parameter/state")" state_is=$(cat "$__object/explorer/state") +init=$(cat "$__global/explorer/init") target_runlevel="$(cat "$__object/parameter/target_runlevel")" # Short circuit if nothing is to be done @@ -33,78 +34,86 @@ name="$__object_id" case "$state_should" in present) - case "$os" in - archlinux) - echo "systemctl enable \"$name\"" - ;; - debian) - case "$os_version" in - [1-7]*) - echo "update-rc.d \"$name\" defaults >/dev/null" - ;; - 8*) - echo "systemctl enable \"$name\"" - ;; - *) - echo "Unsupported version $os_version of $os" >&2 - exit 1 - ;; - esac - ;; + if [ "$init" == 'systemd' ]; then + # this handles ALL linux distros with systemd + # e.g. archlinux, gentoo in some cases, new RHEL and SLES versions + echo "systemctl -q enable \"$name\"" + else + case "$os" in + debian) + case "$os_version" in + [1-7]*) + echo "update-rc.d \"$name\" defaults >/dev/null" + ;; + 8*) + echo "systemctl enable \"$name\"" + ;; + *) + echo "Unsupported version $os_version of $os" >&2 + exit 1 + ;; + esac + ;; - gentoo) - echo rc-update add \"$name\" \"$target_runlevel\" - ;; + gentoo) + echo rc-update add \"$name\" \"$target_runlevel\" + ;; - amazon|centos|fedora|owl|redhat|suse) - echo chkconfig \"$name\" on - ;; + amazon|centos|fedora|owl|redhat|suse) + echo chkconfig \"$name\" on + echo "Unsupported version $os_version of $os" >&2 + exit 1 + ;; - openwrt) - # 'enable' can be successful and still return a non-zero exit - # code, deal with it by checking for success ourselves in that - # case (the || ... part). - echo "/etc/init.d/\"$name\" enable || [ -f /etc/rc.d/S??\"$name\" ]" - ;; + openwrt) + # 'enable' can be successful and still return a non-zero exit + # code, deal with it by checking for success ourselves in that + # case (the || ... part). + echo "/etc/init.d/\"$name\" enable || [ -f /etc/rc.d/S??\"$name\" ]" + ;; - ubuntu) - echo "update-rc.d \"$name\" defaults >/dev/null" - ;; + ubuntu) + echo "update-rc.d \"$name\" defaults >/dev/null" + ;; - *) - echo "Unsupported os: $os" >&2 - exit 1 - ;; - esac + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; + esac + fi ;; absent) - case "$os" in - archlinux) - echo "systemctl disable \"$name\"" - ;; - debian|ubuntu) - echo update-rc.d -f \"$name\" remove - ;; + if [ "$init" == 'systemd' ]; then + # this handles ALL linux distros with systemd + # e.g. archlinux, gentoo in some cases, new RHEL and SLES versions + echo "systemctl -q disable \"$name\"" - gentoo) - echo rc-update del \"$name\" \"$target_runlevel\" - ;; + else + case "$os" in + debian|ubuntu) + echo update-rc.d -f \"$name\" remove + ;; - centos|fedora|owl|redhat|suse) - echo chkconfig \"$name\" off - ;; + gentoo) + echo rc-update del \"$name\" \"$target_runlevel\" + ;; - openwrt) - echo "\"/etc/init.d/$name\" disable" - ;; + centos|fedora|owl|redhat|suse) + echo chkconfig \"$name\" off + ;; - *) - echo "Unsupported os: $os" >&2 - exit 1 - ;; - esac - + openwrt) + echo "\"/etc/init.d/$name\" disable" + ;; + + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; + esac + fi ;; *) From d3a0bd20c0b14cb129f2bc7f0e55d2069bc5a5d3 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 24 Mar 2016 10:58:14 +0100 Subject: [PATCH 0080/1332] replace egrep with awk functions --- cdist/conf/type/__zypper_service/explorer/service_uri | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri index d57d2aa8..6eee47fb 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_uri +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -25,6 +25,4 @@ if [ -f "$__object/parameter/uri" ]; then else uri="/$__object_id" fi -# simpler command which works only on SLES11 SP3 or newer: -# echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 7) -echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\<$uri\>" | awk '{print $NF}') +echo $(zypper ls -u | awk 'BEGIN { FS = "[ ]+\\|[ ]+" } ; $4 == "Yes" && $NF == "'$uri'" {print $NF}') From 2c49e04c9847fe55ec4b64fe815ce0fe36e79766 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 24 Mar 2016 11:22:09 +0100 Subject: [PATCH 0081/1332] Updated the exlorer for more systems changed the ps syntax, so it should work on freebsd to added a case so it could easy implemented for other os to --- cdist/conf/explorer/init | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cdist/conf/explorer/init b/cdist/conf/explorer/init index 3777b431..a9cdd0d3 100755 --- a/cdist/conf/explorer/init +++ b/cdist/conf/explorer/init @@ -18,7 +18,19 @@ # along with cdist. If not, see . # # -# Check whether the given name will be started on boot or not +# Returns the process name of pid 1 ( normaly the init system ) +# for example at linux this value is "init" or "systemd" in most cases # -ps -o comm= --pid 1 +uname_s="$(uname -s)" + +case "$uname_s" in + Linux|FreeBSD) + ps -o comm= -p 1 || true + exit 0 + ;; + *) + echo "init exlorer needs to be implemented for $os" >&2 + exit 1 + ;; +esac From 9c6d7dbd892c30c11ed8c03f74a24d688d47cad4 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 24 Mar 2016 11:29:13 +0100 Subject: [PATCH 0082/1332] modified the unknown case ... --- cdist/conf/explorer/init | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cdist/conf/explorer/init b/cdist/conf/explorer/init index a9cdd0d3..fd54d0c0 100755 --- a/cdist/conf/explorer/init +++ b/cdist/conf/explorer/init @@ -27,10 +27,8 @@ uname_s="$(uname -s)" case "$uname_s" in Linux|FreeBSD) ps -o comm= -p 1 || true - exit 0 ;; *) - echo "init exlorer needs to be implemented for $os" >&2 - exit 1 + echo "unknown" ;; esac From f7de217129de14e3857fd19eaa1cc1402312966a Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 25 Mar 2016 16:39:48 +0100 Subject: [PATCH 0083/1332] modified the unknown case to empty... --- cdist/conf/explorer/init | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/explorer/init b/cdist/conf/explorer/init index fd54d0c0..2693a0d3 100755 --- a/cdist/conf/explorer/init +++ b/cdist/conf/explorer/init @@ -29,6 +29,7 @@ case "$uname_s" in ps -o comm= -p 1 || true ;; *) - echo "unknown" + # return a empty string as unknown value + echo "" ;; esac From f6a5f56098fe4b6b8c113f2ef74ae0906f57d6f2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 26 Mar 2016 16:40:41 +0100 Subject: [PATCH 0084/1332] Use the same dir for ssh mux socket and Local base_path. --- scripts/cdist | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/cdist b/scripts/cdist index 265d73f0..9fa3ddb8 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -133,11 +133,16 @@ def commandline(): args_dict = vars(args) # if command with remote_copy and remote_exec params if 'remote_copy' in args_dict and 'remote_exec' in args_dict: + # if out_path is not set then create temp dir here so + # Local uses it for base_path and ssh mux socket is + # created in it. + if args_dict['out_path'] is None: + args.out_path = tempfile.mkdtemp() # if remote-exec and/or remote-copy args are None then user # didn't specify command line options nor env vars: # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC if args_dict['remote_copy'] is None or args_dict['remote_exec'] is None: - control_path_dir = tempfile.mkdtemp(prefix="cdist.control.path") + control_path_dir = args.out_path import atexit atexit.register(lambda: shutil.rmtree(control_path_dir)) mux_opts = inspect_ssh_mux_opts(control_path_dir) From 0e2e90322b9e3eee18ec6f2fe824e73eaac7f663 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 27 Mar 2016 10:03:12 +0200 Subject: [PATCH 0085/1332] rmtree only if it is temp dir. If user specifies out_path then do not rmtree it. --- scripts/cdist | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 9fa3ddb8..fecf61d0 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -138,13 +138,19 @@ def commandline(): # created in it. if args_dict['out_path'] is None: args.out_path = tempfile.mkdtemp() + is_temp_dir = True + else: + is_temp_dir = False # if remote-exec and/or remote-copy args are None then user # didn't specify command line options nor env vars: # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC if args_dict['remote_copy'] is None or args_dict['remote_exec'] is None: control_path_dir = args.out_path - import atexit - atexit.register(lambda: shutil.rmtree(control_path_dir)) + # only rmtree if it is temp directory; + # if user specifies out_path do not remove it + if is_temp_dir: + import atexit + atexit.register(lambda: shutil.rmtree(control_path_dir)) mux_opts = inspect_ssh_mux_opts(control_path_dir) if args_dict['remote_exec'] is None: args.remote_exec = cdist.REMOTE_EXEC + mux_opts From 1dfd6671e7f6ce22c834fb38f8f110456f684924 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 18 Mar 2016 21:57:50 +0100 Subject: [PATCH 0086/1332] Fix #416: error for non-posix remote shell. Fix remote.py test errors. --- cdist/exec/remote.py | 27 ++++++++++++++++++++++----- cdist/test/exec/remote.py | 31 ++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 9b7d5d1c..c99cc77c 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -130,12 +130,29 @@ class Remote(object): # FIXME: replace this by -o SendEnv name -o SendEnv name ... to ssh? # can't pass environment to remote side, so prepend command with # variable declarations + + # cdist command prepended with variable assignments expects + # posix shell (bourne, bash) at the remote as user default shell. + # If remote user shell isn't poxis shell, but for e.g. csh/tcsh + # then these var assignments are not var assignments for this + # remote shell, it tries to execute it as a command and fails. + # So really do this by default: + # /bin/sh -c 'export ; command' + # so that constructed remote command isn't dependent on remote + # shell. Do this only if env is not None. env breaks this. + # Explicitly use /bin/sh, because var assignments assume poxis + # shell already. + # This leaves the posibility to write script that needs to be run + # remotely in e.g. csh and setting up CDIST_REMOTE_SHELL to e.g. + # /bin/csh will execute this script in the right way. if env: - remote_env = ["%s=%s" % item for item in env.items()] - cmd.extend(remote_env) - - cmd.extend(command) - + cmd.append("/bin/sh") + cmd.append("-c") + remote_env = [" export %s=%s;" % item for item in env.items()] + string_cmd = " ".join(remote_env) + " ".join(command) + cmd.append(string_cmd) + else: + cmd.extend(command) return self._run_command(cmd, env=env, return_output=return_output) def _run_command(self, command, env=None, return_output=False): diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 8e7d408a..7d61b85c 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -39,7 +39,7 @@ class RemoteTestCase(test.CdistTestCase): user = getpass.getuser() remote_exec = "ssh -o User=%s -q" % user remote_copy = "scp -o User=%s -q" % user - self.remote = remote.Remote(self.target_host, self.base_path, remote_exec, remote_copy) + self.remote = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) def tearDown(self): shutil.rmtree(self.temp_dir) @@ -125,7 +125,7 @@ class RemoteTestCase(test.CdistTestCase): os.chmod(remote_exec_path, 0o755) remote_exec = remote_exec_path remote_copy = "echo" - r = remote.Remote(self.target_host, self.base_path, remote_exec, remote_copy) + r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) self.assertEqual(r.run('/bin/true', return_output=True), "%s\n" % self.target_host) def test_run_script_target_host_in_env(self): @@ -135,8 +135,33 @@ class RemoteTestCase(test.CdistTestCase): os.chmod(remote_exec_path, 0o755) remote_exec = remote_exec_path remote_copy = "echo" - r = remote.Remote(self.target_host, self.base_path, remote_exec, remote_copy) + r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", "/bin/true"]) self.assertEqual(r.run_script(script, return_output=True), "%s\n" % self.target_host) + + def test_run_script_with_env_target_host_in_env(self): + handle, script = self.mkstemp(dir=self.temp_dir) + with os.fdopen(handle, "w") as fd: + fd.writelines(["#!/bin/sh\n", 'if [ "$__object" ]; then echo $__object; else echo no_env; fi\n']) + os.chmod(script, 0o755) + handle, remote_exec_path = self.mkstemp(dir=self.temp_dir) + with os.fdopen(handle, 'w') as fd: + fd.writelines(["#!/bin/sh\n", 'shift; cmd=$1; shift; $cmd "$@"\n']) + os.chmod(remote_exec_path, 0o755) + remote_exec = remote_exec_path + remote_copy = "echo" + r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) + output = r.run_script(script, return_output=True) + self.assertEqual(output, "no_env\n") + env = { + '__object': 'test_object', + } + output = r.run_script(script, env=env, return_output=True) + self.assertEqual(output, "test_object\n") + +if __name__ == '__main__': + import unittest + + unittest.main() From f55d00fe96dd7c1ab7dd1431784329ade9ac3da7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Mar 2016 12:43:59 +0200 Subject: [PATCH 0087/1332] checkbashisms --- .../conf/type/__firewalld_rule/explorer/rule | 1 + .../conf/type/__firewalld_rule/gencode-remote | 1 + .../conf/type/__iptables_apply/gencode-remote | 2 ++ cdist/conf/type/__iptables_apply/manifest | 1 + cdist/conf/type/__iptables_rule/manifest | 1 + .../type/__key_value/files/remote_script.sh | 2 ++ cdist/conf/type/__motd/gencode-remote | 2 ++ .../__package_zypper/explorer/pkg_version | 2 +- cdist/conf/type/__pacman_conf/manifest | 23 ++++++++++--------- .../type/__pacman_conf_integrate/manifest | 4 ++-- cdist/conf/type/__qemu_img/gencode-remote | 2 ++ cdist/conf/type/__qemu_img/manifest | 2 ++ .../conf/type/__start_on_boot/explorer/state | 2 +- .../conf/type/__start_on_boot/gencode-remote | 4 ++-- 14 files changed, 32 insertions(+), 17 deletions(-) diff --git a/cdist/conf/type/__firewalld_rule/explorer/rule b/cdist/conf/type/__firewalld_rule/explorer/rule index e9e1ebeb..5a0e0265 100644 --- a/cdist/conf/type/__firewalld_rule/explorer/rule +++ b/cdist/conf/type/__firewalld_rule/explorer/rule @@ -1,3 +1,4 @@ +#!/bin/sh # # 2015 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__firewalld_rule/gencode-remote b/cdist/conf/type/__firewalld_rule/gencode-remote index e184f5b3..8f1ba28a 100644 --- a/cdist/conf/type/__firewalld_rule/gencode-remote +++ b/cdist/conf/type/__firewalld_rule/gencode-remote @@ -1,3 +1,4 @@ +#!/bin/sh # # 2015 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__iptables_apply/gencode-remote b/cdist/conf/type/__iptables_apply/gencode-remote index 9cdf28cf..c15d4d7f 100644 --- a/cdist/conf/type/__iptables_apply/gencode-remote +++ b/cdist/conf/type/__iptables_apply/gencode-remote @@ -1,3 +1,5 @@ +#!/bin/sh + if grep -q "^__file/etc/iptables.d/" "$__messages_in"; then echo /etc/init.d/iptables restart fi diff --git a/cdist/conf/type/__iptables_apply/manifest b/cdist/conf/type/__iptables_apply/manifest index a22901ba..3bb2d976 100644 --- a/cdist/conf/type/__iptables_apply/manifest +++ b/cdist/conf/type/__iptables_apply/manifest @@ -1,3 +1,4 @@ +#!/bin/sh # # 2013 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__iptables_rule/manifest b/cdist/conf/type/__iptables_rule/manifest index f02ab18b..13cec523 100644 --- a/cdist/conf/type/__iptables_rule/manifest +++ b/cdist/conf/type/__iptables_rule/manifest @@ -1,3 +1,4 @@ +#!/bin/sh # # 2013 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__key_value/files/remote_script.sh b/cdist/conf/type/__key_value/files/remote_script.sh index 282ba531..52b3f2de 100644 --- a/cdist/conf/type/__key_value/files/remote_script.sh +++ b/cdist/conf/type/__key_value/files/remote_script.sh @@ -1,3 +1,5 @@ +#!/bin/sh + export key="$(cat "$__object/parameter/key" 2>/dev/null \ || echo "$__object_id")" export state="$(cat "$__object/parameter/state")" diff --git a/cdist/conf/type/__motd/gencode-remote b/cdist/conf/type/__motd/gencode-remote index 2aa84902..bfd13b5e 100755 --- a/cdist/conf/type/__motd/gencode-remote +++ b/cdist/conf/type/__motd/gencode-remote @@ -1,3 +1,5 @@ +#!/bin/sh +# # 2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. diff --git a/cdist/conf/type/__package_zypper/explorer/pkg_version b/cdist/conf/type/__package_zypper/explorer/pkg_version index 7f203067..83bf6dab 100644 --- a/cdist/conf/type/__package_zypper/explorer/pkg_version +++ b/cdist/conf/type/__package_zypper/explorer/pkg_version @@ -42,7 +42,7 @@ case "$ptype" in zypper search --match-exact --installed-only --type "$ptype" "$name" | grep -E '^i' | cut -d " " -f 3 || true ;; *) - echo "unknown ptype in __package_zypper explorer" &>2 + echo "unknown ptype in __package_zypper explorer" >&2 exit 1 ;; esac diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest index 19e232a7..903be087 100644 --- a/cdist/conf/type/__pacman_conf/manifest +++ b/cdist/conf/type/__pacman_conf/manifest @@ -42,11 +42,12 @@ contains_element() { MATCH=0 target=$1 - keys="${@:2}" + # keys="${@:2}" + shift - - for key in ${keys}; do - if [ "${key}" == "${target}" ]; then + # for key in ${keys}; do + for key in "$@"; do + if [ "${key}" = "${target}" ]; then MATCH=1 return 0 fi @@ -58,14 +59,14 @@ if [ "${file}" ]; then __file "${sec_path}/plain_file_${file}"\ --state exists --mode 666 - if [ "${state}" == "present" ]; then + if [ "${state}" = "present" ]; then require="__file/${sec_path}/plain_file_${file}" __key_value ${file}_${key}\ --file ${sec_path}/plain_file_${file} --key ${key} --value ${value} --delimiter ' = ' exit 0 - elif [ "${state}" == "absent" ]; then + elif [ "${state}" = "absent" ]; then require="__file/${sec_path}/plain_file_${file}" __key_value ${file}_${key}\ --state absent exit 0 @@ -76,7 +77,7 @@ if [ "${file}" ]; then fi fi -if [ "${section}" == "options" ]; then +if [ "${section}" = "options" ]; then __file "${sec_path}/${section}"\ --state exists --mode 666 --source - << eof @@ -87,10 +88,10 @@ eof contains_element "${key}" "${boolean_option_keys}" if [ "${MATCH}" -eq 1 ]; then - if [ "${value}" == "on" ]; then + if [ "${value}" = "on" ]; then require="__file/${sec_path}/${section}" __line ${key}_${value}\ --file ${sec_path}/${section} --line ${key} - elif [ "${value}" == "off" ]; then + elif [ "${value}" = "off" ]; then require="__file/${sec_path}/${section}" __line ${key}_${value}\ --file ${sec_path}/${section} --line ${key} --state absent fi @@ -111,7 +112,7 @@ else --state exists --mode 666 --source - << eof [${section}] eof - if [ "${state}" == "present" ]; then + if [ "${state}" = "present" ]; then #check if key is valid contains_element "${key}" "${allowed_repo_keys}" @@ -122,7 +123,7 @@ eof require="__file/${sec_path}/repo_${section}" __key_value ${section}_${key}\ --file ${sec_path}/repo_${section} --key ${key} --value ${value} --delimiter ' = ' - elif [ "${state}" == "absent" ]; then + elif [ "${state}" = "absent" ]; then require="__file/${sec_path}/repo_${section}" __key_value ${section}_${key}\ --state absent diff --git a/cdist/conf/type/__pacman_conf_integrate/manifest b/cdist/conf/type/__pacman_conf_integrate/manifest index 5f398c19..1d02f3b3 100644 --- a/cdist/conf/type/__pacman_conf_integrate/manifest +++ b/cdist/conf/type/__pacman_conf_integrate/manifest @@ -22,7 +22,7 @@ state=$(cat $__object/parameter/state 2>/dev/null) path="/etc/" -if [ "${state}" == "present" ]; then +if [ "${state}" = "present" ]; then __file /etc/pacman.conf\ --owner root --group root --mode 644 --source $__type/files/pacman.conf.cdist @@ -35,7 +35,7 @@ if [ "${state}" == "present" ]; then __file /etc/pacman.d/plain_file_empty_placeholder\ --owner root --group root --mode 644 -elif [ "${state}" == "absent" ]; then +elif [ "${state}" = "absent" ]; then __file /etc/pacman.conf\ --owner root --group root --mode 644 --source $__type/files/pacman.conf.pacman diff --git a/cdist/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote index 6e4bb4d0..bffedd26 100644 --- a/cdist/conf/type/__qemu_img/gencode-remote +++ b/cdist/conf/type/__qemu_img/gencode-remote @@ -1,3 +1,5 @@ +#!/bin/sh +# ################################################################################ # State: absent is handled by manifest - we need only to do stuff if image is # not existing and state != absent diff --git a/cdist/conf/type/__qemu_img/manifest b/cdist/conf/type/__qemu_img/manifest index bb2c9366..e0ff6e03 100644 --- a/cdist/conf/type/__qemu_img/manifest +++ b/cdist/conf/type/__qemu_img/manifest @@ -1,3 +1,5 @@ +#!/bin/sh +# ################################################################################ # Default settings # diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 1cad6602..2f94a521 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -28,7 +28,7 @@ init=$("$__explorer/init") target_runlevel="$(cat "$__object/parameter/target_runlevel")" name="$__object_id" -if [ "$init" == 'systemd' ]; then +if [ "$init" = 'systemd' ]; then # this handles ALL linux distros with systemd # e.g. archlinux, gentoo, new RHEL and SLES versions state=$(systemctl is-enabled "$name" >/dev/null 2>&1 \ diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index c8488e3a..8d3678d3 100644 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -34,7 +34,7 @@ name="$__object_id" case "$state_should" in present) - if [ "$init" == 'systemd' ]; then + if [ "$init" = 'systemd' ]; then # this handles ALL linux distros with systemd # e.g. archlinux, gentoo in some cases, new RHEL and SLES versions echo "systemctl -q enable \"$name\"" @@ -85,7 +85,7 @@ case "$state_should" in ;; absent) - if [ "$init" == 'systemd' ]; then + if [ "$init" = 'systemd' ]; then # this handles ALL linux distros with systemd # e.g. archlinux, gentoo in some cases, new RHEL and SLES versions echo "systemctl -q disable \"$name\"" From ee3e9a56f12016be5d8e6eb9914c897d38ab9529 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 31 Mar 2016 12:34:59 +0200 Subject: [PATCH 0088/1332] Remove commented old code. --- cdist/conf/type/__pacman_conf/manifest | 2 -- 1 file changed, 2 deletions(-) diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest index 903be087..b9679577 100644 --- a/cdist/conf/type/__pacman_conf/manifest +++ b/cdist/conf/type/__pacman_conf/manifest @@ -42,10 +42,8 @@ contains_element() { MATCH=0 target=$1 - # keys="${@:2}" shift - # for key in ${keys}; do for key in "$@"; do if [ "${key}" = "${target}" ]; then MATCH=1 From de74b857478056cd8e7acb6c34d6862bffeb6cde Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 31 Mar 2016 13:21:35 +0200 Subject: [PATCH 0089/1332] Update changelog. --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index fa3e6f7d..bd0bc324 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,9 @@ Changelog --------- next: + * Types: Remove bashisms in scripts (Darko Poljak) + * Core: Fix bug in remote command with environment (Darko Poljak) + * Core: Fix bug in local code execution (Darko Poljak) * Documentation: Fix spelling in manual pages (Dmitry Bogatov) * New type: __pacman_conf: Manage pacman.conf (Dominique Roux) * New type: __pacman_conf_integrate: cdist compatible pacman.conf (Dominique Roux) From 8191ea91e1f6e7ff82a5fa2d9fb6a063dd5dcd5a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 1 Apr 2016 10:42:32 +0200 Subject: [PATCH 0090/1332] Fix remote exec bug and bug with save_cache and ssh mux socket file. --- cdist/exec/remote.py | 5 ++--- cdist/test/exec/remote.py | 7 +++++++ scripts/cdist | 20 +++++--------------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index c99cc77c..77e2c8be 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -146,10 +146,9 @@ class Remote(object): # remotely in e.g. csh and setting up CDIST_REMOTE_SHELL to e.g. # /bin/csh will execute this script in the right way. if env: - cmd.append("/bin/sh") - cmd.append("-c") remote_env = [" export %s=%s;" % item for item in env.items()] - string_cmd = " ".join(remote_env) + " ".join(command) + string_cmd = ("/bin/sh -c '" + " ".join(remote_env) + + " ".join(command) + "'") cmd.append(string_cmd) else: cmd.extend(command) diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 7d61b85c..89e9dbc8 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -155,9 +155,16 @@ class RemoteTestCase(test.CdistTestCase): r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) output = r.run_script(script, return_output=True) self.assertEqual(output, "no_env\n") + + handle, remote_exec_path = self.mkstemp(dir=self.temp_dir) + with os.fdopen(handle, 'w') as fd: + fd.writelines(["#!/bin/sh\n", 'shift; cmd=$1; eval $cmd\n']) + os.chmod(remote_exec_path, 0o755) + remote_exec = remote_exec_path env = { '__object': 'test_object', } + r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) output = r.run_script(script, env=env, return_output=True) self.assertEqual(output, "test_object\n") diff --git a/scripts/cdist b/scripts/cdist index fecf61d0..8e22aacb 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -26,7 +26,8 @@ def inspect_ssh_mux_opts(control_path_dir="~/.ssh/"): import subprocess import os - control_path = os.path.join(control_path_dir, "cdist.master-%l-%r@%h:%p") + control_path = os.path.join(control_path_dir, + "cdist.socket.master-%l-%r@%h:%p") wanted_mux_opts = { "ControlPath": control_path, "ControlMaster": "auto", @@ -133,24 +134,13 @@ def commandline(): args_dict = vars(args) # if command with remote_copy and remote_exec params if 'remote_copy' in args_dict and 'remote_exec' in args_dict: - # if out_path is not set then create temp dir here so - # Local uses it for base_path and ssh mux socket is - # created in it. - if args_dict['out_path'] is None: - args.out_path = tempfile.mkdtemp() - is_temp_dir = True - else: - is_temp_dir = False # if remote-exec and/or remote-copy args are None then user # didn't specify command line options nor env vars: # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC if args_dict['remote_copy'] is None or args_dict['remote_exec'] is None: - control_path_dir = args.out_path - # only rmtree if it is temp directory; - # if user specifies out_path do not remove it - if is_temp_dir: - import atexit - atexit.register(lambda: shutil.rmtree(control_path_dir)) + control_path_dir = tempfile.mkdtemp() + import atexit + atexit.register(lambda: shutil.rmtree(control_path_dir)) mux_opts = inspect_ssh_mux_opts(control_path_dir) if args_dict['remote_exec'] is None: args.remote_exec = cdist.REMOTE_EXEC + mux_opts From 3062421cf59bf2e7bf4a98e42deb7c7588c76c0d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 2 Apr 2016 22:44:02 +0200 Subject: [PATCH 0091/1332] Fix bug with parallel hosts operation and specified output path. --- cdist/exec/local.py | 31 ++++++++++++------ .../conf/type/__cdist_test_type/gencode-local | 8 +++++ .../type/__cdist_test_type/gencode-remote | 1 + cdist/test/exec/local.py | 32 ++++++++++++------- docs/changelog | 1 + 5 files changed, 52 insertions(+), 21 deletions(-) create mode 100755 cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-local create mode 120000 cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-remote diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 0be803a9..c0554831 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -2,6 +2,7 @@ # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2011-2015 Nico Schottelius (nico-cdist at schottelius.org) +# 2016 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -51,9 +52,18 @@ class Local(object): # FIXME: stopped: create base that does not require moving later if base_path: - self.base_path = base_path + base_path_parent = base_path else: - self.base_path = tempfile.mkdtemp() + base_path_parent = tempfile.mkdtemp() + import atexit + atexit.register(lambda: shutil.rmtree(base_path_parent)) + self.hostdir = self._hostdir() + self.base_path = os.path.join(base_path_parent, self.hostdir) + + self._init_log() + self._init_permissions() + + self.mkdir(self.base_path) # FIXME: as well self._init_cache_dir(None) @@ -63,8 +73,6 @@ class Local(object): self._add_conf_dirs = add_conf_dirs - self._init_log() - self._init_permissions() self._init_paths() self._init_object_marker() self._init_conf_dirs() @@ -80,6 +88,13 @@ class Local(object): else: return None + def _hostdir(self): + if os.path.isabs(self.target_host): + hostdir = self.target_host[1:] + else: + hostdir = self.target_host + return hostdir + def _init_log(self): self.log = logging.getLogger(self.target_host) @@ -210,13 +225,9 @@ class Local(object): return self.run(command=command, env=env, return_output=return_output, message_prefix=message_prefix) - def save_cache(self): - if os.path.isabs(self.target_host): - hostdir = self.target_host[1:] - else: - hostdir = self.target_host - destination = os.path.join(self.cache_path, hostdir) + def save_cache(self): + destination = os.path.join(self.cache_path, self.hostdir) self.log.debug("Saving " + self.base_path + " to " + destination) try: diff --git a/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-local b/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-local new file mode 100755 index 00000000..771894fb --- /dev/null +++ b/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-local @@ -0,0 +1,8 @@ +#!/bin/sh + +echo "echo __target_host: $__target_host" +echo "echo __global: $__global" +echo "echo __type: $__type" +echo "echo __object: $__object" +echo "echo __object_id: $__object_id" +echo "echo __object_name: $__object_name" diff --git a/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-remote b/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-remote new file mode 120000 index 00000000..7b427cac --- /dev/null +++ b/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-remote @@ -0,0 +1 @@ +gencode-local \ No newline at end of file diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index 6cb0c605..6c201e91 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -2,6 +2,7 @@ # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2016 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -35,17 +36,21 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') conf_dir = op.join(fixtures, "conf") +bin_true = "/usr/bin/true" +bin_false = "/usr/bin/false" + class LocalTestCase(test.CdistTestCase): def setUp(self): target_host = 'localhost' self.temp_dir = self.mkdtemp() - self.out_path = self.temp_dir + self.out_parent_path = self.temp_dir + self.out_path = op.join(self.out_parent_path, target_host) self.local = local.Local( target_host=target_host, - out_path=self.out_path, + base_path=self.out_parent_path, exec_path=test.cdist_exec_path ) @@ -63,7 +68,7 @@ class LocalTestCase(test.CdistTestCase): self.assertEqual(self.local.conf_path, os.path.join(self.out_path, "conf")) def test_out_path(self): - self.assertEqual(self.local.out_path, self.out_path) + self.assertEqual(self.local.base_path, self.out_path) def test_bin_path(self): self.assertEqual(self.local.bin_path, os.path.join(self.out_path, "bin")) @@ -94,7 +99,7 @@ class LocalTestCase(test.CdistTestCase): link_test_local = local.Local( target_host='localhost', - out_path=self.out_path, + base_path=self.out_parent_path, exec_path=test.cdist_exec_path, ) @@ -111,7 +116,7 @@ class LocalTestCase(test.CdistTestCase): link_test_local = local.Local( target_host='localhost', - out_path=self.out_path, + base_path=self.out_parent_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir] ) @@ -131,7 +136,7 @@ class LocalTestCase(test.CdistTestCase): link_test_local = local.Local( target_host='localhost', - out_path=self.out_path, + base_path=self.out_parent_path, exec_path=test.cdist_exec_path, ) @@ -144,21 +149,21 @@ class LocalTestCase(test.CdistTestCase): ### other tests def test_run_success(self): - self.local.run(['/bin/true']) + self.local.run([bin_true]) def test_run_fail(self): - self.assertRaises(cdist.Error, self.local.run, ['/bin/false']) + self.assertRaises(cdist.Error, self.local.run, [bin_false]) def test_run_script_success(self): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", "/bin/true"]) + fd.writelines(["#!/bin/sh\n", bin_true]) self.local.run_script(script) def test_run_script_fail(self): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", "/bin/false"]) + fd.writelines(["#!/bin/sh\n", bin_false]) self.assertRaises(cdist.Error, self.local.run_script, script) def test_run_script_get_output(self): @@ -180,6 +185,11 @@ class LocalTestCase(test.CdistTestCase): def test_create_files_dirs(self): self.local.create_files_dirs() - self.assertTrue(os.path.isdir(self.local.out_path)) + self.assertTrue(os.path.isdir(self.local.base_path)) self.assertTrue(os.path.isdir(self.local.bin_path)) self.assertTrue(os.path.isdir(self.local.conf_path)) + +if __name__ == "__main__": + import unittest + + unittest.main() diff --git a/docs/changelog b/docs/changelog index b1acf329..8584eb95 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Core: Fix bug with parallel hosts operation when output path is specifed (Darko Poljak) * Core: Add CDIST_REMOTE_COPY/EXEC env variables and multiplexing options for default scp/ssh (Darko Poljak) * Types: Remove bashisms in scripts (Darko Poljak) * Core: Fix bug in remote command with environment (Darko Poljak) From e4cbb382abafd3891faef17c98bc9ed9259a5b28 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 5 Apr 2016 20:23:13 +0200 Subject: [PATCH 0092/1332] PATH resolution for true/false. --- cdist/test/exec/local.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index 6c201e91..12a0d47b 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -36,8 +36,8 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') conf_dir = op.join(fixtures, "conf") -bin_true = "/usr/bin/true" -bin_false = "/usr/bin/false" +bin_true = "true" +bin_false = "false" class LocalTestCase(test.CdistTestCase): From ac171ba21934093be08e369424478ae1c2a54e4b Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 6 Apr 2016 17:29:23 +0200 Subject: [PATCH 0093/1332] remove a copy paste artefact which is wrong there --- cdist/conf/type/__start_on_boot/gencode-remote | 2 -- 1 file changed, 2 deletions(-) diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index c8488e3a..bcba21be 100644 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -61,8 +61,6 @@ case "$state_should" in amazon|centos|fedora|owl|redhat|suse) echo chkconfig \"$name\" on - echo "Unsupported version $os_version of $os" >&2 - exit 1 ;; openwrt) From d313971e1a1e79bf9a76dbd537cb1bb5298af572 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 11 Apr 2016 19:21:11 +0200 Subject: [PATCH 0094/1332] Create __pyvenv type and modify __package_pip accordingly. --- cdist/conf/type/__package_pip/explorer/su | 27 +++++++ cdist/conf/type/__package_pip/explorer/sudo | 27 +++++++ cdist/conf/type/__package_pip/gencode-remote | 42 +++++++++- cdist/conf/type/__package_pip/man.text | 8 ++ .../type/__package_pip/parameter/optional | 1 + cdist/conf/type/__pyvenv/explorer/group | 5 ++ cdist/conf/type/__pyvenv/explorer/owner | 5 ++ cdist/conf/type/__pyvenv/explorer/state | 9 +++ cdist/conf/type/__pyvenv/gencode-remote | 68 +++++++++++++++++ cdist/conf/type/__pyvenv/man.text | 76 +++++++++++++++++++ cdist/conf/type/__pyvenv/manifest | 46 +++++++++++ .../type/__pyvenv/parameter/default/group | 1 + .../conf/type/__pyvenv/parameter/default/mode | 1 + .../type/__pyvenv/parameter/default/owner | 1 + .../type/__pyvenv/parameter/default/python | 1 + .../type/__pyvenv/parameter/default/state | 1 + .../__pyvenv/parameter/default/venvparams | 1 + cdist/conf/type/__pyvenv/parameter/optional | 6 ++ 18 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 cdist/conf/type/__package_pip/explorer/su create mode 100644 cdist/conf/type/__package_pip/explorer/sudo create mode 100755 cdist/conf/type/__pyvenv/explorer/group create mode 100755 cdist/conf/type/__pyvenv/explorer/owner create mode 100755 cdist/conf/type/__pyvenv/explorer/state create mode 100755 cdist/conf/type/__pyvenv/gencode-remote create mode 100755 cdist/conf/type/__pyvenv/man.text create mode 100755 cdist/conf/type/__pyvenv/manifest create mode 100755 cdist/conf/type/__pyvenv/parameter/default/group create mode 100755 cdist/conf/type/__pyvenv/parameter/default/mode create mode 100755 cdist/conf/type/__pyvenv/parameter/default/owner create mode 100644 cdist/conf/type/__pyvenv/parameter/default/python create mode 100755 cdist/conf/type/__pyvenv/parameter/default/state create mode 100644 cdist/conf/type/__pyvenv/parameter/default/venvparams create mode 100755 cdist/conf/type/__pyvenv/parameter/optional diff --git a/cdist/conf/type/__package_pip/explorer/su b/cdist/conf/type/__package_pip/explorer/su new file mode 100644 index 00000000..f355a1bc --- /dev/null +++ b/cdist/conf/type/__package_pip/explorer/su @@ -0,0 +1,27 @@ +#!/bin/sh +# +# 2016 Darko Poljak (darko.poljak 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 . +# + +which su > /dev/null 2>&1 +if [ $? -eq 0 ] +then + echo yes +else + echo no +fi diff --git a/cdist/conf/type/__package_pip/explorer/sudo b/cdist/conf/type/__package_pip/explorer/sudo new file mode 100644 index 00000000..7b702bc0 --- /dev/null +++ b/cdist/conf/type/__package_pip/explorer/sudo @@ -0,0 +1,27 @@ +#!/bin/sh +# +# 2016 Darko Poljak (darko.poljak 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 . +# + +which sudo > /dev/null 2>&1 +if [ $? -eq 0 ] +then + echo yes +else + echo no +fi diff --git a/cdist/conf/type/__package_pip/gencode-remote b/cdist/conf/type/__package_pip/gencode-remote index ba44927a..ccf30f1a 100644 --- a/cdist/conf/type/__package_pip/gencode-remote +++ b/cdist/conf/type/__package_pip/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2016 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -40,12 +41,49 @@ else pip="pip" fi +runasparam="$__object/parameter/runas" +if [ -f "$runasparam" ] +then + runas=$(cat "$runasparam") + has_sudo=$(cat "$__object/explorer/sudo") + if [ "$has_sudo" = "yes" ] + then + runas_cmd="sudo" + else + has_su=$(cat "$__object/explorer/su") + if [ "$has_su" = "yes" ] + then + runas_cmd="su" + else + runas_cmd="" + fi + fi +else + runas_cmd="" +fi + case "$state_should" in present) - echo $pip install -q "$name" + if [ "$runas_cmd" = "sudo" ] + then + echo sudo -H -u $runas $pip install -q "$name" + elif [ "$runas_cmd" = "su" ] + then + echo su $runas -c \"$pip install -q "$name"\" + else + echo $pip install -q "$name" + fi ;; absent) - echo $pip uninstall -q -y "$name" + if [ "$runas_cmd" = "sudo" ] + then + echo sudo -H -u $runas $pip uninstall -q -y "$name" + elif [ "$runas_cmd" = "su" ] + then + echo su $runas -c \"$pip uninstall -q -y "$name"\" + else + echo $pip uninstall -q -y "$name" + fi ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_pip/man.text b/cdist/conf/type/__package_pip/man.text index 5f619871..cb7c7e11 100644 --- a/cdist/conf/type/__package_pip/man.text +++ b/cdist/conf/type/__package_pip/man.text @@ -30,6 +30,11 @@ pip:: state:: Either "present" or "absent", defaults to "present" +runas:: + Run pip as specified user. By default it runs as root. + It uses sudo or su, whichever it founds first, respectively. + If no sudo nor su is present then pip is run by default. + EXAMPLES -------- @@ -40,6 +45,9 @@ __package_pip pyro --state present # Use pip in a virtualenv located at /root/shinken_virtualenv __package_pip pyro --state present --pip /root/shinken_virtualenv/bin/pip + +# Use pip in a virtualenv located at /foo/shinken_virtualenv as user foo +__package_pip pyro --state present --pip /foo/shinken_virtualenv/bin/pip --runas foo -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__package_pip/parameter/optional b/cdist/conf/type/__package_pip/parameter/optional index f32876f7..83265c8b 100644 --- a/cdist/conf/type/__package_pip/parameter/optional +++ b/cdist/conf/type/__package_pip/parameter/optional @@ -1,2 +1,3 @@ pip state +runas diff --git a/cdist/conf/type/__pyvenv/explorer/group b/cdist/conf/type/__pyvenv/explorer/group new file mode 100755 index 00000000..ff072c5e --- /dev/null +++ b/cdist/conf/type/__pyvenv/explorer/group @@ -0,0 +1,5 @@ +#!/bin/sh + +destination="/$__object_id" + +stat --print "%G" ${destination} 2>/dev/null || exit 0 diff --git a/cdist/conf/type/__pyvenv/explorer/owner b/cdist/conf/type/__pyvenv/explorer/owner new file mode 100755 index 00000000..b77e3c6e --- /dev/null +++ b/cdist/conf/type/__pyvenv/explorer/owner @@ -0,0 +1,5 @@ +#!/bin/sh + +destination="/$__object_id" + +stat --print "%U" ${destination} 2>/dev/null || exit 0 diff --git a/cdist/conf/type/__pyvenv/explorer/state b/cdist/conf/type/__pyvenv/explorer/state new file mode 100755 index 00000000..ffe3cbbd --- /dev/null +++ b/cdist/conf/type/__pyvenv/explorer/state @@ -0,0 +1,9 @@ +#!/bin/sh + +destination="/$__object_id" + +if [ -d "$destination" ]; then + echo present +else + echo absent +fi diff --git a/cdist/conf/type/__pyvenv/gencode-remote b/cdist/conf/type/__pyvenv/gencode-remote new file mode 100755 index 00000000..b0fa121d --- /dev/null +++ b/cdist/conf/type/__pyvenv/gencode-remote @@ -0,0 +1,68 @@ +#!/bin/sh +# +# 2016 Darko Poljak (darko.poljak 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 . +# +# + +state_is="$(cat "$__object/explorer/state")" +owner_is="$(cat "$__object/explorer/owner")" +group_is="$(cat "$__object/explorer/group")" + +state_should="$(cat "$__object/parameter/state")" + +destination="/$__object_id" + +owner="$(cat "$__object/parameter/owner")" +group="$(cat "$__object/parameter/group")" +mode="$(cat "$__object/parameter/mode")" +python="$(cat "$__object/parameter/python")" +if [ "$python" ] +then + python_opt="-p $python" +else + python_opt="" +fi +venvparams="$(cat "$__object/parameter/venvparams")" + +[ "$state_should" = "$state_is" -a \ + "$owner" = "$owner_is" -a \ + "$group" = "$group_is" -a \ + -n "$mode" ] && exit 0 + +case $state_should in + present) + + if [ "$state_should" != "$state_is" ]; then + echo virtualenv "$python_opt" $venvparams "$destination" + fi + if [ \( -n "$owner" -a "$owner_is" != "$owner" \) -o \ + \( -n "$group" -a "$group_is" != "$group" \) ]; then + echo chown -R "${owner}:${group}" "$destination" + fi + if [ -n "$mode" ]; then + echo chmod -R "$mode" "$destination" + fi + ;; + absent) + ;; + + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__pyvenv/man.text b/cdist/conf/type/__pyvenv/man.text new file mode 100755 index 00000000..2f9a6ea5 --- /dev/null +++ b/cdist/conf/type/__pyvenv/man.text @@ -0,0 +1,76 @@ +cdist-type__pyvenv(7) +================== +Darko Poljak + + +NAME +---- +cdist-type__pyvenv - Create or remove python virtualenv + + +DESCRIPTION +----------- +This cdist type allows you to create or remove python virtualenv. +It assumes pip and virtualenv are already installed. Concrete packages +or installation procedures depend on concrete OS and/or OS +version/distribution. +Ensure this in your init manifest as in the following example: +-------------------------------------------------------------------------------- +case "$__target_host" in + localhost) + __package python3-pip --state present + require="__package/python3-pip" __package_pip virtualenv --pip pip3 --state present + require="__package/python3-pip __package_pip/virtualenv" __pyvenv /home/darko/testenv --owner darko --group darko --mode 740 --state present + ;; +-------------------------------------------------------------------------------- + + +REQUIRED PARAMETERS +------------------- +None + +OPTIONAL PARAMETERS +------------------- +state:: + Either "present" or "absent", defaults to "present" + +group:: + Group to chgrp to. + +mode:: + Unix permissions, suitable for chmod. + +owner:: + User to chown to. + +python:: + Use specific python interpreter for creating virtualenv. + The default is the interpreter that virtualenv was installed with. + +venvparams:: + virtualenv specific parameters to pass to virtualenv invocation. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__pyvenv /home/services/djangoenv + +# Create python virtualenv for user foo using specific python interpreter. +__pyvenv /home/foo/fooenv --group foo --user foo --python python2.6 + +# Create python virtualenv with specific parameters. +__pyvenv /home/services/djangoenv --venvparams "--relocatable --system-site-packages" +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2016 Darko Poljak. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__pyvenv/manifest b/cdist/conf/type/__pyvenv/manifest new file mode 100755 index 00000000..bd2b76e9 --- /dev/null +++ b/cdist/conf/type/__pyvenv/manifest @@ -0,0 +1,46 @@ +#!/bin/sh +# +# 2016 Darko Poljak (darko.poljak 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 . +# + +# It assumes pip and virtualenv are already installed. Concrete packages +# or installation procedures depend on concrete OS and/or OS +# version/distribution. + +state_should="$(cat "$__object/parameter/state")" +owner="$(cat "$__object/parameter/owner")" +group="$(cat "$__object/parameter/group")" +mode="$(cat "$__object/parameter/mode")" + +case "$state_should" in + present) + : + ;; + + absent) + __directory "$__object_id" --state absent \ + --owner "$owner" \ + --group "$group" \ + --mode "$mode" + ;; + + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__pyvenv/parameter/default/group b/cdist/conf/type/__pyvenv/parameter/default/group new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__pyvenv/parameter/default/group @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__pyvenv/parameter/default/mode b/cdist/conf/type/__pyvenv/parameter/default/mode new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__pyvenv/parameter/default/mode @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__pyvenv/parameter/default/owner b/cdist/conf/type/__pyvenv/parameter/default/owner new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__pyvenv/parameter/default/owner @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__pyvenv/parameter/default/python b/cdist/conf/type/__pyvenv/parameter/default/python new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__pyvenv/parameter/default/python @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__pyvenv/parameter/default/state b/cdist/conf/type/__pyvenv/parameter/default/state new file mode 100755 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__pyvenv/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__pyvenv/parameter/default/venvparams b/cdist/conf/type/__pyvenv/parameter/default/venvparams new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__pyvenv/parameter/default/venvparams @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__pyvenv/parameter/optional b/cdist/conf/type/__pyvenv/parameter/optional new file mode 100755 index 00000000..6b3fda2e --- /dev/null +++ b/cdist/conf/type/__pyvenv/parameter/optional @@ -0,0 +1,6 @@ +state +group +owner +mode +python +venvparams From 2410b30b40a5d73c35a03401a58fd10e0bf0255b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 11 Apr 2016 19:30:45 +0200 Subject: [PATCH 0095/1332] Update changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index b1acf329..5ec8edea 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,8 @@ Changelog --------- next: + * Type __package_pip: Add support for running as specified user (useful for pip from virtualenv (Darko Poljak) + * New type: __pyvenv: Manage python virtualenv (Darko Poljak) * Core: Add CDIST_REMOTE_COPY/EXEC env variables and multiplexing options for default scp/ssh (Darko Poljak) * Types: Remove bashisms in scripts (Darko Poljak) * Core: Fix bug in remote command with environment (Darko Poljak) From 1882040a259cff2cf855e7fa8ebbd32fb4c56309 Mon Sep 17 00:00:00 2001 From: smwltr Date: Tue, 12 Apr 2016 12:18:47 +0900 Subject: [PATCH 0096/1332] Adding suuport for OS Devuan --- cdist/conf/explorer/os | 5 +++++ cdist/conf/explorer/os_version | 3 +++ cdist/conf/type/__apt_norecommends/manifest | 2 +- cdist/conf/type/__hostname/gencode-remote | 4 ++-- cdist/conf/type/__hostname/manifest | 2 +- cdist/conf/type/__locale/manifest | 2 +- cdist/conf/type/__motd/gencode-remote | 4 ++-- cdist/conf/type/__motd/manifest | 2 +- cdist/conf/type/__package/manifest | 2 +- cdist/conf/type/__package_update_index/gencode-remote | 2 +- cdist/conf/type/__package_upgrade_all/gencode-remote | 2 +- cdist/conf/type/__postfix/manifest | 2 +- cdist/conf/type/__postfix_master/manifest | 2 +- cdist/conf/type/__postfix_postconf/explorer/value | 2 +- cdist/conf/type/__postfix_postconf/gencode-remote | 2 +- cdist/conf/type/__postfix_reload/gencode-remote | 2 +- cdist/conf/type/__start_on_boot/explorer/state | 2 +- cdist/conf/type/__timezone/gencode-remote | 2 +- cdist/conf/type/__timezone/manifest | 2 +- other/archived_types/__autofs/manifest | 2 +- other/archived_types/__autofs_reload/gencode-remote | 2 +- 21 files changed, 29 insertions(+), 21 deletions(-) diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index b9f3512b..de1d29c3 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -49,6 +49,11 @@ if [ -f /etc/debian_version ]; then echo debian exit 0 fi + +if [ -f /etc/devuan_version ]; then + echo devuan + exit 0 +fi ### if [ -f /etc/gentoo-release ]; then diff --git a/cdist/conf/explorer/os_version b/cdist/conf/explorer/os_version index 8f092827..6c7becdc 100755 --- a/cdist/conf/explorer/os_version +++ b/cdist/conf/explorer/os_version @@ -33,6 +33,9 @@ case "$($__explorer/os)" in debian) cat /etc/debian_version ;; + devuan) + cat /etc/devuan_version + ;; fedora) cat /etc/fedora-release ;; diff --git a/cdist/conf/type/__apt_norecommends/manifest b/cdist/conf/type/__apt_norecommends/manifest index 6fdc2d93..9e633308 100755 --- a/cdist/conf/type/__apt_norecommends/manifest +++ b/cdist/conf/type/__apt_norecommends/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian) + ubuntu|debian|devuan) # No stinking recommends thank you very much. # If I want something installed I will do so myself. __file /etc/apt/apt.conf.d/99-no-recommends \ diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 576f80bf..9fac7bf4 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -35,7 +35,7 @@ has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") # If everything is ok -> exit # case "$os" in - archlinux|debian|suse|ubuntu) + archlinux|debian|suse|ubuntu|devuan) if [ "$name_config" = "$name_should" -a "$name_running" = "$name_should" ]; then exit 0 fi @@ -60,7 +60,7 @@ if [ "$has_hostnamectl" ]; then echo "hostnamectl set-hostname '$name_should'" else case "$os" in - archlinux|debian|ubuntu) + archlinux|debian|ubuntu|devuan) echo "hostname '$name_should'" echo "printf '%s\n' '$name_should' > /etc/hostname" ;; diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 448e56da..76f962e0 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -34,7 +34,7 @@ not_supported() { } case "$os" in - archlinux|debian|suse|ubuntu) + archlinux|debian|suse|ubuntu|devuan) # handled in gencode-remote : ;; diff --git a/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest index 0e279630..c1837ae3 100644 --- a/cdist/conf/type/__locale/manifest +++ b/cdist/conf/type/__locale/manifest @@ -26,7 +26,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - debian) + debian|devuan) # Debian needs a seperate package __package locales --state present ;; diff --git a/cdist/conf/type/__motd/gencode-remote b/cdist/conf/type/__motd/gencode-remote index bfd13b5e..41fe3482 100755 --- a/cdist/conf/type/__motd/gencode-remote +++ b/cdist/conf/type/__motd/gencode-remote @@ -22,8 +22,8 @@ os=$(cat "$__global/explorer/os") case "$os" in - debian|ubuntu) - + debian|ubuntu|devuan) + # Debian and Ubuntu need to be updated, # as seen in /etc/init.d/bootlogs echo "uname -snrvm > /var/run/motd" diff --git a/cdist/conf/type/__motd/manifest b/cdist/conf/type/__motd/manifest index 286d1ff3..4848a4c3 100755 --- a/cdist/conf/type/__motd/manifest +++ b/cdist/conf/type/__motd/manifest @@ -30,7 +30,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - debian|ubuntu) + debian|ubuntu|devuan) destination=/etc/motd.tail ;; *) diff --git a/cdist/conf/type/__package/manifest b/cdist/conf/type/__package/manifest index 25e43b30..6b0daa98 100755 --- a/cdist/conf/type/__package/manifest +++ b/cdist/conf/type/__package/manifest @@ -32,7 +32,7 @@ else case "$os" in amazon|centos|fedora|redhat) type="yum" ;; archlinux) type="pacman" ;; - debian|ubuntu) type="apt" ;; + debian|ubuntu|devuan) type="apt" ;; freebsd) if [ -n "$(cat "$__object/explorer/pkgng_exists")" ]; then type="pkgng_freebsd" diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index 8ee837eb..589e7202 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -30,7 +30,7 @@ else os="$(cat "$__global/explorer/os")" case "$os" in amazon|centos|fedora|redhat) type="yum" ;; - debian|ubuntu) type="apt" ;; + debian|ubuntu|devuan) type="apt" ;; archlinux) type="pacman" ;; *) echo "Don't know how to manage packages on: $os" >&2 diff --git a/cdist/conf/type/__package_upgrade_all/gencode-remote b/cdist/conf/type/__package_upgrade_all/gencode-remote index 57676a57..4d034816 100755 --- a/cdist/conf/type/__package_upgrade_all/gencode-remote +++ b/cdist/conf/type/__package_upgrade_all/gencode-remote @@ -31,7 +31,7 @@ else os="$(cat "$__global/explorer/os")" case "$os" in amazon|centos|fedora|redhat) type="yum" ;; - debian|ubuntu) type="apt" ;; + debian|ubuntu|devuan) type="apt" ;; archlinux) type="pacman" ;; *) echo "Don't know how to manage packages on: $os" >&2 diff --git a/cdist/conf/type/__postfix/manifest b/cdist/conf/type/__postfix/manifest index 5a184910..43443e1e 100755 --- a/cdist/conf/type/__postfix/manifest +++ b/cdist/conf/type/__postfix/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|suse|centos) + ubuntu|debian|archlinux|suse|centos|devuan) __package postfix --state present ;; *) diff --git a/cdist/conf/type/__postfix_master/manifest b/cdist/conf/type/__postfix_master/manifest index 7777892b..3d82c526 100755 --- a/cdist/conf/type/__postfix_master/manifest +++ b/cdist/conf/type/__postfix_master/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|centos) + ubuntu|debian|archlinux|centos|devuan) : ;; *) diff --git a/cdist/conf/type/__postfix_postconf/explorer/value b/cdist/conf/type/__postfix_postconf/explorer/value index 3f319eda..d451bce6 100755 --- a/cdist/conf/type/__postfix_postconf/explorer/value +++ b/cdist/conf/type/__postfix_postconf/explorer/value @@ -22,7 +22,7 @@ os=$("$__explorer/os") case "$os" in - ubuntu|debian|archlinux|suse|centos) + ubuntu|debian|archlinux|suse|centos|devuan) : ;; *) diff --git a/cdist/conf/type/__postfix_postconf/gencode-remote b/cdist/conf/type/__postfix_postconf/gencode-remote index 4b4096a5..b3557640 100755 --- a/cdist/conf/type/__postfix_postconf/gencode-remote +++ b/cdist/conf/type/__postfix_postconf/gencode-remote @@ -21,7 +21,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|suse|centos) + ubuntu|debian|archlinux|suse|centos|devuan) : ;; *) diff --git a/cdist/conf/type/__postfix_reload/gencode-remote b/cdist/conf/type/__postfix_reload/gencode-remote index 8311568a..7323606c 100755 --- a/cdist/conf/type/__postfix_reload/gencode-remote +++ b/cdist/conf/type/__postfix_reload/gencode-remote @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|centos) + ubuntu|debian|archlinux|centos|devuan) echo "postfix reload" ;; *) diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 2f94a521..ca0f3a51 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -37,7 +37,7 @@ if [ "$init" = 'systemd' ]; then else case "$os" in - debian|openwrt) + debian|openwrt|devuan) state="present" [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" ;; diff --git a/cdist/conf/type/__timezone/gencode-remote b/cdist/conf/type/__timezone/gencode-remote index b4782d4b..c07a61cb 100755 --- a/cdist/conf/type/__timezone/gencode-remote +++ b/cdist/conf/type/__timezone/gencode-remote @@ -24,7 +24,7 @@ timezone="$__object_id" os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian) + ubuntu|debian|devuan) echo "echo \"$timezone\" > /etc/timezone" ;; esac diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index 9b0cce73..8ddfd122 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -26,7 +26,7 @@ timezone="$__object_id" os=$(cat "$__global/explorer/os") case "$os" in - archlinux|debian|ubuntu) + archlinux|debian|ubuntu|devuan) __package tzdata export require="__package/tzdata" ;; diff --git a/other/archived_types/__autofs/manifest b/other/archived_types/__autofs/manifest index 4a726c0a..ed6e87ee 100755 --- a/other/archived_types/__autofs/manifest +++ b/other/archived_types/__autofs/manifest @@ -23,7 +23,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux) + ubuntu|debian|archlinux|devuan) __package autofs --state present __start_on_boot autofs --state present ;; diff --git a/other/archived_types/__autofs_reload/gencode-remote b/other/archived_types/__autofs_reload/gencode-remote index 883602e2..913d3f24 100755 --- a/other/archived_types/__autofs_reload/gencode-remote +++ b/other/archived_types/__autofs_reload/gencode-remote @@ -28,7 +28,7 @@ not_supported() { } case "$os" in - ubuntu|debian|archlinux) + ubuntu|debian|archlinux|devuan) echo "pkill -HUP automount" ;; *) From 49423e174b35427e2984a8f77fb988c3c43bc862 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Apr 2016 08:24:44 +0200 Subject: [PATCH 0097/1332] Use pyvenv instead of virtualenv. --- cdist/conf/type/__pyvenv/gencode-remote | 10 +- cdist/conf/type/__pyvenv/man.text | 147 ++++++++++++------------ cdist/conf/type/__pyvenv/manifest | 2 +- 3 files changed, 73 insertions(+), 86 deletions(-) diff --git a/cdist/conf/type/__pyvenv/gencode-remote b/cdist/conf/type/__pyvenv/gencode-remote index b0fa121d..4e4513ee 100755 --- a/cdist/conf/type/__pyvenv/gencode-remote +++ b/cdist/conf/type/__pyvenv/gencode-remote @@ -30,13 +30,6 @@ destination="/$__object_id" owner="$(cat "$__object/parameter/owner")" group="$(cat "$__object/parameter/group")" mode="$(cat "$__object/parameter/mode")" -python="$(cat "$__object/parameter/python")" -if [ "$python" ] -then - python_opt="-p $python" -else - python_opt="" -fi venvparams="$(cat "$__object/parameter/venvparams")" [ "$state_should" = "$state_is" -a \ @@ -46,9 +39,8 @@ venvparams="$(cat "$__object/parameter/venvparams")" case $state_should in present) - if [ "$state_should" != "$state_is" ]; then - echo virtualenv "$python_opt" $venvparams "$destination" + echo pyvenv $venvparams "$destination" fi if [ \( -n "$owner" -a "$owner_is" != "$owner" \) -o \ \( -n "$group" -a "$group_is" != "$group" \) ]; then diff --git a/cdist/conf/type/__pyvenv/man.text b/cdist/conf/type/__pyvenv/man.text index 2f9a6ea5..3b1072f1 100755 --- a/cdist/conf/type/__pyvenv/man.text +++ b/cdist/conf/type/__pyvenv/man.text @@ -1,76 +1,71 @@ -cdist-type__pyvenv(7) -================== -Darko Poljak - - -NAME ----- -cdist-type__pyvenv - Create or remove python virtualenv - - -DESCRIPTION ------------ -This cdist type allows you to create or remove python virtualenv. -It assumes pip and virtualenv are already installed. Concrete packages -or installation procedures depend on concrete OS and/or OS -version/distribution. -Ensure this in your init manifest as in the following example: --------------------------------------------------------------------------------- -case "$__target_host" in - localhost) - __package python3-pip --state present - require="__package/python3-pip" __package_pip virtualenv --pip pip3 --state present - require="__package/python3-pip __package_pip/virtualenv" __pyvenv /home/darko/testenv --owner darko --group darko --mode 740 --state present - ;; --------------------------------------------------------------------------------- - - -REQUIRED PARAMETERS -------------------- -None - -OPTIONAL PARAMETERS -------------------- -state:: - Either "present" or "absent", defaults to "present" - -group:: - Group to chgrp to. - -mode:: - Unix permissions, suitable for chmod. - -owner:: - User to chown to. - -python:: - Use specific python interpreter for creating virtualenv. - The default is the interpreter that virtualenv was installed with. - -venvparams:: - virtualenv specific parameters to pass to virtualenv invocation. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -__pyvenv /home/services/djangoenv - -# Create python virtualenv for user foo using specific python interpreter. -__pyvenv /home/foo/fooenv --group foo --user foo --python python2.6 - -# Create python virtualenv with specific parameters. -__pyvenv /home/services/djangoenv --venvparams "--relocatable --system-site-packages" --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2016 Darko Poljak. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +cdist-type__pyvenv(7) +================== +Darko Poljak + + +NAME +---- +cdist-type__pyvenv - Create or remove python virtual environment + + +DESCRIPTION +----------- +This cdist type allows you to create or remove python virtual environment using pyvenv. +It assumes python >= 3.3 is already installed. Concrete package depends on concrete OS +and/or OS version/distribution. +Ensure this for e.g. in your init manifest as in the following example: +-------------------------------------------------------------------------------- +case "$__target_host" in + localhost) + __package python3 --state present + require="__package/python3" __pyvenv /home/darko/testenv --owner darko --group darko --mode 740 --state present + ;; +-------------------------------------------------------------------------------- + + +REQUIRED PARAMETERS +------------------- +None + +OPTIONAL PARAMETERS +------------------- +state:: + Either "present" or "absent", defaults to "present" + +group:: + Group to chgrp to + +mode:: + Unix permissions, suitable for chmod + +owner:: + User to chown to + +venvparams:: + Specific parameters to pass to pyvenv invocation + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__pyvenv /home/services/djangoenv + +# Create python virtualenv for user foo. +__pyvenv /home/foo/fooenv --group foo --user foo + +# Create python virtualenv with specific parameters. +__pyvenv /home/services/djangoenv --venvparams "--copies --system-site-packages" +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2016 Darko Poljak. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). + diff --git a/cdist/conf/type/__pyvenv/manifest b/cdist/conf/type/__pyvenv/manifest index bd2b76e9..3f0fbb17 100755 --- a/cdist/conf/type/__pyvenv/manifest +++ b/cdist/conf/type/__pyvenv/manifest @@ -18,7 +18,7 @@ # along with cdist. If not, see . # -# It assumes pip and virtualenv are already installed. Concrete packages +# It assumes python >= 3.3 is already installed. Concrete packages # or installation procedures depend on concrete OS and/or OS # version/distribution. From 85af0c1bb0d6806914975ff8ddedcf189e140b80 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Apr 2016 08:26:58 +0200 Subject: [PATCH 0098/1332] Remove virtualenv params not present in pyvenv. --- cdist/conf/type/__pyvenv/parameter/optional | 1 - 1 file changed, 1 deletion(-) diff --git a/cdist/conf/type/__pyvenv/parameter/optional b/cdist/conf/type/__pyvenv/parameter/optional index 6b3fda2e..fc4019c9 100755 --- a/cdist/conf/type/__pyvenv/parameter/optional +++ b/cdist/conf/type/__pyvenv/parameter/optional @@ -2,5 +2,4 @@ state group owner mode -python venvparams From 3296158a375b50afe03136160156e8711857fcd7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Apr 2016 08:27:23 +0200 Subject: [PATCH 0099/1332] Remove virtualenv params not present in pyvenv. --- cdist/conf/type/__pyvenv/parameter/default/python | 1 - 1 file changed, 1 deletion(-) delete mode 100644 cdist/conf/type/__pyvenv/parameter/default/python diff --git a/cdist/conf/type/__pyvenv/parameter/default/python b/cdist/conf/type/__pyvenv/parameter/default/python deleted file mode 100644 index 8b137891..00000000 --- a/cdist/conf/type/__pyvenv/parameter/default/python +++ /dev/null @@ -1 +0,0 @@ - From 0ba27d8326e6ba37262c544335c4a6f29224f7eb Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Apr 2016 08:29:38 +0200 Subject: [PATCH 0100/1332] Fix text typos. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 5ec8edea..9feb2097 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,7 +2,7 @@ Changelog --------- next: - * Type __package_pip: Add support for running as specified user (useful for pip from virtualenv (Darko Poljak) + * Type __package_pip: Add support for running as specified user (useful for pip in venv) (Darko Poljak) * New type: __pyvenv: Manage python virtualenv (Darko Poljak) * Core: Add CDIST_REMOTE_COPY/EXEC env variables and multiplexing options for default scp/ssh (Darko Poljak) * Types: Remove bashisms in scripts (Darko Poljak) From 4d5fa3087f1af3d2c6f0d4e2a86c44d3c8b9de25 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Apr 2016 20:14:06 +0200 Subject: [PATCH 0101/1332] Update comment info. --- cdist/conf/type/__pyvenv/man.text | 11 ++++++----- cdist/conf/type/__pyvenv/manifest | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__pyvenv/man.text b/cdist/conf/type/__pyvenv/man.text index 3b1072f1..80934710 100755 --- a/cdist/conf/type/__pyvenv/man.text +++ b/cdist/conf/type/__pyvenv/man.text @@ -10,15 +10,16 @@ cdist-type__pyvenv - Create or remove python virtual environment DESCRIPTION ----------- -This cdist type allows you to create or remove python virtual environment using pyvenv. -It assumes python >= 3.3 is already installed. Concrete package depends on concrete OS -and/or OS version/distribution. +This cdist type allows you to create or remove python virtual +environment using pyvenv. +It assumes pyvenv is already installed. Concrete package depends +on concrete OS and/or OS version/distribution. Ensure this for e.g. in your init manifest as in the following example: -------------------------------------------------------------------------------- case "$__target_host" in localhost) - __package python3 --state present - require="__package/python3" __pyvenv /home/darko/testenv --owner darko --group darko --mode 740 --state present + __package python3-venv --state present + require="__package/python3-venv" __pyvenv /home/darko/testenv --owner darko --group darko --mode 740 --state present ;; -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__pyvenv/manifest b/cdist/conf/type/__pyvenv/manifest index 3f0fbb17..3e41ad04 100755 --- a/cdist/conf/type/__pyvenv/manifest +++ b/cdist/conf/type/__pyvenv/manifest @@ -18,7 +18,7 @@ # along with cdist. If not, see . # -# It assumes python >= 3.3 is already installed. Concrete packages +# It assumes pyvenv is already installed. Concrete packages # or installation procedures depend on concrete OS and/or OS # version/distribution. From d9b2f1a54073763e99e1ecbfd3e1003a0e656811 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Apr 2016 22:32:15 +0200 Subject: [PATCH 0102/1332] Add parameter --pyvenv. --- cdist/conf/type/__pyvenv/gencode-remote | 15 +++++++++++---- cdist/conf/type/__pyvenv/man.text | 6 ++++++ cdist/conf/type/__pyvenv/parameter/optional | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__pyvenv/gencode-remote b/cdist/conf/type/__pyvenv/gencode-remote index 4e4513ee..907e0ff6 100755 --- a/cdist/conf/type/__pyvenv/gencode-remote +++ b/cdist/conf/type/__pyvenv/gencode-remote @@ -25,22 +25,29 @@ group_is="$(cat "$__object/explorer/group")" state_should="$(cat "$__object/parameter/state")" -destination="/$__object_id" - owner="$(cat "$__object/parameter/owner")" group="$(cat "$__object/parameter/group")" mode="$(cat "$__object/parameter/mode")" -venvparams="$(cat "$__object/parameter/venvparams")" [ "$state_should" = "$state_is" -a \ "$owner" = "$owner_is" -a \ "$group" = "$group_is" -a \ -n "$mode" ] && exit 0 +destination="/$__object_id" +venvparams="$(cat "$__object/parameter/venvparams")" +pyvenvparam="$__object/parameter/pyvenv" +if [ -f "$pyvenvparam" ] +then + pyvenv=$(cat "$pyvenvparam") +else + pyvenv="pyvenv" +fi + case $state_should in present) if [ "$state_should" != "$state_is" ]; then - echo pyvenv $venvparams "$destination" + echo $pyvenv $venvparams "$destination" fi if [ \( -n "$owner" -a "$owner_is" != "$owner" \) -o \ \( -n "$group" -a "$group_is" != "$group" \) ]; then diff --git a/cdist/conf/type/__pyvenv/man.text b/cdist/conf/type/__pyvenv/man.text index 80934710..6124c72c 100755 --- a/cdist/conf/type/__pyvenv/man.text +++ b/cdist/conf/type/__pyvenv/man.text @@ -42,6 +42,9 @@ mode:: owner:: User to chown to +pyvenv:: + Use this specific pyvenv + venvparams:: Specific parameters to pass to pyvenv invocation @@ -52,6 +55,9 @@ EXAMPLES -------------------------------------------------------------------------------- __pyvenv /home/services/djangoenv +# Use specific pyvenv +__pyvenv /home/foo/fooenv --pyvenv /usr/local/bin/pyvenv-3.4 + # Create python virtualenv for user foo. __pyvenv /home/foo/fooenv --group foo --user foo diff --git a/cdist/conf/type/__pyvenv/parameter/optional b/cdist/conf/type/__pyvenv/parameter/optional index fc4019c9..ed2218b1 100755 --- a/cdist/conf/type/__pyvenv/parameter/optional +++ b/cdist/conf/type/__pyvenv/parameter/optional @@ -3,3 +3,4 @@ group owner mode venvparams +pyvenv From a1e86a481c9e11261a7382a91bf8a6ddbedadc31 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Apr 2016 22:34:10 +0200 Subject: [PATCH 0103/1332] Updated man. --- cdist/conf/type/__pyvenv/man.text | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__pyvenv/man.text b/cdist/conf/type/__pyvenv/man.text index 6124c72c..4fcd4dd1 100755 --- a/cdist/conf/type/__pyvenv/man.text +++ b/cdist/conf/type/__pyvenv/man.text @@ -19,8 +19,10 @@ Ensure this for e.g. in your init manifest as in the following example: case "$__target_host" in localhost) __package python3-venv --state present - require="__package/python3-venv" __pyvenv /home/darko/testenv --owner darko --group darko --mode 740 --state present + require="__package/python3-venv" __pyvenv /home/darko/testenv --pyvenv "pyvenv-3.4" --owner darko --group darko --mode 740 --state present + require="__pyvenv/home/darko/testenv" __package_pip docopt --pip /home/darko/testenv/bin/pip --runas darko --state present ;; +esac -------------------------------------------------------------------------------- From cd78d4140a564e1547a072b857536360d6482e91 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Apr 2016 08:37:33 +0200 Subject: [PATCH 0104/1332] Add global explorers su, sudo and sucmd. --- .../conf/{type/__package_pip => }/explorer/su | 11 ++++- cdist/conf/explorer/sucmd | 46 +++++++++++++++++++ .../{type/__package_pip => }/explorer/sudo | 11 ++++- cdist/conf/type/__package_pip/gencode-remote | 28 ++--------- 4 files changed, 69 insertions(+), 27 deletions(-) rename cdist/conf/{type/__package_pip => }/explorer/su (68%) create mode 100644 cdist/conf/explorer/sucmd rename cdist/conf/{type/__package_pip => }/explorer/sudo (67%) diff --git a/cdist/conf/type/__package_pip/explorer/su b/cdist/conf/explorer/su similarity index 68% rename from cdist/conf/type/__package_pip/explorer/su rename to cdist/conf/explorer/su index f355a1bc..ae164e69 100644 --- a/cdist/conf/type/__package_pip/explorer/su +++ b/cdist/conf/explorer/su @@ -17,11 +17,18 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # +# This explorer returns script code string for running a command with su. +# If no su is found then it returns empty string. +# It uses two arguments, first user and the second command to run. +# If the result string is assigned to foo it is used as: +# $ $foo user command +# which su > /dev/null 2>&1 if [ $? -eq 0 ] then - echo yes + su_func='f() { su -c "$2" $1 ; }' + echo "eval '${su_func}' ; f " else - echo no + echo "" fi diff --git a/cdist/conf/explorer/sucmd b/cdist/conf/explorer/sucmd new file mode 100644 index 00000000..1f16666d --- /dev/null +++ b/cdist/conf/explorer/sucmd @@ -0,0 +1,46 @@ +#!/bin/sh +# +# 2016 Darko Poljak (darko.poljak 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 . +# +# This explorer returns script code string for running a command with su +# or sudo, whichever it founds. If searches the command in the order of +# first sudo and then su if sudo is not found. +# If no sudo nor su is found then it returns string script code to run +# bare command. +# It uses two arguments, first user and the second command to run. +# If the result string is assigned to foo it is used as: +# $ $foo user command +# + +# first check sudo +which sudo > /dev/null 2>&1 +if [ $? -eq 0 ] +then + func='f() { sudo -H -u $1 $2; }' +else + # if no sudo then check su + which su > /dev/null 2>&1 + if [ $? -eq 0 ] + then + func='f() { su -c "$2" $1 ; }' + else + # if no sudo nor su then run bare command + func='f() { $2 ; }' + fi +fi +echo "eval '${func}' ; f " diff --git a/cdist/conf/type/__package_pip/explorer/sudo b/cdist/conf/explorer/sudo similarity index 67% rename from cdist/conf/type/__package_pip/explorer/sudo rename to cdist/conf/explorer/sudo index 7b702bc0..079c570d 100644 --- a/cdist/conf/type/__package_pip/explorer/sudo +++ b/cdist/conf/explorer/sudo @@ -17,11 +17,18 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # +# This explorer returns script code string for running a command with sudo. +# If no sudo is found then it returns empty string. +# It uses two arguments, first user and the second command to run. +# If the result string is assigned to foo it is used as: +# $ $foo user command +# which sudo > /dev/null 2>&1 if [ $? -eq 0 ] then - echo yes + sudo_func='f() { sudo -H -u $1 $2; }' + echo "eval '${sudo_func}' ; f " else - echo no + echo "" fi diff --git a/cdist/conf/type/__package_pip/gencode-remote b/cdist/conf/type/__package_pip/gencode-remote index ccf30f1a..b9a52efc 100644 --- a/cdist/conf/type/__package_pip/gencode-remote +++ b/cdist/conf/type/__package_pip/gencode-remote @@ -45,42 +45,24 @@ runasparam="$__object/parameter/runas" if [ -f "$runasparam" ] then runas=$(cat "$runasparam") - has_sudo=$(cat "$__object/explorer/sudo") - if [ "$has_sudo" = "yes" ] - then - runas_cmd="sudo" - else - has_su=$(cat "$__object/explorer/su") - if [ "$has_su" = "yes" ] - then - runas_cmd="su" - else - runas_cmd="" - fi - fi + runas_cmd=$(cat "$__global/explorer/sucmd") else runas_cmd="" fi case "$state_should" in present) - if [ "$runas_cmd" = "sudo" ] + if [ "$runas_cmd" ] then - echo sudo -H -u $runas $pip install -q "$name" - elif [ "$runas_cmd" = "su" ] - then - echo su $runas -c \"$pip install -q "$name"\" + echo "$runas_cmd $runas \"$pip install -q $name\"" else echo $pip install -q "$name" fi ;; absent) - if [ "$runas_cmd" = "sudo" ] + if [ "$runas_cmd" ] then - echo sudo -H -u $runas $pip uninstall -q -y "$name" - elif [ "$runas_cmd" = "su" ] - then - echo su $runas -c \"$pip uninstall -q -y "$name"\" + echo "$runas_cmd $runas \"$pip uninstall -q -y $name\"" else echo $pip uninstall -q -y "$name" fi From 641b511f1aaa2ed9e441a9cdb9db766d6f819d5e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Apr 2016 08:39:33 +0200 Subject: [PATCH 0105/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 9feb2097..3ee4622d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Types: Add global explorers su, sudo and sucmd (Darko Poljak) * Type __package_pip: Add support for running as specified user (useful for pip in venv) (Darko Poljak) * New type: __pyvenv: Manage python virtualenv (Darko Poljak) * Core: Add CDIST_REMOTE_COPY/EXEC env variables and multiplexing options for default scp/ssh (Darko Poljak) From 856678b09c1d3304010ec236022aad8311ca4c55 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Apr 2016 08:40:08 +0200 Subject: [PATCH 0106/1332] Update changelog. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 3ee4622d..25dc2a00 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,7 +2,7 @@ Changelog --------- next: - * Types: Add global explorers su, sudo and sucmd (Darko Poljak) + * Types: Add global explorers su, sudo and sucmd (Darko Poljak) * Type __package_pip: Add support for running as specified user (useful for pip in venv) (Darko Poljak) * New type: __pyvenv: Manage python virtualenv (Darko Poljak) * Core: Add CDIST_REMOTE_COPY/EXEC env variables and multiplexing options for default scp/ssh (Darko Poljak) From 5c33d2292520c73f8cba89efb91284dc71366137 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Apr 2016 10:50:51 +0200 Subject: [PATCH 0107/1332] Prefer su over sudo. --- cdist/conf/explorer/sucmd | 40 +++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/cdist/conf/explorer/sucmd b/cdist/conf/explorer/sucmd index 1f16666d..bd4343d2 100644 --- a/cdist/conf/explorer/sucmd +++ b/cdist/conf/explorer/sucmd @@ -19,27 +19,47 @@ # # This explorer returns script code string for running a command with su # or sudo, whichever it founds. If searches the command in the order of -# first sudo and then su if sudo is not found. -# If no sudo nor su is found then it returns string script code to run +# first su and then sudo if su is not found. +# If no su nor sudo is found then it returns string script code to run # bare command. # It uses two arguments, first user and the second command to run. # If the result string is assigned to foo it is used as: # $ $foo user command # -# first check sudo -which sudo > /dev/null 2>&1 -if [ $? -eq 0 ] -then - func='f() { sudo -H -u $1 $2; }' -else - # if no sudo then check su +sudo_func() { + which sudo > /dev/null 2>&1 + if [ $? -eq 0 ] + then + func='f() { sudo -H -u $1 $2; }' + retval=0 + else + func='' + retval=1 + fi + return $retval +} +su_func() { which su > /dev/null 2>&1 if [ $? -eq 0 ] then func='f() { su -c "$2" $1 ; }' + retval=0 else - # if no sudo nor su then run bare command + func='' + retval=1 + fi + return $retval +} +# first check su +su_func +if [ $? -ne 0 ] +then + # if no su then check sudo + sudo_func + if [ $? -ne 0 ] + then + # if no su nor sudo then run bare command func='f() { $2 ; }' fi fi From f24d2644807033f0cb3f5ab080d7d3b5c1e03740 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Apr 2016 12:04:31 +0200 Subject: [PATCH 0108/1332] Updated usage comment. --- cdist/conf/explorer/su | 5 +++-- cdist/conf/explorer/sucmd | 5 +++-- cdist/conf/explorer/sudo | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cdist/conf/explorer/su b/cdist/conf/explorer/su index ae164e69..9fc83c56 100644 --- a/cdist/conf/explorer/su +++ b/cdist/conf/explorer/su @@ -20,8 +20,9 @@ # This explorer returns script code string for running a command with su. # If no su is found then it returns empty string. # It uses two arguments, first user and the second command to run. -# If the result string is assigned to foo it is used as: -# $ $foo user command +# If the result string is assigned to foo it can be used in code +# generation as: +# echo "$foo user command" # which su > /dev/null 2>&1 diff --git a/cdist/conf/explorer/sucmd b/cdist/conf/explorer/sucmd index bd4343d2..78d46b09 100644 --- a/cdist/conf/explorer/sucmd +++ b/cdist/conf/explorer/sucmd @@ -23,8 +23,9 @@ # If no su nor sudo is found then it returns string script code to run # bare command. # It uses two arguments, first user and the second command to run. -# If the result string is assigned to foo it is used as: -# $ $foo user command +# If the result string is assigned to foo it can be used in code +# generation as: +# echo "$foo user command" # sudo_func() { diff --git a/cdist/conf/explorer/sudo b/cdist/conf/explorer/sudo index 079c570d..b217f58b 100644 --- a/cdist/conf/explorer/sudo +++ b/cdist/conf/explorer/sudo @@ -20,8 +20,9 @@ # This explorer returns script code string for running a command with sudo. # If no sudo is found then it returns empty string. # It uses two arguments, first user and the second command to run. -# If the result string is assigned to foo it is used as: -# $ $foo user command +# If the result string is assigned to foo it can be used in code +# generation as: +# echo "$foo user command" # which sudo > /dev/null 2>&1 From e76d2af3586508e90b24c85a625fae424f9faf85 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Apr 2016 08:13:47 +0200 Subject: [PATCH 0109/1332] Remove old style defaults. --- cdist/conf/type/__mount/parameter/default/options | 1 + cdist/conf/type/__mount/parameter/default/type | 1 + 2 files changed, 2 insertions(+) create mode 100644 cdist/conf/type/__mount/parameter/default/options create mode 100644 cdist/conf/type/__mount/parameter/default/type diff --git a/cdist/conf/type/__mount/parameter/default/options b/cdist/conf/type/__mount/parameter/default/options new file mode 100644 index 00000000..e94f8140 --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/options @@ -0,0 +1 @@ +defaults diff --git a/cdist/conf/type/__mount/parameter/default/type b/cdist/conf/type/__mount/parameter/default/type new file mode 100644 index 00000000..865faf10 --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/type @@ -0,0 +1 @@ +auto From 2ea85c773c20fab6cec5ca7b2391db3fade515ee Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Apr 2016 08:14:44 +0200 Subject: [PATCH 0110/1332] Remove old style defaults. --- cdist/conf/type/__mount/manifest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__mount/manifest b/cdist/conf/type/__mount/manifest index 8a1fa234..472b6e2e 100755 --- a/cdist/conf/type/__mount/manifest +++ b/cdist/conf/type/__mount/manifest @@ -26,9 +26,9 @@ if [ ! -f "$__object/parameter/nofstab" ]; then ( printf "%s" "$(cat "$__object/parameter/device")" printf " %s" "$path" -type="$(cat "$__object/parameter/type" 2>/dev/null || echo "auto")" +type="$(cat "$__object/parameter/type")" printf " %s" "$type" -options="$(cat "$__object/parameter/options" 2>/dev/null || echo "defaults")" +options="$(cat "$__object/parameter/options")" printf " %s" "$options" printf " %s" "$(cat "$__object/parameter/dump")" printf " %s\n" "$(cat "$__object/parameter/pass")" From 66c2e16a24df102539e462957bbf8246dd479910 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 21 Apr 2016 08:24:47 +0200 Subject: [PATCH 0111/1332] __package_pip: always use su for runas parameter. --- cdist/conf/type/__package_pip/gencode-remote | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__package_pip/gencode-remote b/cdist/conf/type/__package_pip/gencode-remote index b9a52efc..ccfdb92b 100644 --- a/cdist/conf/type/__package_pip/gencode-remote +++ b/cdist/conf/type/__package_pip/gencode-remote @@ -45,24 +45,23 @@ runasparam="$__object/parameter/runas" if [ -f "$runasparam" ] then runas=$(cat "$runasparam") - runas_cmd=$(cat "$__global/explorer/sucmd") else - runas_cmd="" + runas="" fi case "$state_should" in present) - if [ "$runas_cmd" ] + if [ "$runas" ] then - echo "$runas_cmd $runas \"$pip install -q $name\"" + echo "su -c \"$pip install -q $name\" $runas" else echo $pip install -q "$name" fi ;; absent) - if [ "$runas_cmd" ] + if [ "$runas" ] then - echo "$runas_cmd $runas \"$pip uninstall -q -y $name\"" + echo "su -c \"$pip uninstall -q -y $name\" $runas" else echo $pip uninstall -q -y "$name" fi From 7aa197b731238f5315ee37e27a8c92bb4f413590 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 21 Apr 2016 08:26:07 +0200 Subject: [PATCH 0112/1332] Rm unnecessary details from __package_pip man. --- cdist/conf/type/__package_pip/man.text | 2 -- 1 file changed, 2 deletions(-) diff --git a/cdist/conf/type/__package_pip/man.text b/cdist/conf/type/__package_pip/man.text index cb7c7e11..5b67e62f 100644 --- a/cdist/conf/type/__package_pip/man.text +++ b/cdist/conf/type/__package_pip/man.text @@ -32,8 +32,6 @@ state:: runas:: Run pip as specified user. By default it runs as root. - It uses sudo or su, whichever it founds first, respectively. - If no sudo nor su is present then pip is run by default. EXAMPLES From 5e0975a30417eb48e7e49a296b5ca0e03c2cb6dd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 21 Apr 2016 08:26:47 +0200 Subject: [PATCH 0113/1332] Remove unnecessary global explorer. --- cdist/conf/explorer/su | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 cdist/conf/explorer/su diff --git a/cdist/conf/explorer/su b/cdist/conf/explorer/su deleted file mode 100644 index 9fc83c56..00000000 --- a/cdist/conf/explorer/su +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -# -# 2016 Darko Poljak (darko.poljak 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 . -# -# This explorer returns script code string for running a command with su. -# If no su is found then it returns empty string. -# It uses two arguments, first user and the second command to run. -# If the result string is assigned to foo it can be used in code -# generation as: -# echo "$foo user command" -# - -which su > /dev/null 2>&1 -if [ $? -eq 0 ] -then - su_func='f() { su -c "$2" $1 ; }' - echo "eval '${su_func}' ; f " -else - echo "" -fi From b7da9d1ef50b2ec16ee7f4a3abb429450f43e955 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 21 Apr 2016 08:26:57 +0200 Subject: [PATCH 0114/1332] Remove unnecessary global explorer. --- cdist/conf/explorer/sucmd | 67 --------------------------------------- 1 file changed, 67 deletions(-) delete mode 100644 cdist/conf/explorer/sucmd diff --git a/cdist/conf/explorer/sucmd b/cdist/conf/explorer/sucmd deleted file mode 100644 index 78d46b09..00000000 --- a/cdist/conf/explorer/sucmd +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh -# -# 2016 Darko Poljak (darko.poljak 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 . -# -# This explorer returns script code string for running a command with su -# or sudo, whichever it founds. If searches the command in the order of -# first su and then sudo if su is not found. -# If no su nor sudo is found then it returns string script code to run -# bare command. -# It uses two arguments, first user and the second command to run. -# If the result string is assigned to foo it can be used in code -# generation as: -# echo "$foo user command" -# - -sudo_func() { - which sudo > /dev/null 2>&1 - if [ $? -eq 0 ] - then - func='f() { sudo -H -u $1 $2; }' - retval=0 - else - func='' - retval=1 - fi - return $retval -} -su_func() { - which su > /dev/null 2>&1 - if [ $? -eq 0 ] - then - func='f() { su -c "$2" $1 ; }' - retval=0 - else - func='' - retval=1 - fi - return $retval -} -# first check su -su_func -if [ $? -ne 0 ] -then - # if no su then check sudo - sudo_func - if [ $? -ne 0 ] - then - # if no su nor sudo then run bare command - func='f() { $2 ; }' - fi -fi -echo "eval '${func}' ; f " From b40034a54aa17b19b82b1ad66f781959eaf51578 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 21 Apr 2016 08:27:08 +0200 Subject: [PATCH 0115/1332] Remove unnecessary global explorer. --- cdist/conf/explorer/sudo | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 cdist/conf/explorer/sudo diff --git a/cdist/conf/explorer/sudo b/cdist/conf/explorer/sudo deleted file mode 100644 index b217f58b..00000000 --- a/cdist/conf/explorer/sudo +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh -# -# 2016 Darko Poljak (darko.poljak 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 . -# -# This explorer returns script code string for running a command with sudo. -# If no sudo is found then it returns empty string. -# It uses two arguments, first user and the second command to run. -# If the result string is assigned to foo it can be used in code -# generation as: -# echo "$foo user command" -# - -which sudo > /dev/null 2>&1 -if [ $? -eq 0 ] -then - sudo_func='f() { sudo -H -u $1 $2; }' - echo "eval '${sudo_func}' ; f " -else - echo "" -fi From 9a9836a0477d028ee166bfa748b43ac98414f250 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 21 Apr 2016 08:28:47 +0200 Subject: [PATCH 0116/1332] Remove unnecessary global explorers. --- docs/changelog | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 25dc2a00..9feb2097 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,7 +2,6 @@ Changelog --------- next: - * Types: Add global explorers su, sudo and sucmd (Darko Poljak) * Type __package_pip: Add support for running as specified user (useful for pip in venv) (Darko Poljak) * New type: __pyvenv: Manage python virtualenv (Darko Poljak) * Core: Add CDIST_REMOTE_COPY/EXEC env variables and multiplexing options for default scp/ssh (Darko Poljak) From 360ab47be0a02ac65c34314881d59f6cbc6991d3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 21 Apr 2016 09:23:19 +0200 Subject: [PATCH 0117/1332] Fix '=' length. --- cdist/conf/type/__pyvenv/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__pyvenv/man.text b/cdist/conf/type/__pyvenv/man.text index 4fcd4dd1..71d30ed5 100755 --- a/cdist/conf/type/__pyvenv/man.text +++ b/cdist/conf/type/__pyvenv/man.text @@ -1,5 +1,5 @@ cdist-type__pyvenv(7) -================== +===================== Darko Poljak From e933e8cd750f2735d223eb44f1904f71aaf0b047 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 22 Apr 2016 14:41:31 +0200 Subject: [PATCH 0118/1332] Add missing name parameter. --- cdist/conf/type/__package_pip/parameter/optional | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__package_pip/parameter/optional b/cdist/conf/type/__package_pip/parameter/optional index 83265c8b..d909e790 100644 --- a/cdist/conf/type/__package_pip/parameter/optional +++ b/cdist/conf/type/__package_pip/parameter/optional @@ -1,3 +1,4 @@ +name pip state runas From a4a31c5880b2ec079967c01a253ac87b508403e8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 4 May 2016 08:20:55 +0200 Subject: [PATCH 0119/1332] Prepare for 4.0.0. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index dd9c7fab..3a644b6f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.0.0: 2016-05-04 * Core: Fix bug with parallel hosts operation when output path is specifed (Darko Poljak) * Type __package_pip: Add support for running as specified user (useful for pip in venv) (Darko Poljak) * New type: __pyvenv: Manage python virtualenv (Darko Poljak) From 15f7fd039ac4a47b87eb0e07cbbe07dc64cd85ea Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 4 May 2016 12:06:19 +0200 Subject: [PATCH 0120/1332] Make sed invocation to not be GNU specific. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fb5fc09f..777387b7 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 # is the man page section (1 or 7). The first three lines of the input # (xml, DOCTYPE, head tags) are ignored, since the head tags contains # the title of the page and should not contain a href. -CROSSLINK=sed --in-place '1,3!s/\([[:alnum:]_-]*\)(\([17]\))/&<\/a>/g' +CROSSLINK=sed -i '1,3!s/\([[:alnum:]_-]*\)(\([17]\))/&<\/a>/g' helper=./bin/build-helper MANDIR=docs/man From f63e8ed2b9238044d6d313260c599b0780f40857 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 4 May 2016 12:23:19 +0200 Subject: [PATCH 0121/1332] For BSD sed variant -i suffix is required. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 777387b7..d78eb1a1 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 # is the man page section (1 or 7). The first three lines of the input # (xml, DOCTYPE, head tags) are ignored, since the head tags contains # the title of the page and should not contain a href. -CROSSLINK=sed -i '1,3!s/\([[:alnum:]_-]*\)(\([17]\))/&<\/a>/g' +CROSSLINK=sed -i '' '1,3!s/\([[:alnum:]_-]*\)(\([17]\))/&<\/a>/g' helper=./bin/build-helper MANDIR=docs/man From 8a079b3440b7ec57e9c9bb45da93fac69290be99 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 5 May 2016 09:58:35 +0200 Subject: [PATCH 0122/1332] Fix spelling errors - Bogatov's patch. --- cdist/conf/type/__cron/man.text | 2 +- cdist/conf/type/__directory/man.text | 2 +- cdist/conf/type/__key_value/man.text | 2 +- cdist/conf/type/__zypper_repo/man.text | 4 ++-- docs/man/cdist-reference.text.sh | 2 +- docs/man/man7/cdist-best-practice.text | 2 +- docs/man/man7/cdist-manifest.text | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cdist/conf/type/__cron/man.text b/cdist/conf/type/__cron/man.text index f4e80a08..ee30c83f 100644 --- a/cdist/conf/type/__cron/man.text +++ b/cdist/conf/type/__cron/man.text @@ -42,7 +42,7 @@ raw:: See crontab(5) for the extensions if any that your cron implementation implements. raw_command:: - Take whatever the user has given in the commmand and ignore everything else. + Take whatever the user has given in the command and ignore everything else. If given, the command will be added to crontab. Can for example be used to define variables like SHELL or MAILTO. diff --git a/cdist/conf/type/__directory/man.text b/cdist/conf/type/__directory/man.text index a0bf8062..77d5da34 100644 --- a/cdist/conf/type/__directory/man.text +++ b/cdist/conf/type/__directory/man.text @@ -59,7 +59,7 @@ create:: remove:: Directory exists, but state is absent, directory will be removed by generated code. remove non directory:: - Someting other than a directory with the same name exists and was removed prior to create. + Something other than a directory with the same name exists and was removed prior to create. EXAMPLES diff --git a/cdist/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.text index d4c8e2cc..c27931e5 100644 --- a/cdist/conf/type/__key_value/man.text +++ b/cdist/conf/type/__key_value/man.text @@ -19,7 +19,7 @@ REQUIRED PARAMETERS file:: The file to operate on. delimiter:: - The delimiter which seperates the key from the value. + The delimiter which separates the key from the value. OPTIONAL PARAMETERS diff --git a/cdist/conf/type/__zypper_repo/man.text b/cdist/conf/type/__zypper_repo/man.text index e8024ce5..a1dd9565 100644 --- a/cdist/conf/type/__zypper_repo/man.text +++ b/cdist/conf/type/__zypper_repo/man.text @@ -22,11 +22,11 @@ OPTIONAL PARAMETERS ------------------- state:: Either "present" or "absent" or "enabled" or "disabled", defaults to "present" + - #present# - make sure that the repo is aviable, needs uri and repo_desc + + #present# - make sure that the repo is available, needs uri and repo_desc + for all following states, the repo can be searched via repo_id or uri + #absent# - drop the repo if found + #enabled# - a repo can have state disabled if installed via zypper service (ris), in this case, you can enable the repo + - #disabled# - instead of absent (drop), a repo can also set to disabled, wich makes it inaccessible + + #disabled# - instead of absent (drop), a repo can also set to disabled, which makes it inaccessible + uri:: If supplied, use the uri and not the object id as repo uri. diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 0aaaec0a..012bcf5d 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -183,7 +183,7 @@ files:: (for instance to store template results). changed:: This empty file exists in an object directory, if the object has - code to be excuted (either remote or local) + code to be executed (either remote or local) stdin:: This file exists and contains data, if data was provided on stdin when the type was called. diff --git a/docs/man/man7/cdist-best-practice.text b/docs/man/man7/cdist-best-practice.text index a818be60..953b8272 100644 --- a/docs/man/man7/cdist-best-practice.text +++ b/docs/man/man7/cdist-best-practice.text @@ -88,7 +88,7 @@ MAINTAINING MULTIPLE CONFIGURATIONS ----------------------------------- When you need to manage multiple sites with cdist, like company_a, company_b and private for instance, you can easily use git for this purpose. -Including a possible common base that is reused accross the different sites: +Including a possible common base that is reused across the different sites: -------------------------------------------------------------------------------- # create branches diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index a844c012..12cc91c8 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -181,11 +181,11 @@ OVERRIDES --------- In some special cases, you would like to create an already defined object with different parameters. In normal situations this leads to an error in cdist. -If you whish, you can setup the environment variable CDIST_OVERRIDE +If you wish, you can setup the environment variable CDIST_OVERRIDE (any value or even empty is ok) to tell cdist, that this object override is wanted and should be accepted. ATTENTION: Only use this feature if you are 100% sure in which order -cdist encounters the affected objects, otherwhise this results +cdist encounters the affected objects, otherwise this results in an undefined situation. If CDIST_OVERRIDE and CDIST_ORDER_DEPENDENCY are set for an object, From 0bb251bdda0de1dfe7c577ff5bc15055e5591ef3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 13 May 2016 22:20:55 +0200 Subject: [PATCH 0123/1332] Fix suffix description for __block type. --- cdist/conf/type/__block/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__block/man.text b/cdist/conf/type/__block/man.text index 2312d293..97f538fa 100644 --- a/cdist/conf/type/__block/man.text +++ b/cdist/conf/type/__block/man.text @@ -34,7 +34,7 @@ prefix:: Defaults to #cdist:__block/$__object_id suffix:: - the prefix to add after the text. + the suffix to add after the text. Defaults to #/cdist:__block/$__object_id state:: From 103e520d5aede5404ea8b7bd03fe6ca19f3ce0fc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 13 May 2016 22:29:08 +0200 Subject: [PATCH 0124/1332] Fix suffix description for __block type. --- cdist/conf/type/__block/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__block/man.text b/cdist/conf/type/__block/man.text index 2312d293..97f538fa 100644 --- a/cdist/conf/type/__block/man.text +++ b/cdist/conf/type/__block/man.text @@ -34,7 +34,7 @@ prefix:: Defaults to #cdist:__block/$__object_id suffix:: - the prefix to add after the text. + the suffix to add after the text. Defaults to #/cdist:__block/$__object_id state:: From c4f782d19469e0cca8c6440f82b2ab39e107fbf4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 13 May 2016 22:44:54 +0200 Subject: [PATCH 0125/1332] Fix spelling error in __group man. --- cdist/conf/type/__group/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__group/man.text b/cdist/conf/type/__group/man.text index 4b18a552..8a441923 100644 --- a/cdist/conf/type/__group/man.text +++ b/cdist/conf/type/__group/man.text @@ -45,7 +45,7 @@ remove:: change :: Changed group property from current_value to new_value set :: - set property to new value, property was not set bevore + set property to new value, property was not set before EXAMPLES From 4fce4a631c8f2603cddd9f2065ec13a599fc3f21 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 22 May 2016 09:22:39 +0200 Subject: [PATCH 0126/1332] Add -f option for reading hosts from file or stdin. --- cdist/config.py | 32 ++++++++++++++++++++++++++++++-- docs/man/man1/cdist.text | 10 +++++++++- scripts/cdist | 25 +++++++++++++++++++------ 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index bba9bfcb..fd08d460 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -53,6 +53,21 @@ class Config(object): self.local.create_files_dirs() self.remote.create_files_dirs() + @staticmethod + def hosts(source): + """Yield hosts from source. + Source can be a sequence or filename (stdin if \'-\'). + In case of filename each line represents one host. + """ + if isinstance(source, str): + import fileinput + for host in fileinput.input(files=(source)): + yield host.strip() # remove leading and trailing whitespace + else: + for host in source: + yield host + + @classmethod def commandline(cls, args): """Configure remote system""" @@ -60,6 +75,12 @@ class Config(object): # FIXME: Refactor relict - remove later log = logging.getLogger("cdist") + + if args.manifest == '-' and args.hostfile == '-': + raise cdist.Error("Cannot read both, manifest and host file, from stdin") + # if no host source is specified then read hosts from stdin + if not (args.hostfile or args.host): + args.hostfile = '-' initial_manifest_tempfile = None if args.manifest == '-': @@ -79,8 +100,15 @@ class Config(object): process = {} failed_hosts = [] time_start = time.time() + + hostcnt = 0 + if args.host: + host_source = args.host + else: + host_source = args.hostfile - for host in args.host: + for host in cls.hosts(host_source): + hostcnt += 1 if args.parallel: log.debug("Creating child process for %s", host) process[host] = multiprocessing.Process(target=cls.onehost, args=(host, args, True)) @@ -101,7 +129,7 @@ class Config(object): failed_hosts.append(host) time_end = time.time() - log.info("Total processing time for %s host(s): %s", len(args.host), + log.info("Total processing time for %s host(s): %s", hostcnt, (time_end - time_start)) if len(failed_hosts) > 0: diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index e29ae3ae..ed2ce805 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -14,7 +14,7 @@ cdist [-h] [-d] [-v] [-V] {banner,config,shell} ... cdist banner [-h] [-d] [-v] -cdist config [-h] [-d] [-V] [-c CONF_DIR] [-i MANIFEST] [-p] [-s] host [host ...] +cdist config [-h] [-d] [-V] [-c CONF_DIR] [-f HOSTFILE] [-i MANIFEST] [-p] [-s] [host [host ...]] cdist shell [-h] [-d] [-v] [-s SHELL] @@ -63,6 +63,11 @@ Configure one or more hosts --conf-dir argument have higher precedence over those set through the environment variable. +-f HOSTFILE, --file HOSTFILE:: + Read hosts to operate on from specified file or from stdin if '-' + (each host on separate line). If no host or host file is + specified then, by default, read hosts from stdin. + -i MANIFEST, --initial-manifest MANIFEST:: Path to a cdist manifest or - to read from stdin @@ -105,6 +110,9 @@ EXAMPLES --remote-copy /path/to/my/remote/copy \ -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch +# Configure hosts in parallel by reading hosts from file loadbalancers +% cdist config -f loadbalancers + # Display banner cdist banner diff --git a/scripts/cdist b/scripts/cdist index 8e22aacb..0cfd01d6 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -67,12 +67,14 @@ def commandline(): action='store_true', default=False) # Main subcommand parser - parser['main'] = argparse.ArgumentParser(description='cdist ' + cdist.VERSION, + parser['main'] = argparse.ArgumentParser(description='cdist ' + + cdist.VERSION, parents=[parser['loglevel']]) parser['main'].add_argument('-V', '--version', help='Show version', action='version', version='%(prog)s ' + cdist.VERSION) - parser['sub'] = parser['main'].add_subparsers(title="Commands") + parser['sub'] = parser['main'].add_subparsers(title="Commands", + dest="command") # Banner parser['banner'] = parser['sub'].add_parser('banner', @@ -82,11 +84,16 @@ def commandline(): # Config parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) - parser['config'].add_argument('host', nargs='+', + parser['config'].add_argument('host', nargs='*', help='one or more hosts to operate on') parser['config'].add_argument('-c', '--conf-dir', - help='Add configuration directory (can be repeated, last one wins)', - action='append') + help=('Add configuration directory (can be repeated, ' + 'last one wins)'), action='append') + parser['config'].add_argument('-f', '--file', + help=('Read hosts to operate on from specified file or from stdin ' + 'if \'-\' (each host on separate line). If no host or host ' + 'file is specified then, by default, read hosts from stdin.'), + dest='hostfile', required=False) parser['config'].add_argument('-i', '--initial-manifest', help='Path to a cdist manifest or \'-\' to read from stdin.', dest='manifest', required=False) @@ -108,7 +115,8 @@ def commandline(): action='store', dest='remote_copy', default=os.environ.get('CDIST_REMOTE_COPY')) parser['config'].add_argument('--remote-exec', - help='Command to use for remote execution (should behave like ssh)', + help=('Command to use for remote execution ' + '(should behave like ssh)'), action='store', dest='remote_exec', default=os.environ.get('CDIST_REMOTE_EXEC')) parser['config'].set_defaults(func=cdist.config.Config.commandline) @@ -147,6 +155,11 @@ def commandline(): if args_dict['remote_copy'] is None: args.remote_copy = cdist.REMOTE_COPY + mux_opts + if args.command == 'config': + if args.manifest == '-' and args.hostfile == '-': + print('cdist config: error: cannot read both, manifest and host file, from stdin') + sys.exit(1) + log.debug(args) log.info("version %s" % cdist.VERSION) From fa5175fee5e0cd1ed2aa7d8b3d63b39cc3977eec Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 22 May 2016 09:45:08 +0200 Subject: [PATCH 0127/1332] Allow both hosts sources: command line args and file. --- cdist/config.py | 26 +++++++++++++++----------- docs/man/man1/cdist.text | 7 ++++--- scripts/cdist | 7 ++++--- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index fd08d460..f5e62ce1 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -26,6 +26,7 @@ import shutil import sys import time import pprint +import itertools import cdist @@ -61,11 +62,17 @@ class Config(object): """ if isinstance(source, str): import fileinput - for host in fileinput.input(files=(source)): - yield host.strip() # remove leading and trailing whitespace + try: + for host in fileinput.input(files=(source)): + # remove leading and trailing whitespace + yield host.strip() + except (IOError, OSError) as e: + raise cdist.Error("Error reading hosts from \'{}\'".format( + source)) else: - for host in source: - yield host + if source: + for host in source: + yield host @classmethod @@ -77,7 +84,8 @@ class Config(object): log = logging.getLogger("cdist") if args.manifest == '-' and args.hostfile == '-': - raise cdist.Error("Cannot read both, manifest and host file, from stdin") + raise cdist.Error(("Cannot read both, manifest and host file, " + "from stdin")) # if no host source is specified then read hosts from stdin if not (args.hostfile or args.host): args.hostfile = '-' @@ -102,12 +110,8 @@ class Config(object): time_start = time.time() hostcnt = 0 - if args.host: - host_source = args.host - else: - host_source = args.hostfile - - for host in cls.hosts(host_source): + for host in itertools.chain(cls.hosts(args.host), + cls.hosts(args.hostfile)): hostcnt += 1 if args.parallel: log.debug("Creating child process for %s", host) diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index ed2ce805..4e45ae81 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -64,9 +64,10 @@ Configure one or more hosts environment variable. -f HOSTFILE, --file HOSTFILE:: - Read hosts to operate on from specified file or from stdin if '-' - (each host on separate line). If no host or host file is - specified then, by default, read hosts from stdin. + Read additional hosts to operate on from specified file + or from stdin if '-' (each host on separate line). + If no host or host file is specified then, by default, + read hosts from stdin. -i MANIFEST, --initial-manifest MANIFEST:: Path to a cdist manifest or - to read from stdin diff --git a/scripts/cdist b/scripts/cdist index 0cfd01d6..ccdb5232 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -90,9 +90,10 @@ def commandline(): help=('Add configuration directory (can be repeated, ' 'last one wins)'), action='append') parser['config'].add_argument('-f', '--file', - help=('Read hosts to operate on from specified file or from stdin ' - 'if \'-\' (each host on separate line). If no host or host ' - 'file is specified then, by default, read hosts from stdin.'), + help=('Read additional hosts to operate on from specified file ' + 'or from stdin if \'-\' (each host on separate line). ' + 'If no host or host file is specified then, by default, ' + 'read hosts from stdin.'), dest='hostfile', required=False) parser['config'].add_argument('-i', '--initial-manifest', help='Path to a cdist manifest or \'-\' to read from stdin.', From cf32b669ff0661f5f3a407614b93c05b86321a07 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 20 May 2016 08:50:56 +0200 Subject: [PATCH 0128/1332] Write sphinx rst docs. --- .gitignore | 3 + Makefile | 76 ++--- .../conf/type/__apt_key/{man.text => man.rst} | 39 +-- .../type/__apt_key_uri/{man.text => man.rst} | 27 +- .../__apt_norecommends/{man.text => man.rst} | 15 +- .../conf/type/__apt_ppa/{man.text => man.rst} | 27 +- .../type/__apt_source/{man.text => man.rst} | 43 ++- .../__apt_update_index/{man.text => man.rst} | 15 +- cdist/conf/type/__block/{man.text => man.rst} | 53 ++- .../__ccollect_source/{man.text => man.rst} | 37 +-- cdist/conf/type/__cdist/{man.text => man.rst} | 27 +- .../type/__cdistmarker/{man.text => man.rst} | 25 +- .../type/__config_file/{man.text => man.rst} | 37 +-- .../conf/type/__consul/{man.text => man.rst} | 27 +- .../type/__consul_agent/{man.text => man.rst} | 168 ++++++---- .../type/__consul_check/{man.text => man.rst} | 51 +-- .../__consul_reload/{man.text => man.rst} | 15 +- .../__consul_service/{man.text => man.rst} | 56 ++-- .../__consul_template/{man.text => man.rst} | 94 +++--- .../{man.text => man.rst} | 50 +-- .../{man.text => man.rst} | 47 +-- .../{man.text => man.rst} | 38 +-- .../__consul_watch_key/{man.text => man.rst} | 34 +- .../{man.text => man.rst} | 34 +- .../{man.text => man.rst} | 29 +- .../{man.text => man.rst} | 57 ++-- .../{man.text => man.rst} | 29 +- cdist/conf/type/__cron/{man.text => man.rst} | 55 ++- .../{man.text => man.rst} | 31 +- .../type/__directory/{man.text => man.rst} | 66 ++-- .../conf/type/__dog_vdi/{man.text => man.rst} | 33 +- cdist/conf/type/__file/man.rst | 109 ++++++ cdist/conf/type/__file/man.text | 109 ------ cdist/conf/type/__firewalld_rule/man.rst | 75 +++++ cdist/conf/type/__firewalld_rule/man.text | 78 ----- cdist/conf/type/__git/{man.text => man.rst} | 31 +- cdist/conf/type/__group/{man.text => man.rst} | 51 ++- .../type/__hostname/{man.text => man.rst} | 25 +- .../__iptables_apply/{man.text => man.rst} | 11 +- cdist/conf/type/__iptables_rule/man.rst | 60 ++++ cdist/conf/type/__iptables_rule/man.text | 64 ---- cdist/conf/type/__issue/{man.text => man.rst} | 21 +- cdist/conf/type/__jail/{man.text => man.rst} | 77 +++-- .../type/__key_value/{man.text => man.rst} | 55 ++- cdist/conf/type/__line/{man.text => man.rst} | 39 +-- cdist/conf/type/__link/{man.text => man.rst} | 39 +-- .../conf/type/__locale/{man.text => man.rst} | 27 +- cdist/conf/type/__motd/{man.text => man.rst} | 23 +- cdist/conf/type/__mount/{man.text => man.rst} | 49 ++- .../__mysql_database/{man.text => man.rst} | 21 +- .../conf/type/__package/{man.text => man.rst} | 38 +-- .../type/__package_apt/{man.text => man.rst} | 33 +- .../__package_emerge/{man.text => man.rst} | 35 +- .../{man.text => man.rst} | 26 +- .../__package_luarocks/{man.text => man.rst} | 27 +- .../type/__package_opkg/{man.text => man.rst} | 29 +- .../__package_pacman/{man.text => man.rst} | 31 +- .../type/__package_pip/{man.text => man.rst} | 35 +- .../{man.text => man.rst} | 41 ++- cdist/conf/type/__package_pkg_openbsd/man.rst | 63 ++++ .../conf/type/__package_pkg_openbsd/man.text | 66 ---- .../{man.text => man.rst} | 59 ++-- .../__package_rubygem/{man.text => man.rst} | 27 +- .../{man.text => man.rst} | 30 +- .../{man.text => man.rst} | 30 +- .../type/__package_yum/{man.text => man.rst} | 37 +-- .../__package_zypper/{man.text => man.rst} | 43 ++- .../type/__pacman_conf/{man.text => man.rst} | 36 +- .../{man.text => man.rst} | 22 +- cdist/conf/type/__pf_apply/man.rst | 53 +++ cdist/conf/type/__pf_apply/man.text | 52 --- .../type/__pf_ruleset/{man.text => man.rst} | 26 +- .../conf/type/__postfix/{man.text => man.rst} | 15 +- .../__postfix_master/{man.text => man.rst} | 59 ++-- .../__postfix_postconf/{man.text => man.rst} | 20 +- .../__postfix_postmap/{man.text => man.rst} | 15 +- .../__postfix_reload/{man.text => man.rst} | 15 +- .../__postgres_database/{man.text => man.rst} | 21 +- .../__postgres_role/{man.text => man.rst} | 37 +-- cdist/conf/type/__process/man.rst | 67 ++++ cdist/conf/type/__process/man.text | 70 ---- cdist/conf/type/__pyvenv/man.rst | 78 +++++ cdist/conf/type/__pyvenv/man.text | 80 ----- .../type/__qemu_img/{man.text => man.rst} | 25 +- cdist/conf/type/__rbenv/{man.text => man.rst} | 29 +- cdist/conf/type/__rsync/{man.text => man.rst} | 69 ++-- cdist/conf/type/__rvm/{man.text => man.rst} | 29 +- cdist/conf/type/__rvm_gem/man.rst | 54 +++ cdist/conf/type/__rvm_gem/man.text | 57 ---- cdist/conf/type/__rvm_gemset/man.rst | 52 +++ cdist/conf/type/__rvm_gemset/man.text | 55 --- cdist/conf/type/__rvm_ruby/man.rst | 53 +++ cdist/conf/type/__rvm_ruby/man.text | 54 --- .../{man.text => man.rst} | 43 ++- .../{man.text => man.rst} | 95 +++--- .../type/__ssh_dot_ssh/{man.text => man.rst} | 22 +- .../type/__staged_file/{man.text => man.rst} | 79 ++--- .../__start_on_boot/{man.text => man.rst} | 34 +- .../type/__timezone/{man.text => man.rst} | 21 +- .../{man.text => man.rst} | 21 +- cdist/conf/type/__user/{man.text => man.rst} | 67 ++-- .../type/__user_groups/{man.text => man.rst} | 27 +- cdist/conf/type/__yum_repo/man.rst | 121 +++++++ cdist/conf/type/__yum_repo/man.text | 91 ----- cdist/conf/type/__zypper_repo/man.rst | 70 ++++ cdist/conf/type/__zypper_repo/man.text | 73 ---- cdist/conf/type/__zypper_service/man.rst | 63 ++++ cdist/conf/type/__zypper_service/man.text | 67 ---- docs/man/Makefile | 230 +++++++++++++ ...ference.text.sh => cdist-reference.rst.sh} | 107 +++--- docs/man/conf.py | 305 +++++++++++++++++ docs/man/index.rst | 12 + docs/man/man1/{cdist.text => cdist.rst} | 116 ++++--- docs/man/man7/cdist-best-practice.rst | 238 +++++++++++++ docs/man/man7/cdist-best-practice.text | 247 -------------- ...ist-bootstrap.text => cdist-bootstrap.rst} | 101 +++--- ...cdist-explorer.text => cdist-explorer.rst} | 53 +-- .../{cdist-hacker.text => cdist-hacker.rst} | 104 +++--- ...cdist-manifest.text => cdist-manifest.rst} | 220 ++++++------ docs/man/man7/cdist-messaging.rst | 111 +++++++ docs/man/man7/cdist-messaging.text | 114 ------- ...t-quickstart.text => cdist-quickstart.rst} | 76 ++--- docs/man/man7/cdist-reference.rst | 313 ++++++++++++++++++ ...c-copy.text => cdist-remote-exec-copy.rst} | 17 +- .../{cdist-stages.text => cdist-stages.rst} | 11 +- ...hooting.text => cdist-troubleshooting.rst} | 52 ++- ...cdist-tutorial.text => cdist-tutorial.rst} | 33 +- .../man7/{cdist-type.text => cdist-type.rst} | 226 ++++++------- docs/man/man7/cdist-type__apt_key.rst | 1 + docs/man/man7/cdist-type__apt_key_uri.rst | 1 + .../man/man7/cdist-type__apt_norecommends.rst | 1 + docs/man/man7/cdist-type__apt_ppa.rst | 1 + docs/man/man7/cdist-type__apt_source.rst | 1 + .../man/man7/cdist-type__apt_update_index.rst | 1 + docs/man/man7/cdist-type__block.rst | 1 + docs/man/man7/cdist-type__ccollect_source.rst | 1 + docs/man/man7/cdist-type__cdist.rst | 1 + docs/man/man7/cdist-type__cdistmarker.rst | 1 + docs/man/man7/cdist-type__config_file.rst | 1 + docs/man/man7/cdist-type__consul.rst | 1 + docs/man/man7/cdist-type__consul_agent.rst | 1 + docs/man/man7/cdist-type__consul_check.rst | 1 + docs/man/man7/cdist-type__consul_reload.rst | 1 + docs/man/man7/cdist-type__consul_service.rst | 1 + docs/man/man7/cdist-type__consul_template.rst | 1 + .../cdist-type__consul_template_template.rst | 1 + .../man7/cdist-type__consul_watch_checks.rst | 1 + .../man7/cdist-type__consul_watch_event.rst | 1 + .../man/man7/cdist-type__consul_watch_key.rst | 1 + .../cdist-type__consul_watch_keyprefix.rst | 1 + .../man7/cdist-type__consul_watch_nodes.rst | 1 + .../man7/cdist-type__consul_watch_service.rst | 1 + .../cdist-type__consul_watch_services.rst | 1 + docs/man/man7/cdist-type__cron.rst | 1 + .../cdist-type__debconf_set_selections.rst | 1 + docs/man/man7/cdist-type__directory.rst | 1 + docs/man/man7/cdist-type__dog_vdi.rst | 1 + docs/man/man7/cdist-type__file.rst | 1 + docs/man/man7/cdist-type__firewalld_rule.rst | 1 + docs/man/man7/cdist-type__git.rst | 1 + docs/man/man7/cdist-type__group.rst | 1 + docs/man/man7/cdist-type__hostname.rst | 1 + docs/man/man7/cdist-type__iptables_apply.rst | 1 + docs/man/man7/cdist-type__iptables_rule.rst | 1 + docs/man/man7/cdist-type__issue.rst | 1 + docs/man/man7/cdist-type__jail.rst | 1 + docs/man/man7/cdist-type__key_value.rst | 1 + docs/man/man7/cdist-type__line.rst | 1 + docs/man/man7/cdist-type__link.rst | 1 + docs/man/man7/cdist-type__locale.rst | 1 + docs/man/man7/cdist-type__motd.rst | 1 + docs/man/man7/cdist-type__mount.rst | 1 + docs/man/man7/cdist-type__mysql_database.rst | 1 + docs/man/man7/cdist-type__package.rst | 1 + docs/man/man7/cdist-type__package_apt.rst | 1 + docs/man/man7/cdist-type__package_emerge.rst | 1 + ...dist-type__package_emerge_dependencies.rst | 1 + .../man/man7/cdist-type__package_luarocks.rst | 1 + docs/man/man7/cdist-type__package_opkg.rst | 1 + docs/man/man7/cdist-type__package_pacman.rst | 1 + docs/man/man7/cdist-type__package_pip.rst | 1 + .../man7/cdist-type__package_pkg_freebsd.rst | 1 + .../man7/cdist-type__package_pkg_openbsd.rst | 1 + .../cdist-type__package_pkgng_freebsd.rst | 1 + docs/man/man7/cdist-type__package_rubygem.rst | 1 + .../man7/cdist-type__package_update_index.rst | 1 + .../man7/cdist-type__package_upgrade_all.rst | 1 + docs/man/man7/cdist-type__package_yum.rst | 1 + docs/man/man7/cdist-type__package_zypper.rst | 1 + docs/man/man7/cdist-type__pacman_conf.rst | 1 + .../cdist-type__pacman_conf_integrate.rst | 1 + docs/man/man7/cdist-type__pf_apply.rst | 1 + docs/man/man7/cdist-type__pf_ruleset.rst | 1 + docs/man/man7/cdist-type__postfix.rst | 1 + docs/man/man7/cdist-type__postfix_master.rst | 1 + .../man/man7/cdist-type__postfix_postconf.rst | 1 + docs/man/man7/cdist-type__postfix_postmap.rst | 1 + docs/man/man7/cdist-type__postfix_reload.rst | 1 + .../man7/cdist-type__postgres_database.rst | 1 + docs/man/man7/cdist-type__postgres_role.rst | 1 + docs/man/man7/cdist-type__process.rst | 1 + docs/man/man7/cdist-type__pyvenv.rst | 1 + docs/man/man7/cdist-type__qemu_img.rst | 1 + docs/man/man7/cdist-type__rbenv.rst | 1 + docs/man/man7/cdist-type__rsync.rst | 1 + docs/man/man7/cdist-type__rvm.rst | 1 + docs/man/man7/cdist-type__rvm_gem.rst | 1 + docs/man/man7/cdist-type__rvm_gemset.rst | 1 + docs/man/man7/cdist-type__rvm_ruby.rst | 1 + .../man7/cdist-type__ssh_authorized_key.rst | 1 + .../man7/cdist-type__ssh_authorized_keys.rst | 1 + docs/man/man7/cdist-type__ssh_dot_ssh.rst | 1 + docs/man/man7/cdist-type__staged_file.rst | 1 + docs/man/man7/cdist-type__start_on_boot.rst | 1 + docs/man/man7/cdist-type__timezone.rst | 1 + .../man7/cdist-type__update_alternatives.rst | 1 + docs/man/man7/cdist-type__user.rst | 1 + docs/man/man7/cdist-type__user_groups.rst | 1 + docs/man/man7/cdist-type__yum_repo.rst | 1 + docs/man/man7/cdist-type__zypper_repo.rst | 1 + docs/man/man7/cdist-type__zypper_service.rst | 1 + .../__autofs/{man.text => man.rst} | 15 +- .../__autofs_map/{man.text => man.rst} | 43 ++- .../__autofs_reload/{man.text => man.rst} | 15 +- .../__init_script/{man.text => man.rst} | 28 +- .../__mysql_server/{man.text => man.rst} | 35 +- .../__nfs_client/{man.text => man.rst} | 15 +- .../__nfs_export/{man.text => man.rst} | 27 +- .../__nfs_server/{man.text => man.rst} | 15 +- .../__rsyncer/{man.text => man.rst} | 29 +- .../__run_command/man.rst | 66 ++++ .../__run_command/man.text | 70 ---- 232 files changed, 4430 insertions(+), 3696 deletions(-) rename cdist/conf/type/__apt_key/{man.text => man.rst} (52%) rename cdist/conf/type/__apt_key_uri/{man.text => man.rst} (61%) rename cdist/conf/type/__apt_norecommends/{man.text => man.rst} (63%) rename cdist/conf/type/__apt_ppa/{man.text => man.rst} (55%) rename cdist/conf/type/__apt_source/{man.text => man.rst} (60%) rename cdist/conf/type/__apt_update_index/{man.text => man.rst} (65%) rename cdist/conf/type/__block/{man.text => man.rst} (66%) rename cdist/conf/type/__ccollect_source/{man.text => man.rst} (65%) rename cdist/conf/type/__cdist/{man.text => man.rst} (67%) rename cdist/conf/type/__cdistmarker/{man.text => man.rst} (67%) rename cdist/conf/type/__config_file/{man.text => man.rst} (57%) rename cdist/conf/type/__consul/{man.text => man.rst} (71%) rename cdist/conf/type/__consul_agent/{man.text => man.rst} (61%) rename cdist/conf/type/__consul_check/{man.text => man.rst} (64%) rename cdist/conf/type/__consul_reload/{man.text => man.rst} (65%) rename cdist/conf/type/__consul_service/{man.text => man.rst} (66%) rename cdist/conf/type/__consul_template/{man.text => man.rst} (82%) rename cdist/conf/type/__consul_template_template/{man.text => man.rst} (59%) rename cdist/conf/type/__consul_watch_checks/{man.text => man.rst} (62%) rename cdist/conf/type/__consul_watch_event/{man.text => man.rst} (65%) rename cdist/conf/type/__consul_watch_key/{man.text => man.rst} (68%) rename cdist/conf/type/__consul_watch_keyprefix/{man.text => man.rst} (68%) rename cdist/conf/type/__consul_watch_nodes/{man.text => man.rst} (69%) rename cdist/conf/type/__consul_watch_service/{man.text => man.rst} (60%) rename cdist/conf/type/__consul_watch_services/{man.text => man.rst} (68%) rename cdist/conf/type/__cron/{man.text => man.rst} (62%) rename cdist/conf/type/__debconf_set_selections/{man.text => man.rst} (52%) rename cdist/conf/type/__directory/{man.text => man.rst} (57%) rename cdist/conf/type/__dog_vdi/{man.text => man.rst} (50%) create mode 100644 cdist/conf/type/__file/man.rst delete mode 100644 cdist/conf/type/__file/man.text create mode 100644 cdist/conf/type/__firewalld_rule/man.rst delete mode 100644 cdist/conf/type/__firewalld_rule/man.text rename cdist/conf/type/__git/{man.text => man.rst} (60%) rename cdist/conf/type/__group/{man.text => man.rst} (53%) rename cdist/conf/type/__hostname/{man.text => man.rst} (63%) rename cdist/conf/type/__iptables_apply/{man.text => man.rst} (83%) create mode 100644 cdist/conf/type/__iptables_rule/man.rst delete mode 100644 cdist/conf/type/__iptables_rule/man.text rename cdist/conf/type/__issue/{man.text => man.rst} (62%) rename cdist/conf/type/__jail/{man.text => man.rst} (64%) rename cdist/conf/type/__key_value/{man.text => man.rst} (64%) rename cdist/conf/type/__line/{man.text => man.rst} (59%) rename cdist/conf/type/__link/{man.text => man.rst} (51%) rename cdist/conf/type/__locale/{man.text => man.rst} (53%) rename cdist/conf/type/__motd/{man.text => man.rst} (63%) rename cdist/conf/type/__mount/{man.text => man.rst} (66%) rename cdist/conf/type/__mysql_database/{man.text => man.rst} (65%) rename cdist/conf/type/__package/{man.text => man.rst} (61%) rename cdist/conf/type/__package_apt/{man.text => man.rst} (58%) rename cdist/conf/type/__package_emerge/{man.text => man.rst} (58%) rename cdist/conf/type/__package_emerge_dependencies/{man.text => man.rst} (55%) rename cdist/conf/type/__package_luarocks/{man.text => man.rst} (59%) rename cdist/conf/type/__package_opkg/{man.text => man.rst} (57%) rename cdist/conf/type/__package_pacman/{man.text => man.rst} (54%) rename cdist/conf/type/__package_pip/{man.text => man.rst} (55%) rename cdist/conf/type/__package_pkg_freebsd/{man.text => man.rst} (53%) create mode 100644 cdist/conf/type/__package_pkg_openbsd/man.rst delete mode 100644 cdist/conf/type/__package_pkg_openbsd/man.text rename cdist/conf/type/__package_pkgng_freebsd/{man.text => man.rst} (60%) rename cdist/conf/type/__package_rubygem/{man.text => man.rst} (60%) rename cdist/conf/type/__package_update_index/{man.text => man.rst} (58%) rename cdist/conf/type/__package_upgrade_all/{man.text => man.rst} (58%) rename cdist/conf/type/__package_yum/{man.text => man.rst} (54%) rename cdist/conf/type/__package_zypper/{man.text => man.rst} (55%) rename cdist/conf/type/__pacman_conf/{man.text => man.rst} (59%) rename cdist/conf/type/__pacman_conf_integrate/{man.text => man.rst} (57%) create mode 100644 cdist/conf/type/__pf_apply/man.rst delete mode 100644 cdist/conf/type/__pf_apply/man.text rename cdist/conf/type/__pf_ruleset/{man.text => man.rst} (57%) rename cdist/conf/type/__postfix/{man.text => man.rst} (66%) rename cdist/conf/type/__postfix_master/{man.text => man.rst} (51%) rename cdist/conf/type/__postfix_postconf/{man.text => man.rst} (64%) rename cdist/conf/type/__postfix_postmap/{man.text => man.rst} (62%) rename cdist/conf/type/__postfix_reload/{man.text => man.rst} (63%) rename cdist/conf/type/__postgres_database/{man.text => man.rst} (60%) rename cdist/conf/type/__postgres_role/{man.text => man.rst} (59%) create mode 100644 cdist/conf/type/__process/man.rst delete mode 100644 cdist/conf/type/__process/man.text create mode 100755 cdist/conf/type/__pyvenv/man.rst delete mode 100755 cdist/conf/type/__pyvenv/man.text rename cdist/conf/type/__qemu_img/{man.text => man.rst} (59%) rename cdist/conf/type/__rbenv/{man.text => man.rst} (54%) rename cdist/conf/type/__rsync/{man.text => man.rst} (61%) rename cdist/conf/type/__rvm/{man.text => man.rst} (52%) create mode 100644 cdist/conf/type/__rvm_gem/man.rst delete mode 100644 cdist/conf/type/__rvm_gem/man.text create mode 100644 cdist/conf/type/__rvm_gemset/man.rst delete mode 100644 cdist/conf/type/__rvm_gemset/man.text create mode 100644 cdist/conf/type/__rvm_ruby/man.rst delete mode 100644 cdist/conf/type/__rvm_ruby/man.text rename cdist/conf/type/__ssh_authorized_key/{man.text => man.rst} (61%) rename cdist/conf/type/__ssh_authorized_keys/{man.text => man.rst} (51%) rename cdist/conf/type/__ssh_dot_ssh/{man.text => man.rst} (57%) rename cdist/conf/type/__staged_file/{man.text => man.rst} (69%) rename cdist/conf/type/__start_on_boot/{man.text => man.rst} (57%) rename cdist/conf/type/__timezone/{man.text => man.rst} (56%) rename cdist/conf/type/__update_alternatives/{man.text => man.rst} (61%) rename cdist/conf/type/__user/{man.text => man.rst} (56%) rename cdist/conf/type/__user_groups/{man.text => man.rst} (60%) create mode 100644 cdist/conf/type/__yum_repo/man.rst delete mode 100644 cdist/conf/type/__yum_repo/man.text create mode 100644 cdist/conf/type/__zypper_repo/man.rst delete mode 100644 cdist/conf/type/__zypper_repo/man.text create mode 100644 cdist/conf/type/__zypper_service/man.rst delete mode 100644 cdist/conf/type/__zypper_service/man.text create mode 100644 docs/man/Makefile rename docs/man/{cdist-reference.text.sh => cdist-reference.rst.sh} (85%) create mode 100644 docs/man/conf.py create mode 100644 docs/man/index.rst rename docs/man/man1/{cdist.text => cdist.rst} (60%) create mode 100644 docs/man/man7/cdist-best-practice.rst delete mode 100644 docs/man/man7/cdist-best-practice.text rename docs/man/man7/{cdist-bootstrap.text => cdist-bootstrap.rst} (59%) rename docs/man/man7/{cdist-explorer.text => cdist-explorer.rst} (59%) rename docs/man/man7/{cdist-hacker.text => cdist-hacker.rst} (60%) rename docs/man/man7/{cdist-manifest.text => cdist-manifest.rst} (52%) create mode 100644 docs/man/man7/cdist-messaging.rst delete mode 100644 docs/man/man7/cdist-messaging.text rename docs/man/man7/{cdist-quickstart.text => cdist-quickstart.rst} (50%) create mode 100644 docs/man/man7/cdist-reference.rst rename docs/man/man7/{cdist-remote-exec-copy.text => cdist-remote-exec-copy.rst} (84%) rename docs/man/man7/{cdist-stages.text => cdist-stages.rst} (95%) rename docs/man/man7/{cdist-troubleshooting.text => cdist-troubleshooting.rst} (52%) rename docs/man/man7/{cdist-tutorial.text => cdist-tutorial.rst} (78%) rename docs/man/man7/{cdist-type.text => cdist-type.rst} (54%) create mode 120000 docs/man/man7/cdist-type__apt_key.rst create mode 120000 docs/man/man7/cdist-type__apt_key_uri.rst create mode 120000 docs/man/man7/cdist-type__apt_norecommends.rst create mode 120000 docs/man/man7/cdist-type__apt_ppa.rst create mode 120000 docs/man/man7/cdist-type__apt_source.rst create mode 120000 docs/man/man7/cdist-type__apt_update_index.rst create mode 120000 docs/man/man7/cdist-type__block.rst create mode 120000 docs/man/man7/cdist-type__ccollect_source.rst create mode 120000 docs/man/man7/cdist-type__cdist.rst create mode 120000 docs/man/man7/cdist-type__cdistmarker.rst create mode 120000 docs/man/man7/cdist-type__config_file.rst create mode 120000 docs/man/man7/cdist-type__consul.rst create mode 120000 docs/man/man7/cdist-type__consul_agent.rst create mode 120000 docs/man/man7/cdist-type__consul_check.rst create mode 120000 docs/man/man7/cdist-type__consul_reload.rst create mode 120000 docs/man/man7/cdist-type__consul_service.rst create mode 120000 docs/man/man7/cdist-type__consul_template.rst create mode 120000 docs/man/man7/cdist-type__consul_template_template.rst create mode 120000 docs/man/man7/cdist-type__consul_watch_checks.rst create mode 120000 docs/man/man7/cdist-type__consul_watch_event.rst create mode 120000 docs/man/man7/cdist-type__consul_watch_key.rst create mode 120000 docs/man/man7/cdist-type__consul_watch_keyprefix.rst create mode 120000 docs/man/man7/cdist-type__consul_watch_nodes.rst create mode 120000 docs/man/man7/cdist-type__consul_watch_service.rst create mode 120000 docs/man/man7/cdist-type__consul_watch_services.rst create mode 120000 docs/man/man7/cdist-type__cron.rst create mode 120000 docs/man/man7/cdist-type__debconf_set_selections.rst create mode 120000 docs/man/man7/cdist-type__directory.rst create mode 120000 docs/man/man7/cdist-type__dog_vdi.rst create mode 120000 docs/man/man7/cdist-type__file.rst create mode 120000 docs/man/man7/cdist-type__firewalld_rule.rst create mode 120000 docs/man/man7/cdist-type__git.rst create mode 120000 docs/man/man7/cdist-type__group.rst create mode 120000 docs/man/man7/cdist-type__hostname.rst create mode 120000 docs/man/man7/cdist-type__iptables_apply.rst create mode 120000 docs/man/man7/cdist-type__iptables_rule.rst create mode 120000 docs/man/man7/cdist-type__issue.rst create mode 120000 docs/man/man7/cdist-type__jail.rst create mode 120000 docs/man/man7/cdist-type__key_value.rst create mode 120000 docs/man/man7/cdist-type__line.rst create mode 120000 docs/man/man7/cdist-type__link.rst create mode 120000 docs/man/man7/cdist-type__locale.rst create mode 120000 docs/man/man7/cdist-type__motd.rst create mode 120000 docs/man/man7/cdist-type__mount.rst create mode 120000 docs/man/man7/cdist-type__mysql_database.rst create mode 120000 docs/man/man7/cdist-type__package.rst create mode 120000 docs/man/man7/cdist-type__package_apt.rst create mode 120000 docs/man/man7/cdist-type__package_emerge.rst create mode 120000 docs/man/man7/cdist-type__package_emerge_dependencies.rst create mode 120000 docs/man/man7/cdist-type__package_luarocks.rst create mode 120000 docs/man/man7/cdist-type__package_opkg.rst create mode 120000 docs/man/man7/cdist-type__package_pacman.rst create mode 120000 docs/man/man7/cdist-type__package_pip.rst create mode 120000 docs/man/man7/cdist-type__package_pkg_freebsd.rst create mode 120000 docs/man/man7/cdist-type__package_pkg_openbsd.rst create mode 120000 docs/man/man7/cdist-type__package_pkgng_freebsd.rst create mode 120000 docs/man/man7/cdist-type__package_rubygem.rst create mode 120000 docs/man/man7/cdist-type__package_update_index.rst create mode 120000 docs/man/man7/cdist-type__package_upgrade_all.rst create mode 120000 docs/man/man7/cdist-type__package_yum.rst create mode 120000 docs/man/man7/cdist-type__package_zypper.rst create mode 120000 docs/man/man7/cdist-type__pacman_conf.rst create mode 120000 docs/man/man7/cdist-type__pacman_conf_integrate.rst create mode 120000 docs/man/man7/cdist-type__pf_apply.rst create mode 120000 docs/man/man7/cdist-type__pf_ruleset.rst create mode 120000 docs/man/man7/cdist-type__postfix.rst create mode 120000 docs/man/man7/cdist-type__postfix_master.rst create mode 120000 docs/man/man7/cdist-type__postfix_postconf.rst create mode 120000 docs/man/man7/cdist-type__postfix_postmap.rst create mode 120000 docs/man/man7/cdist-type__postfix_reload.rst create mode 120000 docs/man/man7/cdist-type__postgres_database.rst create mode 120000 docs/man/man7/cdist-type__postgres_role.rst create mode 120000 docs/man/man7/cdist-type__process.rst create mode 120000 docs/man/man7/cdist-type__pyvenv.rst create mode 120000 docs/man/man7/cdist-type__qemu_img.rst create mode 120000 docs/man/man7/cdist-type__rbenv.rst create mode 120000 docs/man/man7/cdist-type__rsync.rst create mode 120000 docs/man/man7/cdist-type__rvm.rst create mode 120000 docs/man/man7/cdist-type__rvm_gem.rst create mode 120000 docs/man/man7/cdist-type__rvm_gemset.rst create mode 120000 docs/man/man7/cdist-type__rvm_ruby.rst create mode 120000 docs/man/man7/cdist-type__ssh_authorized_key.rst create mode 120000 docs/man/man7/cdist-type__ssh_authorized_keys.rst create mode 120000 docs/man/man7/cdist-type__ssh_dot_ssh.rst create mode 120000 docs/man/man7/cdist-type__staged_file.rst create mode 120000 docs/man/man7/cdist-type__start_on_boot.rst create mode 120000 docs/man/man7/cdist-type__timezone.rst create mode 120000 docs/man/man7/cdist-type__update_alternatives.rst create mode 120000 docs/man/man7/cdist-type__user.rst create mode 120000 docs/man/man7/cdist-type__user_groups.rst create mode 120000 docs/man/man7/cdist-type__yum_repo.rst create mode 120000 docs/man/man7/cdist-type__zypper_repo.rst create mode 120000 docs/man/man7/cdist-type__zypper_service.rst rename other/archived_types/__autofs/{man.text => man.rst} (65%) rename other/archived_types/__autofs_map/{man.text => man.rst} (62%) rename other/archived_types/__autofs_reload/{man.text => man.rst} (63%) rename other/types_submitted_for_inclusion/__init_script/{man.text => man.rst} (63%) rename other/types_submitted_for_inclusion/__mysql_server/{man.text => man.rst} (58%) rename other/types_submitted_for_inclusion/__nfs_client/{man.text => man.rst} (67%) rename other/types_submitted_for_inclusion/__nfs_export/{man.text => man.rst} (67%) rename other/types_submitted_for_inclusion/__nfs_server/{man.text => man.rst} (67%) rename other/types_submitted_for_inclusion/__rsyncer/{man.text => man.rst} (72%) create mode 100644 other/types_submitted_for_inclusion/__run_command/man.rst delete mode 100644 other/types_submitted_for_inclusion/__run_command/man.text diff --git a/.gitignore b/.gitignore index baf9b6f2..9c3594f7 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ MANIFEST dist/ cdist/version.py +#sphinx build dir +_build/ + # Packaging: Archlinux /PKGBUILD /cdist-*.pkg.tar.xz diff --git a/Makefile b/Makefile index d78eb1a1..e584fc63 100644 --- a/Makefile +++ b/Makefile @@ -18,15 +18,6 @@ # # -A2XM=a2x -f manpage --no-xmllint -a encoding=UTF-8 -A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 -# Create cross-links in html man pages -# We look for something like "cdist-type(7)" and make a href out of it -# The first matching group is the man page name and the second group -# is the man page section (1 or 7). The first three lines of the input -# (xml, DOCTYPE, head tags) are ignored, since the head tags contains -# the title of the page and should not contain a href. -CROSSLINK=sed -i '' '1,3!s/\([[:alnum:]_-]*\)(\([17]\))/&<\/a>/g' helper=./bin/build-helper MANDIR=docs/man @@ -45,6 +36,8 @@ CHANGELOG_FILE=docs/changelog PYTHON_VERSION=cdist/version.py +SPHINXM=make -C $(MANDIR) man +SPHINXH=make -C $(MANDIR) html ################################################################################ # Manpages # @@ -52,59 +45,42 @@ MAN1DSTDIR=$(MANDIR)/man1 MAN7DSTDIR=$(MANDIR)/man7 # Manpages #1: Types -# Use shell / ls to get complete list - $(TYPEDIR)/*/man.text does not work -MANTYPESRC=$(shell ls $(TYPEDIR)/*/man.text) - -# replace first path component +# Use shell / ls to get complete list - $(TYPEDIR)/*/man.rst does not work +MANTYPESRC=$(shell ls $(TYPEDIR)/*/man.rst) MANTYPEPREFIX=$(subst $(TYPEDIR)/,$(MAN7DSTDIR)/cdist-type,$(MANTYPESRC)) +MANTYPES=$(subst /man.rst,.rst,$(MANTYPEPREFIX)) -# replace man.text with .7 or .html -MANTYPEMAN=$(subst /man.text,.7,$(MANTYPEPREFIX)) -MANTYPEHTML=$(subst /man.text,.html,$(MANTYPEPREFIX)) -MANTYPEALL=$(MANTYPEMAN) $(MANTYPEHTML) - -# Link manpage so A2XH does not create man.html but correct named file -$(MAN7DSTDIR)/cdist-type%.text: $(TYPEDIR)/%/man.text +# Link manpage: do not create man.html but correct named file +$(MAN7DSTDIR)/cdist-type%.rst: $(TYPEDIR)/%/man.rst ln -sf "../../../$^" $@ # Manpages #2: reference -MANREF=$(MAN7DSTDIR)/cdist-reference.text -MANREFSH=$(MANDIR)/cdist-reference.text.sh -MANREFMAN=$(MANREF:.text=.7) -MANREFHTML=$(MANREF:.text=.html) -MANREFALL=$(MANREFMAN) $(MANREFHTML) +MANREF=$(MAN7DSTDIR)/cdist-reference.rst +MANREFSH=$(MANDIR)/cdist-reference.rst.sh $(MANREF): $(MANREFSH) $(MANREFSH) -# Manpages #3: static pages -MAN1STATIC=$(shell ls $(MAN1DSTDIR)/*.text) -MAN7STATIC=$(shell ls $(MAN7DSTDIR)/*.text) -MANSTATICMAN=$(MAN1STATIC:.text=.1) $(MAN7STATIC:.text=.7) -MANSTATICHTML=$(MAN1STATIC:.text=.html) $(MAN7STATIC:.text=.html) -MANSTATICALL=$(MANSTATICMAN) $(MANSTATICHTML) +# Manpages #3: generic part +mansphinxman: $(MANTYPES) $(MANREF) + $(SPHINXM) -# Manpages #4: generic part +mansphinxhtml: $(MANTYPES) $(MANREF) + $(SPHINXH) -# Creating the type manpage -%.1 %.7: %.text - $(A2XM) $^ - -# Creating the type html page -%.html: %.text - $(A2XH) $^ - $(CROSSLINK) $@ - -man: $(MANTYPEALL) $(MANREFALL) $(MANSTATICALL) +man: mansphinxman mansphinxhtml # Manpages #5: release part MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) +MANBUILDDIR=$(MANDIR)/_build/html -man-dist: man check-date +man-dist: man rm -rf "${MANWEBDIR}" - mkdir -p "${MANWEBDIR}/man1" "${MANWEBDIR}/man7" - cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${MANWEBDIR}/man1 - cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${MANWEBDIR}/man7 + mkdir -p "${MANWEBDIR}" + # mkdir -p "${MANWEBDIR}/man1" "${MANWEBDIR}/man7" + # cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${MANWEBDIR}/man1 + # cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${MANWEBDIR}/man7 + cp -R ${MANBUILDDIR}/* ${MANWEBDIR} cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" || true man-latest-link: web-pub @@ -216,15 +192,13 @@ release: # clean: - rm -f $(MAN7DSTDIR)/cdist-reference.text + rm -f $(MAN7DSTDIR)/cdist-reference.rst find "$(MANDIR)" -mindepth 2 -type l \ - -o -name "*.1" \ - -o -name "*.7" \ - -o -name "*.html" \ - -o -name "*.xml" \ | xargs rm -f + make -C $(MANDIR) clean + find * -name __pycache__ | xargs rm -rf # Archlinux diff --git a/cdist/conf/type/__apt_key/man.text b/cdist/conf/type/__apt_key/man.rst similarity index 52% rename from cdist/conf/type/__apt_key/man.text rename to cdist/conf/type/__apt_key/man.rst index 1a33e732..43dc89b1 100644 --- a/cdist/conf/type/__apt_key/man.text +++ b/cdist/conf/type/__apt_key/man.rst @@ -1,13 +1,10 @@ cdist-type__apt_key(7) ====================== +Manage the list of keys used by apt + Steven Armstrong -NAME ----- -cdist-type__apt_key - manage the list of keys used by apt - - DESCRIPTION ----------- Manages the list of keys used by apt to authenticate packages. @@ -20,13 +17,13 @@ None. OPTIONAL PARAMETERS ------------------- -state:: +state 'present' or 'absent'. Defaults to 'present' -keyid:: +keyid the id of the key to add. Defaults to __object_id -keyserver:: +keyserver the keyserver from which to fetch the key. If omitted the default set in ./parameter/default/keyserver is used. @@ -34,25 +31,25 @@ keyserver:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Add Ubuntu Archive Automatic Signing Key -__apt_key 437D05B5 -# Same thing -__apt_key 437D05B5 --state present -# Get rid of it -__apt_key 437D05B5 --state absent +.. code-block:: sh -# same thing with human readable name and explicit keyid -__apt_key UbuntuArchiveKey --keyid 437D05B5 + # Add Ubuntu Archive Automatic Signing Key + __apt_key 437D05B5 + # Same thing + __apt_key 437D05B5 --state present + # Get rid of it + __apt_key 437D05B5 --state absent -# same thing with other keyserver -__apt_key UbuntuArchiveKey --keyid 437D05B5 --keyserver keyserver.ubuntu.com --------------------------------------------------------------------------------- + # same thing with human readable name and explicit keyid + __apt_key UbuntuArchiveKey --keyid 437D05B5 + + # same thing with other keyserver + __apt_key UbuntuArchiveKey --keyid 437D05B5 --keyserver keyserver.ubuntu.com SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__apt_key_uri/man.text b/cdist/conf/type/__apt_key_uri/man.rst similarity index 61% rename from cdist/conf/type/__apt_key_uri/man.text rename to cdist/conf/type/__apt_key_uri/man.rst index fe9c3a25..a235e13a 100644 --- a/cdist/conf/type/__apt_key_uri/man.text +++ b/cdist/conf/type/__apt_key_uri/man.rst @@ -1,13 +1,10 @@ cdist-type__apt_key_uri(7) ========================== +Add apt key from uri + Steven Armstrong -NAME ----- -cdist-type__apt_key_uri - add apt key from uri - - DESCRIPTION ----------- Download a key from an uri and add it to the apt keyring. @@ -15,16 +12,16 @@ Download a key from an uri and add it to the apt keyring. REQUIRED PARAMETERS ------------------- -uri:: +uri the uri from which to download the key OPTIONAL PARAMETERS ------------------- -state:: +state 'present' or 'absent', defaults to 'present' -name:: +name a name for this key, used when testing if it is already installed. Defaults to __object_id @@ -32,17 +29,17 @@ name:: EXAMPLES -------- --------------------------------------------------------------------------------- -__apt_key_uri rabbitmq \ - --name 'RabbitMQ Release Signing Key ' \ - --uri http://www.rabbitmq.com/rabbitmq-signing-key-public.asc \ - --state present --------------------------------------------------------------------------------- +.. code-block:: sh + + __apt_key_uri rabbitmq \ + --name 'RabbitMQ Release Signing Key ' \ + --uri http://www.rabbitmq.com/rabbitmq-signing-key-public.asc \ + --state present SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__apt_norecommends/man.text b/cdist/conf/type/__apt_norecommends/man.rst similarity index 63% rename from cdist/conf/type/__apt_norecommends/man.text rename to cdist/conf/type/__apt_norecommends/man.rst index 3b65e72f..232bb166 100644 --- a/cdist/conf/type/__apt_norecommends/man.text +++ b/cdist/conf/type/__apt_norecommends/man.rst @@ -1,13 +1,10 @@ cdist-type__apt_norecommends(7) =============================== +Configure apt to not install recommended packages + Steven Armstrong -NAME ----- -cdist-type__apt_norecommends - configure apt to not install recommended packages - - DESCRIPTION ----------- Configure apt to not install any recommended or suggested packages. @@ -26,14 +23,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__apt_norecommends --------------------------------------------------------------------------------- +.. code-block:: sh + + __apt_norecommends SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__apt_ppa/man.text b/cdist/conf/type/__apt_ppa/man.rst similarity index 55% rename from cdist/conf/type/__apt_ppa/man.text rename to cdist/conf/type/__apt_ppa/man.rst index da18e9f0..e39bd6b2 100644 --- a/cdist/conf/type/__apt_ppa/man.text +++ b/cdist/conf/type/__apt_ppa/man.rst @@ -1,13 +1,10 @@ cdist-type__apt_ppa(7) ====================== +Manage ppa repositories + Steven Armstrong -NAME ----- -cdist-type__apt_ppa - Manage ppa repositories - - DESCRIPTION ----------- This cdist type allows manage ubuntu ppa repositories. @@ -15,7 +12,7 @@ This cdist type allows manage ubuntu ppa repositories. REQUIRED PARAMETERS ------------------- -state:: +state The state the ppa should be in, either 'present' or 'absent'. Defaults to 'present' @@ -28,20 +25,20 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -# Enable a ppa repository -__apt_ppa ppa:sans-intern/missing-bits -# same as -__apt_ppa ppa:sans-intern/missing-bits --state present +.. code-block:: sh -# Disable a ppa repository -__apt_ppa ppa:sans-intern/missing-bits --state absent --------------------------------------------------------------------------------- + # Enable a ppa repository + __apt_ppa ppa:sans-intern/missing-bits + # same as + __apt_ppa ppa:sans-intern/missing-bits --state present + + # Disable a ppa repository + __apt_ppa ppa:sans-intern/missing-bits --state absent SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__apt_source/man.text b/cdist/conf/type/__apt_source/man.rst similarity index 60% rename from cdist/conf/type/__apt_source/man.text rename to cdist/conf/type/__apt_source/man.rst index 03b2b311..70649c4b 100644 --- a/cdist/conf/type/__apt_source/man.text +++ b/cdist/conf/type/__apt_source/man.rst @@ -1,13 +1,10 @@ cdist-type__apt_source(7) ========================= +Manage apt sources + Steven Armstrong -NAME ----- -cdist-type__apt_source - manage apt sources - - DESCRIPTION ----------- This cdist type allows you to manage apt sources. @@ -15,52 +12,52 @@ This cdist type allows you to manage apt sources. REQUIRED PARAMETERS ------------------- -uri:: +uri the uri to the apt repository OPTIONAL PARAMETERS ------------------- -arch:: +arch set this if you need to force and specific arch (ubuntu specific) -state:: +state 'present' or 'absent', defaults to 'present' -distribution:: +distribution the distribution codename to use. Defaults to DISTRIB_CODENAME from the targets /etc/lsb-release -component:: +component space delimited list of components to enable. Defaults to an empty string. BOOLEAN PARAMETERS ------------------ -include-src:: +include-src include deb-src entries EXAMPLES -------- --------------------------------------------------------------------------------- -__apt_source rabbitmq \ - --uri http://www.rabbitmq.com/debian/ \ - --distribution testing \ - --component main \ - --include-src \ - --state present +.. code-block:: sh -__apt_source canonical_partner \ - --uri http://archive.canonical.com/ \ - --component partner --state present --------------------------------------------------------------------------------- + __apt_source rabbitmq \ + --uri http://www.rabbitmq.com/debian/ \ + --distribution testing \ + --component main \ + --include-src \ + --state present + + __apt_source canonical_partner \ + --uri http://archive.canonical.com/ \ + --component partner --state present SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__apt_update_index/man.text b/cdist/conf/type/__apt_update_index/man.rst similarity index 65% rename from cdist/conf/type/__apt_update_index/man.text rename to cdist/conf/type/__apt_update_index/man.rst index 628292dc..2fc66c65 100644 --- a/cdist/conf/type/__apt_update_index/man.text +++ b/cdist/conf/type/__apt_update_index/man.rst @@ -1,13 +1,10 @@ cdist-type__apt_update_index(7) =============================== +Update apt's package index + Steven Armstrong -NAME ----- -cdist-type__apt_update_index - Update apt's package index - - DESCRIPTION ----------- This cdist type runs apt-get update whenever any apt sources have changed. @@ -25,14 +22,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__apt_update_index --------------------------------------------------------------------------------- +.. code-block:: sh + + __apt_update_index SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__block/man.text b/cdist/conf/type/__block/man.rst similarity index 66% rename from cdist/conf/type/__block/man.text rename to cdist/conf/type/__block/man.rst index 97f538fa..4b7d61dc 100644 --- a/cdist/conf/type/__block/man.text +++ b/cdist/conf/type/__block/man.rst @@ -1,13 +1,10 @@ cdist-type__block(7) ==================== +Manage blocks of text in files + Steven Armstrong -NAME ----- -cdist-type__block - Manage blocks of text in files - - DESCRIPTION ----------- Manage a block of text in an existing file. @@ -18,62 +15,62 @@ of text. REQUIRED PARAMETERS ------------------- -text:: +text the text to manage. If text is '-' (dash), take what was written to stdin as the text. OPTIONAL PARAMETERS ------------------- -file:: +file the file in which to manage the text block. Defaults to object_id. -prefix:: +prefix the prefix to add before the text. Defaults to #cdist:__block/$__object_id -suffix:: +suffix the suffix to add after the text. Defaults to #/cdist:__block/$__object_id -state:: +state 'present' or 'absent', defaults to 'present' MESSAGES -------- -add:: +add block was added -update:: +update block was updated/changed -remove:: +remove block was removed EXAMPLES -------- --------------------------------------------------------------------------------- -# text from argument -__block /path/to/file \ - --prefix '#start' \ - --suffix '#end' \ - --text 'some\nblock of\ntext' +.. code-block:: sh -# text from stdin -__block some-id \ - --file /path/to/file \ - --text - << DONE -here some block -of text -DONE --------------------------------------------------------------------------------- + # text from argument + __block /path/to/file \ + --prefix '#start' \ + --suffix '#end' \ + --text 'some\nblock of\ntext' + + # text from stdin + __block some-id \ + --file /path/to/file \ + --text - << DONE + here some block + of text + DONE SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__ccollect_source/man.text b/cdist/conf/type/__ccollect_source/man.rst similarity index 65% rename from cdist/conf/type/__ccollect_source/man.text rename to cdist/conf/type/__ccollect_source/man.rst index 32a7467e..12fb8f42 100644 --- a/cdist/conf/type/__ccollect_source/man.text +++ b/cdist/conf/type/__ccollect_source/man.rst @@ -1,59 +1,58 @@ cdist-type__ccollect_source(7) ============================== +Manage ccollect sources + Nico Schottelius -NAME ----- -cdist-type__ccollect_source - Manage ccollect sources - - DESCRIPTION ----------- This cdist type allows you to create or delete ccollect sources. + REQUIRED PARAMETERS ------------------- -source:: +source The source from which to backup -destination:: +destination The destination directory OPTIONAL PARAMETERS ------------------- -state:: +state 'present' or 'absent', defaults to 'present' -ccollectconf:: +ccollectconf The CCOLLECT_CONF directory. Defaults to /etc/ccollect. OPTIONAL MULTIPLE PARAMETERS ---------------------------- -exclude:: +exclude Paths to exclude of backup + BOOLEAN PARAMETERS ------------------ -verbose:: +verbose Whether to report backup verbosely + EXAMPLES -------- --------------------------------------------------------------------------------- -__ccollect_source doc.ungleich.ch \ - --source doc.ungleich.ch:/ \ - --destination /backup/doc.ungleich.ch \ - --exclude '/proc/*' --exclude '/sys/*' \ - --verbose +.. code-block:: sh --------------------------------------------------------------------------------- + __ccollect_source doc.ungleich.ch \ + --source doc.ungleich.ch:/ \ + --destination /backup/doc.ungleich.ch \ + --exclude '/proc/*' --exclude '/sys/*' \ + --verbose SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - ccollect(1) - http://www.nico.schottelius.org/software/ccollect/ diff --git a/cdist/conf/type/__cdist/man.text b/cdist/conf/type/__cdist/man.rst similarity index 67% rename from cdist/conf/type/__cdist/man.text rename to cdist/conf/type/__cdist/man.rst index 0805598e..f15d3b73 100644 --- a/cdist/conf/type/__cdist/man.text +++ b/cdist/conf/type/__cdist/man.rst @@ -1,13 +1,10 @@ cdist-type__cdist(7) ==================== +Manage cdist installations + Nico Schottelius -NAME ----- -cdist-type__cdist - Manage cdist installations - - DESCRIPTION ----------- This cdist type allows you to easily setup cdist @@ -26,16 +23,16 @@ REQUIRED PARAMETERS OPTIONAL PARAMETERS ------------------- -username:: +username Select the user to create for the cdist installation. Defaults to "cdist". -source:: +source Select the source from which to clone cdist from. Defaults to "git://github.com/telmich/cdist.git". -branch:: +branch Select the branch to checkout from. Defaults to "master". @@ -43,18 +40,18 @@ branch:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Install cdist for user cdist in her home as subfolder cdist -__cdist /home/cdist/cdist +.. code-block:: sh -# Use alternative source -__cdist --source "git://git.schottelius.org/cdist" /home/cdist/cdist --------------------------------------------------------------------------------- + # Install cdist for user cdist in her home as subfolder cdist + __cdist /home/cdist/cdist + + # Use alternative source + __cdist --source "git://git.schottelius.org/cdist" /home/cdist/cdist SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__cdistmarker/man.text b/cdist/conf/type/__cdistmarker/man.rst similarity index 67% rename from cdist/conf/type/__cdistmarker/man.text rename to cdist/conf/type/__cdistmarker/man.rst index 3a59659b..22e711b6 100644 --- a/cdist/conf/type/__cdistmarker/man.text +++ b/cdist/conf/type/__cdistmarker/man.rst @@ -1,13 +1,10 @@ cdist-type__cdistmarker(7) ========================== +Add a timestamped cdist marker. + Daniel Maher -NAME ----- -cdist-type__cdistmarker - Add a timestamped cdist marker. - - DESCRIPTION ----------- This type is used to add a common marker file which indicates that a given @@ -23,11 +20,11 @@ None. OPTIONAL PARAMETERS ------------------- -destination:: +destination The path and filename of the marker. Default: /etc/cdist-configured -format:: +format The format of the timestamp. This is passed directly to system 'date'. Default: -u @@ -35,18 +32,18 @@ format:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Creates the marker as normal. -__cdistmarker +.. code-block:: sh -# Creates the marker differently. -__cdistmarker --destination /tmp/cdist_marker --format '+%s' --------------------------------------------------------------------------------- + # Creates the marker as normal. + __cdistmarker + + # Creates the marker differently. + __cdistmarker --destination /tmp/cdist_marker --format '+%s' SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__config_file/man.text b/cdist/conf/type/__config_file/man.rst similarity index 57% rename from cdist/conf/type/__config_file/man.text rename to cdist/conf/type/__config_file/man.rst index a4ec7363..49b63984 100644 --- a/cdist/conf/type/__config_file/man.text +++ b/cdist/conf/type/__config_file/man.rst @@ -1,13 +1,10 @@ cdist-type__config_file(7) ========================== +Manages config files + Steven Armstrong -NAME ----- -cdist-type__config_file - manages config files - - DESCRIPTION ----------- Deploy config files using the file type. @@ -21,37 +18,37 @@ None. OPTIONAL PARAMETERS ------------------- -group:: +group see cdist-type__file -mode:: +mode see cdist-type__file -onchange:: +onchange the code to run if the file changes -owner:: +owner see cdist-type__file -source:: +source Path to the config file. If source is '-' (dash), take what was written to stdin as the config file content. -state:: +state see cdist-type__file EXAMPLES -------- --------------------------------------------------------------------------------- -__config_file /etc/consul/conf.d/watch_foo.json \ - --owner root --group consul --mode 640 \ - --source "$__type/files/watch_foo.json" \ - --state present \ - --onchange 'service consul status >/dev/null && service consul reload || true' --------------------------------------------------------------------------------- +.. code-block:: sh + + __config_file /etc/consul/conf.d/watch_foo.json \ + --owner root --group consul --mode 640 \ + --source "$__type/files/watch_foo.json" \ + --state present \ + --onchange 'service consul status >/dev/null && service consul reload || true' SEE ALSO -------- -- cdist-type(7) -- cdist-type__file(7) +- `cdist-type(7) `_ +- `cdist-type__file(7) `_ COPYING diff --git a/cdist/conf/type/__consul/man.text b/cdist/conf/type/__consul/man.rst similarity index 71% rename from cdist/conf/type/__consul/man.text rename to cdist/conf/type/__consul/man.rst index 5ebaf1e8..77fae852 100644 --- a/cdist/conf/type/__consul/man.text +++ b/cdist/conf/type/__consul/man.rst @@ -1,13 +1,10 @@ cdist-type__consul(7) ===================== +Install consul + Steven Armstrong -NAME ----- -cdist-type__consul - install consul - - DESCRIPTION ----------- Downloads and installs the consul binary from https://dl.bintray.com/mitchellh/consul. @@ -22,10 +19,10 @@ None. OPTIONAL PARAMETERS ------------------- -state:: +state either 'present' or 'absent'. Defaults to 'present' -version:: +version which version of consul to install. See ./files/versions for a list of supported versions. Defaults to the latest known version. @@ -33,19 +30,19 @@ version:: EXAMPLES -------- --------------------------------------------------------------------------------- -# just install using defaults -__consul +.. code-block:: sh -# specific version -__consul \ - --version 0.4.1 --------------------------------------------------------------------------------- + # just install using defaults + __consul + + # specific version + __consul \ + --version 0.4.1 SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__consul_agent/man.text b/cdist/conf/type/__consul_agent/man.rst similarity index 61% rename from cdist/conf/type/__consul_agent/man.text rename to cdist/conf/type/__consul_agent/man.rst index 3491eb4c..8285cb25 100644 --- a/cdist/conf/type/__consul_agent/man.text +++ b/cdist/conf/type/__consul_agent/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_agent(7) =========================== +Manage the consul agent + Steven Armstrong -NAME ----- -cdist-type__consul_agent - manage the consul agent - - DESCRIPTION ----------- Configure and manage the consul agent. @@ -20,129 +17,154 @@ None. OPTIONAL PARAMETERS ------------------- -acl-datacenter:: +acl-datacenter only used by servers. This designates the datacenter which is authoritative for ACL information. -acl-default-policy:: + +acl-default-policy either "allow" or "deny"; defaults to "allow". The default policy controls the behavior of a token when there is no matching rule. -acl-down-policy:: + +acl-down-policy either "allow", "deny" or "extend-cache"; "extend-cache" is the default. -acl-master-token:: + +acl-master-token only used for servers in the acl_datacenter. This token will be created with management-level permissions if it does not exist. It allows operators to bootstrap the ACL system with a token ID that is well-known. -acl-token:: + +acl-token when provided, the agent will use this token when making requests to the Consul servers. -acl-ttl:: + +acl-ttl used to control Time-To-Live caching of ACLs. -bind-addr:: + +bind-addr sets the bind address for cluster communication -bootstrap-expect:: + +bootstrap-expect sets server to expect bootstrap mode -ca-file-source:: + +ca-file-source path to a PEM encoded certificate authority file which will be uploaded and configure using the ca_file config option. -cert-file-source:: + +cert-file-source path to a PEM encoded certificate file which will be uploaded and configure using the cert_file config option. -client-addr:: + +client-addr sets the address to bind for client access -datacenter:: + +datacenter datacenter of the agent -encrypt:: + +encrypt provides the gossip encryption key -group:: + +group the primary group for the agent -json-config:: + +json-config path to a partial json config file without leading { and trailing }. If json-config is '-' (dash), take what was written to stdin as the file content. -key-file-source:: + +key-file-source path to a PEM encoded private key file which will be uploaded and configure using the key_file config option. -node-name:: + +node-name name of this node. Must be unique in the cluster -retry-join:: + +retry-join address to attempt joining every retry_interval until at least one join works. Can be specified multiple times. -user:: + +user the user to run the agent as -state:: + +state if the agent is 'present' or 'absent'. Defaults to 'present'. Currently state=absent is not working due to some dependency issues. BOOLEAN PARAMETERS ------------------ -disable-remote-exec:: +disable-remote-exec disables support for remote execution. When set to true, the agent will ignore any incoming remote exec requests. -disable-update-check:: + +disable-update-check disables automatic checking for security bulletins and new version releases -leave-on-terminate:: + +leave-on-terminate gracefully leave cluster on SIGTERM -rejoin-after-leave:: + +rejoin-after-leave rejoin the cluster using the previous state after leaving -server:: + +server used to control if an agent is in server or client mode -syslog:: + +syslog enables logging to syslog -verify-incoming:: + +verify-incoming enforce the use of TLS and verify a client's authenticity on incomming connections -verify-outgoing:: + +verify-outgoing enforce the use of TLS and verify the peers authenticity on outgoing connections EXAMPLES -------- --------------------------------------------------------------------------------- -# configure as server, bootstrap and rejoin -hostname="$(cat "$__global/explorer/hostname")" -__consul_agent \ - --datacenter dc1 \ - --node-name "${hostname%%.*}" \ - --disable-update-check \ - --server \ - --rejoin-after-leave \ - --bootstrap-expect 3 \ - --retry-join consul-01 \ - --retry-join consul-02 \ - --retry-join consul-03 +.. code-block:: sh -# configure as server, bootstrap and rejoin with ssl support -hostname="$(cat "$__global/explorer/hostname")" -__consul_agent \ - --datacenter dc1 \ - --node-name "${hostname%%.*}" \ - --disable-update-check \ - --server \ - --rejoin-after-leave \ - --bootstrap-expect 3 \ - --retry-join consul-01 \ - --retry-join consul-02 \ - --retry-join consul-03 \ - --ca-file-source /path/to/ca.pem \ - --cert-file-source /path/to/cert.pem \ - --key-file-source /path/to/key.pem \ - --verify-incoming \ - --verify-outgoing + # configure as server, bootstrap and rejoin + hostname="$(cat "$__global/explorer/hostname")" + __consul_agent \ + --datacenter dc1 \ + --node-name "${hostname%%.*}" \ + --disable-update-check \ + --server \ + --rejoin-after-leave \ + --bootstrap-expect 3 \ + --retry-join consul-01 \ + --retry-join consul-02 \ + --retry-join consul-03 -# configure as client and try joining existing cluster -__consul_agent \ - --datacenter dc1 \ - --node-name "${hostname%%.*}" \ - --disable-update-check \ - --retry-join consul-01 \ - --retry-join consul-02 \ - --retry-join consul-03 + # configure as server, bootstrap and rejoin with ssl support + hostname="$(cat "$__global/explorer/hostname")" + __consul_agent \ + --datacenter dc1 \ + --node-name "${hostname%%.*}" \ + --disable-update-check \ + --server \ + --rejoin-after-leave \ + --bootstrap-expect 3 \ + --retry-join consul-01 \ + --retry-join consul-02 \ + --retry-join consul-03 \ + --ca-file-source /path/to/ca.pem \ + --cert-file-source /path/to/cert.pem \ + --key-file-source /path/to/key.pem \ + --verify-incoming \ + --verify-outgoing --------------------------------------------------------------------------------- + # configure as client and try joining existing cluster + __consul_agent \ + --datacenter dc1 \ + --node-name "${hostname%%.*}" \ + --disable-update-check \ + --retry-join consul-01 \ + --retry-join consul-02 \ + --retry-join consul-03 SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - http://www.consul.io/docs/agent/options.html diff --git a/cdist/conf/type/__consul_check/man.text b/cdist/conf/type/__consul_check/man.rst similarity index 64% rename from cdist/conf/type/__consul_check/man.text rename to cdist/conf/type/__consul_check/man.rst index 18eaf638..1de65358 100644 --- a/cdist/conf/type/__consul_check/man.text +++ b/cdist/conf/type/__consul_check/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_check(7) ============================= +Manages consul checks + Steven Armstrong -NAME ----- -cdist-type__consul_check - manages consul checks - - DESCRIPTION ----------- Generate and deploy check definitions for a consul agent. @@ -23,43 +20,49 @@ None. OPTIONAL PARAMETERS ------------------- -interval:: +interval the interval in which the script given with --script should be run -script:: + +script the shell command to run every --interval -ttl:: + +ttl how long a check is considered healthy without being updated through the HTTP interfave -id:: + +id Defaults to --name -name:: + +name The name of this check. Defaults to __object_id -notes:: + +notes human readable description -state:: + +state if this check is 'present' or 'absent'. Defaults to 'present'. EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_check redis \ - --script /usr/local/bin/check_redis.py \ - --interval 10s +.. code-block:: sh -__consul_check some-object-id \ - --id web-app \ - --name "Web App Status" \ - --notes "Web app does a curl internally every 10 seconds" \ - --ttl 30s --------------------------------------------------------------------------------- + __consul_check redis \ + --script /usr/local/bin/check_redis.py \ + --interval 10s + + __consul_check some-object-id \ + --id web-app \ + --name "Web App Status" \ + --notes "Web app does a curl internally every 10 seconds" \ + --ttl 30s SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_agent(7) +- `cdist-type(7) `_ +- `cdist-type__consul_agent(7) `_ COPYING diff --git a/cdist/conf/type/__consul_reload/man.text b/cdist/conf/type/__consul_reload/man.rst similarity index 65% rename from cdist/conf/type/__consul_reload/man.text rename to cdist/conf/type/__consul_reload/man.rst index 8dd045cf..f66bb545 100644 --- a/cdist/conf/type/__consul_reload/man.text +++ b/cdist/conf/type/__consul_reload/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_reload(7) ============================ +Reload consul + Steven Armstrong -NAME ----- -cdist-type__consul_reload - reload consul - - DESCRIPTION ----------- Reload consul after configuration changes. @@ -26,14 +23,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_reload --------------------------------------------------------------------------------- +.. code-block:: sh + + __consul_reload SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__consul_service/man.text b/cdist/conf/type/__consul_service/man.rst similarity index 66% rename from cdist/conf/type/__consul_service/man.text rename to cdist/conf/type/__consul_service/man.rst index 6bb024b1..9a8efaab 100644 --- a/cdist/conf/type/__consul_service/man.text +++ b/cdist/conf/type/__consul_service/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_service(7) ============================= +Manages consul services + Steven Armstrong -NAME ----- -cdist-type__consul_service - manages consul services - - DESCRIPTION ----------- Generate and deploy service definitions for a consul agent. @@ -23,46 +20,53 @@ None. OPTIONAL PARAMETERS ------------------- -check-interval:: +check-interval the interval in which the script given with --check-script should be run -check-script:: + +check-script the shell command to run every --check-interval -check-ttl:: + +check-ttl how long a service is considered healthy without being updated through the HTTP interfave -id:: + +id Defaults to --name -name:: + +name The name of this service. Defaults to __object_id -port:: + +port the port at which this service can be reached -state:: + +state if this service is 'present' or 'absent'. Defaults to 'present'. -tag:: + +tag a tag to add to this service. Can be specified multiple times. EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_service redis \ - --tag master \ - --tag production \ - --port 8000 \ - --check-script /usr/local/bin/check_redis.py \ - --check-interval 10s +.. code-block:: sh -__consul_service webapp \ - --port 80 \ - --check-ttl 10s --------------------------------------------------------------------------------- + __consul_service redis \ + --tag master \ + --tag production \ + --port 8000 \ + --check-script /usr/local/bin/check_redis.py \ + --check-interval 10s + + __consul_service webapp \ + --port 80 \ + --check-ttl 10s SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_agent(7) +- `cdist-type(7) `_ +- `cdist-type__consul_agent(7) `_ COPYING diff --git a/cdist/conf/type/__consul_template/man.text b/cdist/conf/type/__consul_template/man.rst similarity index 82% rename from cdist/conf/type/__consul_template/man.text rename to cdist/conf/type/__consul_template/man.rst index 0d86aee8..bcdb94e3 100644 --- a/cdist/conf/type/__consul_template/man.text +++ b/cdist/conf/type/__consul_template/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_template(7) ============================== +Manage the consul-template service + Steven Armstrong -NAME ----- -cdist-type__consul_template - manage the consul-template service - - DESCRIPTION ----------- Downloads and installs the consul-template binary from @@ -24,52 +21,69 @@ None. OPTIONAL PARAMETERS ------------------- -auth-username:: +auth-username specify a username for basic authentication. -auth-password:: + +auth-password specify a password for basic authentication. -batch-size:: + +batch-size the size of the batch when polling multiple dependencies. -consul:: + +consul the location of the Consul instance to query (may be an IP address or FQDN) with port. Defaults to 'localhost:8500'. -log-level:: + +log-level The log level for output. This applies to the stdout/stderr logging as well as syslog logging (if enabled). Valid values are "debug", "info", "warn", and "err". The default value is "warn". -max-stale:: + +max-stale the maximum staleness of a query. If specified, Consul will distribute work among all servers instead of just the leader. -retry:: + +retry the amount of time to wait if Consul returns an error when communicating with the API. -state:: + +state either 'present' or 'absent'. Defaults to 'present' -ssl-cert:: + +ssl-cert Path to an SSL client certificate to use to authenticate to the consul server. Useful if the consul server "verify_incoming" option is set. -ssl-ca-cert:: + +ssl-ca-cert Path to a CA certificate file, containing one or more CA certificates to use to validate the certificate sent by the consul server to us. This is a handy alternative to setting --ssl-no-verify if you are using your own CA. -syslog-facility:: + +syslog-facility The facility to use when sending to syslog. This requires the use of --syslog. The default value is LOCAL0. -token:: + +token the Consul API token. -vault-address:: + +vault-address the location of the Vault instance to query (may be an IP address or FQDN) with port. -vault-token:: + +vault-token the Vault API token. -vault-ssl-cert:: + +vault-ssl-cert Path to an SSL client certificate to use to authenticate to the vault server. -vault-ssl-ca-cert:: + +vault-ssl-ca-cert Path to a CA certificate file, containing one or more CA certificates to use to validate the certificate sent by the vault server to us. -version:: + +version which version of consul-template to install. See ./files/versions for a list of supported versions. Defaults to the latest known version. -wait:: + +wait the minimum(:maximum) to wait before rendering a new template to disk and triggering a command, separated by a colon (:). If the optional maximum value is omitted, it is assumed to be 4x the required minimum value. @@ -77,36 +91,40 @@ wait:: BOOLEAN PARAMETERS ------------------ -ssl:: +ssl use HTTPS while talking to Consul. Requires the Consul server to be configured to serve secure connections. -ssl-no-verify:: + +ssl-no-verify ignore certificate warnings. Only used if ssl is enabled. -syslog:: + +syslog Send log output to syslog (in addition to stdout and stderr). -vault-ssl:: + +vault-ssl use HTTPS while talking to Vault. Requires the Vault server to be configured to serve secure connections. -vault-ssl-no-verify:: + +vault-ssl-no-verify ignore certificate warnings. Only used if vault is enabled. EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_template \ - --consul consul.service.consul:8500 \ - --retry 30s +.. code-block:: sh -# specific version -__consul_template \ - --version 0.6.5 \ - --retry 30s --------------------------------------------------------------------------------- + __consul_template \ + --consul consul.service.consul:8500 \ + --retry 30s + + # specific version + __consul_template \ + --version 0.6.5 \ + --retry 30s SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - https://github.com/hashicorp/consul-template diff --git a/cdist/conf/type/__consul_template_template/man.text b/cdist/conf/type/__consul_template_template/man.rst similarity index 59% rename from cdist/conf/type/__consul_template_template/man.text rename to cdist/conf/type/__consul_template_template/man.rst index 159a63fb..20d0a619 100644 --- a/cdist/conf/type/__consul_template_template/man.text +++ b/cdist/conf/type/__consul_template_template/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_template_template(7) ======================================= +Manage consul-template templates + Steven Armstrong -NAME ----- -cdist-type__consul_template_template - manage consul-template templates - - DESCRIPTION ----------- Generate and deploy template definitions for a consul-template. @@ -18,49 +15,52 @@ Either the --source or the --source-file parameter must be given. REQUIRED PARAMETERS ------------------- -destination:: +destination the destination where the generated file should go. OPTIONAL PARAMETERS ------------------- -command:: +command an optional command to run after rendering the template to its destination. -source:: + +source path to the template source. Conflicts --source-file. -source-file:: + +source-file path to a local file which is uploaded using the __file type and configured as the source. If source is '-' (dash), take what was written to stdin as the file content. Conflicts --source. -state:: + +state if this template is 'present' or 'absent'. Defaults to 'present'. EXAMPLES -------- --------------------------------------------------------------------------------- -# configure template on the target -__consul_template_template nginx \ - --source /etc/my-consul-templates/nginx.ctmpl \ - --destination /etc/nginx/nginx.conf \ - --command 'service nginx restart' +.. code-block:: sh + + # configure template on the target + __consul_template_template nginx \ + --source /etc/my-consul-templates/nginx.ctmpl \ + --destination /etc/nginx/nginx.conf \ + --command 'service nginx restart' -# upload a local file to the target and configure it -__consul_template_template nginx \ - --source-file "$__manifest/files/nginx.ctmpl" \ - --destination /etc/nginx/nginx.conf \ - --command 'service nginx restart' --------------------------------------------------------------------------------- + # upload a local file to the target and configure it + __consul_template_template nginx \ + --source-file "$__manifest/files/nginx.ctmpl" \ + --destination /etc/nginx/nginx.conf \ + --command 'service nginx restart' SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_template(7) -- cdist-type__consul_template_config(7) +- `cdist-type(7) `_ +- `cdist-type__consul_template(7) `_ +- `cdist-type__consul_template_config(7) `_ COPYING diff --git a/cdist/conf/type/__consul_watch_checks/man.text b/cdist/conf/type/__consul_watch_checks/man.rst similarity index 62% rename from cdist/conf/type/__consul_watch_checks/man.text rename to cdist/conf/type/__consul_watch_checks/man.rst index 75c42fc2..c1e8c0a7 100644 --- a/cdist/conf/type/__consul_watch_checks/man.text +++ b/cdist/conf/type/__consul_watch_checks/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_watch_checks(7) ================================== +Manages consul checks watches + Steven Armstrong -NAME ----- -cdist-type__consul_watch_checks - manages consul checks watches - - DESCRIPTION ----------- Generate and deploy watch definitions of type 'checks' for a consul agent. @@ -16,45 +13,49 @@ See http://www.consul.io/docs/agent/watches.html for parameter documentation. REQUIRED PARAMETERS ------------------- -handler:: +handler the handler to invoke when the data view updates OPTIONAL PARAMETERS ------------------- -datacenter:: +datacenter can be provided to override the agent's default datacenter -filter-service:: + +filter-service filter to a specific service. Conflicts with --filter-state. -filter-state:: + +filter-state filter to a specific state. Conflicts with --filter-service. -state:: + +state if this watch is 'present' or 'absent'. Defaults to 'present'. -token:: + +token can be provided to override the agent's default ACL token EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_watch_checks some-id \ - --handler /usr/bin/my-handler.sh +.. code-block:: sh -__consul_watch_checks some-id \ - --filter-service consul \ - --handler /usr/bin/my-handler.sh + __consul_watch_checks some-id \ + --handler /usr/bin/my-handler.sh -__consul_watch_checks some-id \ - --filter-state passing \ - --handler /usr/bin/my-handler.sh --------------------------------------------------------------------------------- + __consul_watch_checks some-id \ + --filter-service consul \ + --handler /usr/bin/my-handler.sh + + __consul_watch_checks some-id \ + --filter-state passing \ + --handler /usr/bin/my-handler.sh SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_agent(7) +- `cdist-type(7) `_ +- `cdist-type__consul_agent(7) `_ - http://www.consul.io/docs/agent/watches.html diff --git a/cdist/conf/type/__consul_watch_event/man.text b/cdist/conf/type/__consul_watch_event/man.rst similarity index 65% rename from cdist/conf/type/__consul_watch_event/man.text rename to cdist/conf/type/__consul_watch_event/man.rst index 3b393241..ea9bc61a 100644 --- a/cdist/conf/type/__consul_watch_event/man.text +++ b/cdist/conf/type/__consul_watch_event/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_watch_event(7) ================================= +Manages consul event watches + Steven Armstrong -NAME ----- -cdist-type__consul_watch_event - manages consul event watches - - DESCRIPTION ----------- Generate and deploy watch definitions of type 'event' for a consul agent. @@ -16,39 +13,42 @@ See http://www.consul.io/docs/agent/watches.html for parameter documentation. REQUIRED PARAMETERS ------------------- -handler:: +handler the handler to invoke when the data view updates OPTIONAL PARAMETERS ------------------- -datacenter:: +datacenter can be provided to override the agent's default datacenter -name:: + +name restrict the watch to only events with the given name -state:: + +state if this watch is 'present' or 'absent'. Defaults to 'present'. -token:: + +token can be provided to override the agent's default ACL token EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_watch_event some-id \ - --handler /usr/bin/my-handler.sh +.. code-block:: sh -__consul_watch_event some-id \ - --name web-deploy \ - --handler /usr/bin/my-handler.sh --------------------------------------------------------------------------------- + __consul_watch_event some-id \ + --handler /usr/bin/my-handler.sh + + __consul_watch_event some-id \ + --name web-deploy \ + --handler /usr/bin/my-handler.sh SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_agent(7) +- `cdist-type(7) `_ +- `cdist-type__consul_agent(7) `_ - http://www.consul.io/docs/agent/watches.html diff --git a/cdist/conf/type/__consul_watch_key/man.text b/cdist/conf/type/__consul_watch_key/man.rst similarity index 68% rename from cdist/conf/type/__consul_watch_key/man.text rename to cdist/conf/type/__consul_watch_key/man.rst index 5d8381cb..90e952b8 100644 --- a/cdist/conf/type/__consul_watch_key/man.text +++ b/cdist/conf/type/__consul_watch_key/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_watch_key(7) =============================== +Manages consul key watches + Steven Armstrong -NAME ----- -cdist-type__consul_watch_key - manages consul key watches - - DESCRIPTION ----------- Generate and deploy watch definitions of type 'key' for a consul agent. @@ -16,36 +13,39 @@ See http://www.consul.io/docs/agent/watches.html for parameter documentation. REQUIRED PARAMETERS ------------------- -handler:: +handler the handler to invoke when the data view updates -key:: + +key the key to watch for changes OPTIONAL PARAMETERS ------------------- -datacenter:: +datacenter can be provided to override the agent's default datacenter -state:: + +state if this watch is 'present' or 'absent'. Defaults to 'present'. -token:: + +token can be provided to override the agent's default ACL token EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_watch_key some-id \ - --key foo/bar/baz \ - --handler /usr/bin/my-key-handler.sh --------------------------------------------------------------------------------- +.. code-block:: sh + + __consul_watch_key some-id \ + --key foo/bar/baz \ + --handler /usr/bin/my-key-handler.sh SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_agent(7) +- `cdist-type(7) `_ +- `cdist-type__consul_agent(7) `_ - http://www.consul.io/docs/agent/watches.html diff --git a/cdist/conf/type/__consul_watch_keyprefix/man.text b/cdist/conf/type/__consul_watch_keyprefix/man.rst similarity index 68% rename from cdist/conf/type/__consul_watch_keyprefix/man.text rename to cdist/conf/type/__consul_watch_keyprefix/man.rst index e2f05de2..8ee5822d 100644 --- a/cdist/conf/type/__consul_watch_keyprefix/man.text +++ b/cdist/conf/type/__consul_watch_keyprefix/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_watch_keyprefix(7) ===================================== +Manages consul keyprefix watches + Steven Armstrong -NAME ----- -cdist-type__consul_watch_keyprefix - manages consul keyprefix watches - - DESCRIPTION ----------- Generate and deploy watch definitions of type 'keyprefix' for a consul agent. @@ -16,36 +13,39 @@ See http://www.consul.io/docs/agent/watches.html for parameter documentation. REQUIRED PARAMETERS ------------------- -handler:: +handler the handler to invoke when the data view updates -prefix:: + +prefix the prefix of keys to watch for changes OPTIONAL PARAMETERS ------------------- -datacenter:: +datacenter can be provided to override the agent's default datacenter -state:: + +state if this watch is 'present' or 'absent'. Defaults to 'present'. -token:: + +token can be provided to override the agent's default ACL token EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_watch_keyprefix some-id \ - --prefix foo/ \ - --handler /usr/bin/my-prefix-handler.sh --------------------------------------------------------------------------------- +.. code-block:: sh + + __consul_watch_keyprefix some-id \ + --prefix foo/ \ + --handler /usr/bin/my-prefix-handler.sh SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_agent(7) +- `cdist-type(7) `_ +- `cdist-type__consul_agent(7) `_ - http://www.consul.io/docs/agent/watches.html diff --git a/cdist/conf/type/__consul_watch_nodes/man.text b/cdist/conf/type/__consul_watch_nodes/man.rst similarity index 69% rename from cdist/conf/type/__consul_watch_nodes/man.text rename to cdist/conf/type/__consul_watch_nodes/man.rst index 70b83e92..b5f0a5ce 100644 --- a/cdist/conf/type/__consul_watch_nodes/man.text +++ b/cdist/conf/type/__consul_watch_nodes/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_watch_nodes(7) ================================= +Manages consul nodes watches + Steven Armstrong -NAME ----- -cdist-type__consul_watch_nodes - manages consul nodes watches - - DESCRIPTION ----------- Generate and deploy watch definitions of type 'nodes' for a consul agent. @@ -16,33 +13,35 @@ See http://www.consul.io/docs/agent/watches.html for parameter documentation. REQUIRED PARAMETERS ------------------- -handler:: +handler the handler to invoke when the data view updates OPTIONAL PARAMETERS ------------------- -datacenter:: +datacenter can be provided to override the agent's default datacenter -state:: + +state if this watch is 'present' or 'absent'. Defaults to 'present'. -token:: + +token can be provided to override the agent's default ACL token EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_watch_nodes some-id \ - --handler /usr/bin/my-key-handler.sh --------------------------------------------------------------------------------- +.. code-block:: sh + + __consul_watch_nodes some-id \ + --handler /usr/bin/my-key-handler.sh SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_agent(7) +- `cdist-type(7) `_ +- `cdist-type__consul_agent(7) `_ - http://www.consul.io/docs/agent/watches.html diff --git a/cdist/conf/type/__consul_watch_service/man.text b/cdist/conf/type/__consul_watch_service/man.rst similarity index 60% rename from cdist/conf/type/__consul_watch_service/man.text rename to cdist/conf/type/__consul_watch_service/man.rst index c7731a97..1cc2c00d 100644 --- a/cdist/conf/type/__consul_watch_service/man.text +++ b/cdist/conf/type/__consul_watch_service/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_watch_service(7) =================================== +Manages consul service watches + Steven Armstrong -NAME ----- -cdist-type__consul_watch_service - manages consul service watches - - DESCRIPTION ----------- Generate and deploy watch definitions of type 'service' for a consul agent. @@ -16,55 +13,59 @@ See http://www.consul.io/docs/agent/watches.html for parameter documentation. REQUIRED PARAMETERS ------------------- -handler:: +handler the handler to invoke when the data view updates -service:: + +service the service to watch for changes OPTIONAL PARAMETERS ------------------- -datacenter:: +datacenter can be provided to override the agent's default datacenter -state:: + +state if this watch is 'present' or 'absent'. Defaults to 'present'. -token:: + +token can be provided to override the agent's default ACL token -tag:: + +tag filter by tag BOOLEAN PARAMETERS ------------------ -passingonly:: +passingonly specifies if only hosts passing all checks are displayed EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_watch_service some-id \ - --service consul \ - --handler /usr/bin/my-handler.sh +.. code-block:: sh -__consul_watch_service some-id \ - --service redis \ - --tag production \ - --handler /usr/bin/my-handler.sh + __consul_watch_service some-id \ + --service consul \ + --handler /usr/bin/my-handler.sh -__consul_watch_service some-id \ - --service redis \ - --tag production \ - --passingonly \ - --handler /usr/bin/my-handler.sh --------------------------------------------------------------------------------- + __consul_watch_service some-id \ + --service redis \ + --tag production \ + --handler /usr/bin/my-handler.sh + + __consul_watch_service some-id \ + --service redis \ + --tag production \ + --passingonly \ + --handler /usr/bin/my-handler.sh SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_agent(7) +- `cdist-type(7) `_ +- `cdist-type__consul_agent(7) `_ - http://www.consul.io/docs/agent/watches.html diff --git a/cdist/conf/type/__consul_watch_services/man.text b/cdist/conf/type/__consul_watch_services/man.rst similarity index 68% rename from cdist/conf/type/__consul_watch_services/man.text rename to cdist/conf/type/__consul_watch_services/man.rst index bc489493..bf766222 100644 --- a/cdist/conf/type/__consul_watch_services/man.text +++ b/cdist/conf/type/__consul_watch_services/man.rst @@ -1,13 +1,10 @@ cdist-type__consul_watch_services(7) ==================================== +Manages consul services watches + Steven Armstrong -NAME ----- -cdist-type__consul_watch_services - manages consul services watches - - DESCRIPTION ----------- Generate and deploy watch definitions of type 'services' for a consul agent. @@ -16,33 +13,35 @@ See http://www.consul.io/docs/agent/watches.html for parameter documentation. REQUIRED PARAMETERS ------------------- -handler:: +handler the handler to invoke when the data view updates OPTIONAL PARAMETERS ------------------- -datacenter:: +datacenter can be provided to override the agent's default datacenter -state:: + +state if this watch is 'present' or 'absent'. Defaults to 'present'. -token:: + +token can be provided to override the agent's default ACL token EXAMPLES -------- --------------------------------------------------------------------------------- -__consul_watch_services some-id \ - --handler /usr/bin/my-key-handler.sh --------------------------------------------------------------------------------- +.. code-block:: sh + + __consul_watch_services some-id \ + --handler /usr/bin/my-key-handler.sh SEE ALSO -------- -- cdist-type(7) -- cdist-type__consul_agent(7) +- `cdist-type(7) `_ +- `cdist-type__consul_agent(7) `_ - http://www.consul.io/docs/agent/watches.html diff --git a/cdist/conf/type/__cron/man.text b/cdist/conf/type/__cron/man.rst similarity index 62% rename from cdist/conf/type/__cron/man.text rename to cdist/conf/type/__cron/man.rst index ee30c83f..353f6bae 100644 --- a/cdist/conf/type/__cron/man.text +++ b/cdist/conf/type/__cron/man.rst @@ -1,13 +1,10 @@ cdist-type__cron(7) =================== +Installs and manages cron jobs + Steven Armstrong -NAME ----- -cdist-type__cron - installs and manages cron jobs - - DESCRIPTION ----------- This cdist type allows you to manage entries in a users crontab. @@ -15,33 +12,33 @@ This cdist type allows you to manage entries in a users crontab. REQUIRED PARAMETERS ------------------- -user:: +user The user who's crontab is edited -command:: +command The command to run. OPTIONAL PARAMETERS ------------------- -state:: +state Either present or absent. Defaults to present. -minute:: +minute See crontab(5). Defaults to * -hour:: +hour See crontab(5). Defaults to * -day_of_month:: +day_of_month See crontab(5). Defaults to * -month:: +month See crontab(5). Defaults to * -day_of_week:: +day_of_week See crontab(5). Defaults to * -raw:: +raw Take whatever the user has given instead of time and date fields. If given, all other time and date fields are ignored. Can for example be used to specify cron EXTENSIONS like reboot, yearly etc. See crontab(5) for the extensions if any that your cron implementation implements. -raw_command:: +raw_command Take whatever the user has given in the command and ignore everything else. If given, the command will be added to crontab. Can for example be used to define variables like SHELL or MAILTO. @@ -50,27 +47,27 @@ raw_command:: EXAMPLES -------- --------------------------------------------------------------------------------- -# run Monday to Saturday at 23:15 -__cron some-id --user root --command "/path/to/script" \ - --hour 23 --minute 15 --day_of_week 1-6 +.. code-block:: sh -# run on reboot -__cron some-id --user root --command "/path/to/script" \ - --raw @reboot + # run Monday to Saturday at 23:15 + __cron some-id --user root --command "/path/to/script" \ + --hour 23 --minute 15 --day_of_week 1-6 -# remove cronjob -__cron some-id --user root --command "/path/to/script" --state absent + # run on reboot + __cron some-id --user root --command "/path/to/script" \ + --raw @reboot -# define default shell -__cron some-id --user root --raw_command --command "SHELL=/bin/bash" \ - --state present --------------------------------------------------------------------------------- + # remove cronjob + __cron some-id --user root --command "/path/to/script" --state absent + + # define default shell + __cron some-id --user root --raw_command --command "SHELL=/bin/bash" \ + --state present SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - crontab(5) diff --git a/cdist/conf/type/__debconf_set_selections/man.text b/cdist/conf/type/__debconf_set_selections/man.rst similarity index 52% rename from cdist/conf/type/__debconf_set_selections/man.text rename to cdist/conf/type/__debconf_set_selections/man.rst index e36ebaa3..37aa65b9 100644 --- a/cdist/conf/type/__debconf_set_selections/man.text +++ b/cdist/conf/type/__debconf_set_selections/man.rst @@ -1,13 +1,10 @@ cdist-type__debconf_set_selections(7) ===================================== +Setup debconf selections + Nico Schottelius -NAME ----- -cdist-type__debconf_set_selections - Setup debconf selections - - DESCRIPTION ----------- On Debian and alike systems debconf-set-selections(1) can be used @@ -16,7 +13,7 @@ to setup configuration parameters. REQUIRED PARAMETERS ------------------- -file:: +file Use the given filename as input for debconf-set-selections(1) If filename is "-", read from stdin. @@ -24,23 +21,23 @@ file:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Setup configuration for nslcd -__debconf_set_selections nslcd --file /path/to/file +.. code-block:: sh -# Setup configuration for nslcd from another type -__debconf_set_selections nslcd --file "$__type/files/preseed/nslcd" + # Setup configuration for nslcd + __debconf_set_selections nslcd --file /path/to/file -__debconf_set_selections nslcd --file - << eof -gitolite gitolite/gituser string git -eof --------------------------------------------------------------------------------- + # Setup configuration for nslcd from another type + __debconf_set_selections nslcd --file "$__type/files/preseed/nslcd" + + __debconf_set_selections nslcd --file - << eof + gitolite gitolite/gituser string git + eof SEE ALSO -------- -- cdist-type(7) -- cdist-type__update_alternatives(7) +- `cdist-type(7) `_ +- `cdist-type__update_alternatives(7) `_ - debconf-set-selections(1) diff --git a/cdist/conf/type/__directory/man.text b/cdist/conf/type/__directory/man.rst similarity index 57% rename from cdist/conf/type/__directory/man.text rename to cdist/conf/type/__directory/man.rst index 77d5da34..279763a1 100644 --- a/cdist/conf/type/__directory/man.text +++ b/cdist/conf/type/__directory/man.rst @@ -1,13 +1,10 @@ cdist-type__directory(7) ======================== +Manage a directory + Nico Schottelius -NAME ----- -cdist-type__directory - Manage a directory - - DESCRIPTION ----------- This cdist type allows you to create or remove directories on the target. @@ -20,80 +17,79 @@ None. OPTIONAL PARAMETERS ------------------- -state:: +state 'present' or 'absent', defaults to 'present' -group:: +group Group to chgrp to. -mode:: +mode Unix permissions, suitable for chmod. -owner:: +owner User to chown to. BOOLEAN PARAMETERS ------------------ -parents:: +parents Whether to create parents as well (mkdir -p behaviour). Warning: all intermediate directory permissions default to whatever mkdir -p does. Usually this means root:root, 0700. -recursive:: +recursive If supplied the chgrp and chown call will run recursively. This does *not* influence the behaviour of chmod. MESSAGES -------- -chgrp :: +chgrp Changed group membership -chown :: +chown Changed owner -chmod :: +chmod Changed mode -create:: +create Empty directory was created -remove:: +remove Directory exists, but state is absent, directory will be removed by generated code. -remove non directory:: +remove non directory Something other than a directory with the same name exists and was removed prior to create. EXAMPLES -------- --------------------------------------------------------------------------------- -# A silly example -__directory /tmp/foobar +.. code-block:: sh -# Remove a directory -__directory /tmp/foobar --state absent + # A silly example + __directory /tmp/foobar -# Ensure /etc exists correctly -__directory /etc --owner root --group root --mode 0755 + # Remove a directory + __directory /tmp/foobar --state absent -# Create nfs service directory, including parents -__directory /home/services/nfs --parents + # Ensure /etc exists correctly + __directory /etc --owner root --group root --mode 0755 -# Change permissions recursively -__directory /home/services --recursive --owner root --group root + # Create nfs service directory, including parents + __directory /home/services/nfs --parents -# Setup a temp directory -__directory /local --mode 1777 + # Change permissions recursively + __directory /home/services --recursive --owner root --group root -# Take it all -__directory /home/services/kvm --recursive --parents \ - --owner root --group root --mode 0755 --state present + # Setup a temp directory + __directory /local --mode 1777 --------------------------------------------------------------------------------- + # Take it all + __directory /home/services/kvm --recursive --parents \ + --owner root --group root --mode 0755 --state present SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__dog_vdi/man.text b/cdist/conf/type/__dog_vdi/man.rst similarity index 50% rename from cdist/conf/type/__dog_vdi/man.text rename to cdist/conf/type/__dog_vdi/man.rst index e3453ba7..3e6155a6 100644 --- a/cdist/conf/type/__dog_vdi/man.text +++ b/cdist/conf/type/__dog_vdi/man.rst @@ -1,13 +1,10 @@ cdist-type__dog_vdi(7) ====================== +Manage Sheepdog VM images + Nico Schottelius -NAME ----- -cdist-type__dog_vdi - Manage Sheepdog VM images - - DESCRIPTION ----------- The dog program is used to create images for sheepdog @@ -16,9 +13,9 @@ to be used in qemu. OPTIONAL PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present" -size:: +size Size of the image in "dog vdi" compatible units. Required if state is "present". @@ -28,24 +25,24 @@ size:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Create a 50G size image -__dog_vdi nico-privat.sky.ungleich.ch --size 50G +.. code-block:: sh -# Create a 50G size image (more explicit) -__dog_vdi nico-privat.sky.ungleich.ch --size 50G --state present + # Create a 50G size image + __dog_vdi nico-privat.sky.ungleich.ch --size 50G -# Remove image -__dog_vdi nico-privat.sky.ungleich.ch --state absent + # Create a 50G size image (more explicit) + __dog_vdi nico-privat.sky.ungleich.ch --size 50G --state present -# Remove image - keeping --size is ok -__dog_vdi nico-privat.sky.ungleich.ch --size 50G --state absent --------------------------------------------------------------------------------- + # Remove image + __dog_vdi nico-privat.sky.ungleich.ch --state absent + + # Remove image - keeping --size is ok + __dog_vdi nico-privat.sky.ungleich.ch --size 50G --state absent SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - dog(8) - qemu(1) diff --git a/cdist/conf/type/__file/man.rst b/cdist/conf/type/__file/man.rst new file mode 100644 index 00000000..73336581 --- /dev/null +++ b/cdist/conf/type/__file/man.rst @@ -0,0 +1,109 @@ +cdist-type__file(7) +=================== +Manage files. + +Nico Schottelius + + +DESCRIPTION +----------- +This cdist type allows you to create files, remove files and set file +attributes on the target. + +If the file already exists on the target, then if it is a: + +regular file, and state is: + present + replace it with the source file if they are not equal + exists + do nothing +symlink + replace it with the source file +directory + replace it with the source file + +In any case, make sure that the file attributes are as specified. + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +state + 'present', 'absent' or 'exists', defaults to 'present' where: + + present + the file is exactly the one from source + absent + the file does not exist + exists + the file from source but only if it doesn't already exist + +group + Group to chgrp to. + +mode + Unix permissions, suitable for chmod. + +owner + User to chown to. + +source + If supplied, copy this file from the host running cdist to the target. + If not supplied, an empty file or directory will be created. + If source is '-' (dash), take what was written to stdin as the file content. + +MESSAGES +-------- +chgrp + Changed group membership +chown + Changed owner +chmod + Changed mode +create + Empty file was created (no --source specified) +remove + File exists, but state is absent, file will be removed by generated code. +upload + File was uploaded + + +EXAMPLES +-------- + +.. code-block:: sh + + # Create /etc/cdist-configured as an empty file + __file /etc/cdist-configured + # The same thing + __file /etc/cdist-configured --state present + # Use __file from another type + __file /etc/issue --source "$__type/files/archlinux" --state present + # Delete existing file + __file /etc/cdist-configured --state absent + # Supply some more settings + __file /etc/shadow --source "$__type/files/shadow" \ + --owner root --group shadow --mode 0640 \ + --state present + # Provide a default file, but let the user change it + __file /home/frodo/.bashrc --source "/etc/skel/.bashrc" \ + --state exists \ + --owner frodo --mode 0600 + # Take file content from stdin + __file /tmp/whatever --owner root --group root --mode 644 --source - << DONE + Here goes the content for /tmp/whatever + DONE + + +SEE ALSO +-------- +* `cdist-type(7) `_ + + +COPYING +------- +Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__file/man.text b/cdist/conf/type/__file/man.text deleted file mode 100644 index a582b27b..00000000 --- a/cdist/conf/type/__file/man.text +++ /dev/null @@ -1,109 +0,0 @@ -cdist-type__file(7) -=================== -Nico Schottelius - - -NAME ----- -cdist-type__file - Manage files - - -DESCRIPTION ------------ -This cdist type allows you to create files, remove files and set file -attributes on the target. - -If the file already exists on the target, then if it is a: -- regular file, and state is: - present: replace it with the source file if they are not equal - exists: do nothing -- symlink: replace it with the source file -- directory: replace it with the source file - -In any case, make sure that the file attributes are as specified. - - -REQUIRED PARAMETERS -------------------- -None. - -OPTIONAL PARAMETERS -------------------- -state:: - 'present', 'absent' or 'exists', defaults to 'present' - where: - present: the file is exactly the one from source - absent: the file does not exist - exists: the file from source but only if it doesn't already exist - -group:: - Group to chgrp to. - -mode:: - Unix permissions, suitable for chmod. - -owner:: - User to chown to. - -source:: - If supplied, copy this file from the host running cdist to the target. - If not supplied, an empty file or directory will be created. - If source is '-' (dash), take what was written to stdin as the file content. - -MESSAGES --------- -chgrp :: - Changed group membership -chown :: - Changed owner -chmod :: - Changed mode -create:: - Empty file was created (no --source specified) -remove:: - File exists, but state is absent, file will be removed by generated code. -upload:: - File was uploaded - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Create /etc/cdist-configured as an empty file -__file /etc/cdist-configured -# The same thing -__file /etc/cdist-configured --state present -# Delete existing file -__file /etc/cdist-configured --state absent - -# Use __file from another type -__file /etc/issue --source "$__type/files/archlinux" --state present - -# Supply some more settings -__file /etc/shadow --source "$__type/files/shadow" \ - --owner root --group shadow --mode 0640 \ - --state present - -# Provide a default file, but let the user change it -__file /home/frodo/.bashrc --source "/etc/skel/.bashrc" \ - --state exists \ - --owner frodo --mode 0600 - -# Take file content from stdin -__file /tmp/whatever --owner root --group root --mode 644 --source - << DONE -Here goes the content for /tmp/whatever -DONE - --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__firewalld_rule/man.rst b/cdist/conf/type/__firewalld_rule/man.rst new file mode 100644 index 00000000..d953b3d2 --- /dev/null +++ b/cdist/conf/type/__firewalld_rule/man.rst @@ -0,0 +1,75 @@ +cdist-type__firewalld_rule(7) +============================= +Configure firewalld rules + +Nico Schottelius + + +DESCRIPTION +----------- +This cdist type allows you to manage rules in firewalld +using the *direct* way (i.e. no zone support). + + +REQUIRED PARAMETERS +------------------- +rule + The rule to apply. Essentially an firewalld command + line without firewalld in front of it. +protocol + Either ipv4, ipv4 or eb. See firewall-cmd(1) +table + The table to use (like filter or nat). See firewall-cmd(1). +chain + The chain to use (like INPUT_direct or FORWARD_direct). See firewall-cmd(1). +priority + The priority to use (0 is topmost). See firewall-cmd(1). + + +OPTIONAL PARAMETERS +------------------- +state + 'present' or 'absent', defaults to 'present' + + +EXAMPLES +-------- + +.. code-block:: sh + + # Allow acces from entrance.place4.ungleich.ch + __firewalld_rule entrance \ + --protocol ipv4 \ + --table filter \ + --chain INPUT_direct \ + --priority 0 \ + --rule '-s entrance.place4.ungleich.ch -j ACCEPT' + + # Allow forwarding of traffic from br0 + __firewalld_rule vm-forward --protocol ipv4 \ + --table filter \ + --chain FORWARD_direct \ + --priority 0 \ + --rule '-i br0 -j ACCEPT' + + # Ensure old rule is absent - warning, the rule part must stay the same! + __firewalld_rule vm-forward + --protocol ipv4 \ + --table filter \ + --chain FORWARD_direct \ + --priority 0 \ + --rule '-i br0 -j ACCEPT' \ + --state absent + + +SEE ALSO +-------- +- `cdist-type(7) `_ +- `cdist-type__iptables_rule(7) `_ +- firewalld(8) + + +COPYING +------- +Copyright \(C) 2015 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__firewalld_rule/man.text b/cdist/conf/type/__firewalld_rule/man.text deleted file mode 100644 index 17296a25..00000000 --- a/cdist/conf/type/__firewalld_rule/man.text +++ /dev/null @@ -1,78 +0,0 @@ -cdist-type__firewalld_rule(7) -============================= -Nico Schottelius - - -NAME ----- -cdist-type__firewalld_rule - Configure firewalld rules - - -DESCRIPTION ------------ -This cdist type allows you to manage rules in firewalld -using the *direct* way (i.e. no zone support). - - -REQUIRED PARAMETERS -------------------- -rule:: - The rule to apply. Essentially an firewalld command - line without firewalld in front of it. -protocol:: - Either ipv4, ipv4 or eb. See firewall-cmd(1) -table:: - The table to use (like filter or nat). See firewall-cmd(1). -chain:: - The chain to use (like INPUT_direct or FORWARD_direct). See firewall-cmd(1). -priority:: - The priority to use (0 is topmost). See firewall-cmd(1). - - -OPTIONAL PARAMETERS -------------------- -state:: - 'present' or 'absent', defaults to 'present' - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Allow acces from entrance.place4.ungleich.ch -__firewalld_rule entrance \ - --protocol ipv4 \ - --table filter \ - --chain INPUT_direct \ - --priority 0 \ - --rule '-s entrance.place4.ungleich.ch -j ACCEPT' - -# Allow forwarding of traffic from br0 -__firewalld_rule vm-forward --protocol ipv4 \ - --table filter \ - --chain FORWARD_direct \ - --priority 0 \ - --rule '-i br0 -j ACCEPT' - -# Ensure old rule is absent - warning, the rule part must stay the same! -__firewalld_rule vm-forward - --protocol ipv4 \ - --table filter \ - --chain FORWARD_direct \ - --priority 0 \ - --rule '-i br0 -j ACCEPT' \ - --state absent --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__iptables_rule(7) -- firewalld(8) - - -COPYING -------- -Copyright \(C) 2015 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__git/man.text b/cdist/conf/type/__git/man.rst similarity index 60% rename from cdist/conf/type/__git/man.text rename to cdist/conf/type/__git/man.rst index 5f74108b..75f6e48b 100644 --- a/cdist/conf/type/__git/man.text +++ b/cdist/conf/type/__git/man.rst @@ -1,13 +1,10 @@ cdist-type__git(7) ================== +Get and or keep git repositories up-to-date + Nico Schottelius -NAME ----- -cdist-type__git - Get and or keep git repositories up-to-date - - DESCRIPTION ----------- This cdist type allows you to clone git repositories @@ -15,43 +12,43 @@ This cdist type allows you to clone git repositories REQUIRED PARAMETERS ------------------- -source:: +source Specifies the git remote to clone from OPTIONAL PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present" -branch:: +branch Create this branch by checking out the remote branch of this name Default branch is "master" -group:: +group Group to chgrp to. -mode:: +mode Unix permissions, suitable for chmod. -owner:: +owner User to chown to. EXAMPLES -------- --------------------------------------------------------------------------------- -__git /home/services/dokuwiki --source git://github.com/splitbrain/dokuwiki.git +.. code-block:: sh -# Checkout cdist, stay on branch 2.1 -__git /home/nico/cdist --source git://github.com/telmich/cdist.git --branch 2.1 --------------------------------------------------------------------------------- + __git /home/services/dokuwiki --source git://github.com/splitbrain/dokuwiki.git + + # Checkout cdist, stay on branch 2.1 + __git /home/nico/cdist --source git://github.com/telmich/cdist.git --branch 2.1 SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__group/man.text b/cdist/conf/type/__group/man.rst similarity index 53% rename from cdist/conf/type/__group/man.text rename to cdist/conf/type/__group/man.rst index 8a441923..912dd226 100644 --- a/cdist/conf/type/__group/man.text +++ b/cdist/conf/type/__group/man.rst @@ -1,13 +1,10 @@ cdist-type__group(7) ==================== +Manage groups + Steven Armstrong -NAME ----- -cdist-type__group - Manage groups - - DESCRIPTION ----------- This cdist type allows you to create or modify groups on the target. @@ -20,58 +17,58 @@ None. OPTIONAL PARAMETERS ------------------- -state:: +state absent or present, defaults to present -gid:: +gid see groupmod(8) -password:: +password see above BOOLEAN PARAMETERS ------------------ -system:: +system see groupadd(8), apply only on group creation MESSAGES -------- -mod:: +mod group is modified -add:: +add New group added -remove:: +remove group is removed -change :: +change Changed group property from current_value to new_value -set :: +set set property to new value, property was not set before EXAMPLES -------- --------------------------------------------------------------------------------- -# Create a group 'foobar' with operating system default settings -__group foobar +.. code-block:: sh -# Remove the 'foobar' group -__group foobar --state absent + # Create a group 'foobar' with operating system default settings + __group foobar -# Create a system group 'myservice' with operating system default settings -__group myservice --system + # Remove the 'foobar' group + __group foobar --state absent -# Same but with a specific gid -__group foobar --gid 1234 + # Create a system group 'myservice' with operating system default settings + __group myservice --system -# Same but with a gid and password -__group foobar --gid 1234 --password 'crypted-password-string' --------------------------------------------------------------------------------- + # Same but with a specific gid + __group foobar --gid 1234 + + # Same but with a gid and password + __group foobar --gid 1234 --password 'crypted-password-string' SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__hostname/man.text b/cdist/conf/type/__hostname/man.rst similarity index 63% rename from cdist/conf/type/__hostname/man.text rename to cdist/conf/type/__hostname/man.rst index ac44d426..32d452f7 100644 --- a/cdist/conf/type/__hostname/man.text +++ b/cdist/conf/type/__hostname/man.rst @@ -1,13 +1,10 @@ cdist-type__hostname(7) ======================= +Set the hostname + Steven Armstrong -NAME ----- -cdist-type__hostname - set the hostname - - DESCRIPTION ----------- Set's the hostname on various operating systems. @@ -19,31 +16,31 @@ None. OPTIONAL PARAMETERS ------------------- -name:: +name The hostname to set. Defaults to the first segment of __target_host (${__target_host%%.*}) MESSAGES -------- -changed:: +changed Changed the hostname EXAMPLES -------- --------------------------------------------------------------------------------- -# take hostname from __target_host -__hostname +.. code-block:: sh -# set hostname explicitly -__hostname --name some-static-hostname --------------------------------------------------------------------------------- + # take hostname from __target_host + __hostname + + # set hostname explicitly + __hostname --name some-static-hostname SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__iptables_apply/man.text b/cdist/conf/type/__iptables_apply/man.rst similarity index 83% rename from cdist/conf/type/__iptables_apply/man.text rename to cdist/conf/type/__iptables_apply/man.rst index 87f4b4ee..40605351 100644 --- a/cdist/conf/type/__iptables_apply/man.text +++ b/cdist/conf/type/__iptables_apply/man.rst @@ -1,13 +1,10 @@ cdist-type__iptables_apply(7) ============================= +Apply the rules + Nico Schottelius -NAME ----- -cdist-type__iptables_apply - Apply the rules - - DESCRIPTION ----------- This cdist type deploys an init script that triggers @@ -31,8 +28,8 @@ None (__iptables_apply is used by __iptables_rule) SEE ALSO -------- -- cdist-type(7) -- cdist-type__iptables_rule(7) +- `cdist-type(7) `_ +- `cdist-type__iptables_rule(7) `_ - iptables(8) diff --git a/cdist/conf/type/__iptables_rule/man.rst b/cdist/conf/type/__iptables_rule/man.rst new file mode 100644 index 00000000..5ee02f9c --- /dev/null +++ b/cdist/conf/type/__iptables_rule/man.rst @@ -0,0 +1,60 @@ +cdist-type__iptables_rule(7) +============================ +Deploy iptable rulesets + +Nico Schottelius + + +DESCRIPTION +----------- +This cdist type allows you to manage iptable rules +in a distribution independent manner. + + +REQUIRED PARAMETERS +------------------- +rule + The rule to apply. Essentially an iptables command + line without iptables in front of it. + + +OPTIONAL PARAMETERS +------------------- +state + 'present' or 'absent', defaults to 'present' + + +EXAMPLES +-------- + +.. code-block:: sh + + # Deploy some policies + __iptables_rule policy-in --rule "-P INPUT DROP" + __iptables_rule policy-out --rule "-P OUTPUT ACCEPT" + __iptables_rule policy-fwd --rule "-P FORWARD DROP" + + # The usual established rule + __iptables_rule established --rule "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT" + + # Some service rules + __iptables_rule http --rule "-A INPUT -p tcp --dport 80 -j ACCEPT" + __iptables_rule ssh --rule "-A INPUT -p tcp --dport 22 -j ACCEPT" + __iptables_rule https --rule "-A INPUT -p tcp --dport 443 -j ACCEPT" + + # Ensure some rules are not present anymore + __iptables_rule munin --rule "-A INPUT -p tcp --dport 4949 -j ACCEPT" \ + --state absent + + +SEE ALSO +-------- +- `cdist-type(7) `_ +- `cdist-type__iptables_apply(7) `_ +- iptables(8) + + +COPYING +------- +Copyright \(C) 2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__iptables_rule/man.text b/cdist/conf/type/__iptables_rule/man.text deleted file mode 100644 index 2f5b9785..00000000 --- a/cdist/conf/type/__iptables_rule/man.text +++ /dev/null @@ -1,64 +0,0 @@ -cdist-type__iptables_rule(7) -============================ -Nico Schottelius - - -NAME ----- -cdist-type__iptables_rule - Deploy iptable rulesets - - -DESCRIPTION ------------ -This cdist type allows you to manage iptable rules -in a distribution independent manner. - - -REQUIRED PARAMETERS -------------------- -rule:: - The rule to apply. Essentially an iptables command - line without iptables in front of it. - - -OPTIONAL PARAMETERS -------------------- -state:: - 'present' or 'absent', defaults to 'present' - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Deploy some policies -__iptables_rule policy-in --rule "-P INPUT DROP" -__iptables_rule policy-out --rule "-P OUTPUT ACCEPT" -__iptables_rule policy-fwd --rule "-P FORWARD DROP" - -# The usual established rule -__iptables_rule established --rule "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT" - -# Some service rules -__iptables_rule http --rule "-A INPUT -p tcp --dport 80 -j ACCEPT" -__iptables_rule ssh --rule "-A INPUT -p tcp --dport 22 -j ACCEPT" -__iptables_rule https --rule "-A INPUT -p tcp --dport 443 -j ACCEPT" - -# Ensure some rules are not present anymore -__iptables_rule munin --rule "-A INPUT -p tcp --dport 4949 -j ACCEPT" \ - --state absent - --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__iptables_apply(7) -- iptables(8) - - -COPYING -------- -Copyright \(C) 2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__issue/man.text b/cdist/conf/type/__issue/man.rst similarity index 62% rename from cdist/conf/type/__issue/man.text rename to cdist/conf/type/__issue/man.rst index 40ed920e..4a6c1f8d 100644 --- a/cdist/conf/type/__issue/man.text +++ b/cdist/conf/type/__issue/man.rst @@ -1,13 +1,10 @@ cdist-type__issue(7) ==================== +Manage issue + Nico Schottelius -NAME ----- -cdist-type__issue - Manage issue - - DESCRIPTION ----------- This cdist type allows you to easily setup /etc/issue. @@ -20,7 +17,7 @@ None. OPTIONAL PARAMETERS ------------------- -source:: +source If supplied, use this file as /etc/issue instead of default. @@ -28,17 +25,17 @@ source:: EXAMPLES -------- --------------------------------------------------------------------------------- -__issue +.. code-block:: sh -# When called from another type -__issue --source "$__type/files/myfancyissue" --------------------------------------------------------------------------------- + __issue + + # When called from another type + __issue --source "$__type/files/myfancyissue" SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__jail/man.text b/cdist/conf/type/__jail/man.rst similarity index 64% rename from cdist/conf/type/__jail/man.text rename to cdist/conf/type/__jail/man.rst index be27e909..38ec4f96 100644 --- a/cdist/conf/type/__jail/man.text +++ b/cdist/conf/type/__jail/man.rst @@ -1,13 +1,10 @@ cdist-type__jail(7) =================== +Manage FreeBSD jails + Jake Guffey -NAME ----- -cdist-type__jail - Manage FreeBSD jails - - DESCRIPTION ----------- This type is used on FreeBSD to manage jails. @@ -15,47 +12,47 @@ This type is used on FreeBSD to manage jails. REQUIRED PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present". -jailbase:: +jailbase The location of the .tgz archive containing the base fs for your jails. OPTIONAL PARAMETERS ------------------- -name:: +name The name of the jail. Default is to use the object_id as the jail name. -ip:: +ip The ifconfig style IP/netmask combination to use for the jail guest. If the state parameter is "present," this parameter is required. -hostname:: +hostname The FQDN to use for the jail guest. Defaults to the name parameter. -interface:: +interface The name of the physical interface on the jail server to bind the jail to. Defaults to the first interface found in the output of ifconfig -l. -devfs-ruleset:: +devfs-ruleset The name of the devfs ruleset to associate with the jail. Defaults to "jailrules." This ruleset must be copied to the server via another type. To use this option, devfs-enable must be "true." -jaildir:: +jaildir The location on the remote server to use for hosting jail filesystems. Defaults to /usr/jail. BOOLEAN PARAMETERS ------------------ -stopped:: +stopped Do not start the jail -devfs-disable:: +devfs-disable Whether to disallow devfs mounting within the jail -onboot:: +onboot Whether to add the jail to rc.conf's jail_list variable. @@ -69,48 +66,48 @@ means. MESSAGES -------- -start:: +start The jail was started -stop:: +stop The jail was stopped create: The jail was created -delete:: +delete The jail was deleted -onboot:: +onboot The jail was configured to start on boot EXAMPLES -------- --------------------------------------------------------------------------------- -# Create a jail called www -__jail www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz +.. code-block:: sh -# Remove the jail called www -__jail www --state absent --jailbase /my/jail/base.tgz + # Create a jail called www + __jail www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz -# The jail www should not be started -__jail www --state present --stopped \ - --ip "192.168.1.2 netmask 255.255.255.0" \ - --jailbase /my/jail/base.tgz + # Remove the jail called www + __jail www --state absent --jailbase /my/jail/base.tgz -# Use the name variable explicitly -__jail thisjail --state present --name www \ - --ip "192.168.1.2" \ - --jailbase /my/jail/base.tgz + # The jail www should not be started + __jail www --state present --stopped \ + --ip "192.168.1.2 netmask 255.255.255.0" \ + --jailbase /my/jail/base.tgz -# Go nuts -__jail lotsofoptions --state present --name testjail \ - --ip "192.168.1.100 netmask 255.255.255.0" \ - --hostname "testjail.example.com" --interface "em0" \ - --onboot --jailbase /my/jail/base.tgz --jaildir /jails --------------------------------------------------------------------------------- + # Use the name variable explicitly + __jail thisjail --state present --name www \ + --ip "192.168.1.2" \ + --jailbase /my/jail/base.tgz + + # Go nuts + __jail lotsofoptions --state present --name testjail \ + --ip "192.168.1.100 netmask 255.255.255.0" \ + --hostname "testjail.example.com" --interface "em0" \ + --onboot --jailbase /my/jail/base.tgz --jaildir /jails SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__key_value/man.text b/cdist/conf/type/__key_value/man.rst similarity index 64% rename from cdist/conf/type/__key_value/man.text rename to cdist/conf/type/__key_value/man.rst index c27931e5..4b259c75 100644 --- a/cdist/conf/type/__key_value/man.text +++ b/cdist/conf/type/__key_value/man.rst @@ -1,13 +1,10 @@ cdist-type__key_value(7) ======================== +Change property values in files + Steven Armstrong -NAME ----- -cdist-type__key_value - Change property values in files - - DESCRIPTION ----------- This cdist type allows you to change values in a key value based config @@ -16,22 +13,22 @@ file. REQUIRED PARAMETERS ------------------- -file:: +file The file to operate on. -delimiter:: +delimiter The delimiter which separates the key from the value. OPTIONAL PARAMETERS ------------------- -state:: +state present or absent, defaults to present. If present, sets the key to value, if absent, removes the key from the file. -key:: +key The key to change. Defaults to object_id. -value:: +value The value for the key. Optional if state=absent, required otherwise. -comment:: +comment If supplied, the value will be inserted before the line with the key, but only if the key or value must be changed. You need to ensure yourself that the line is prefixed with the correct @@ -40,41 +37,41 @@ comment:: BOOLEAN PARAMETERS ------------------ -exact_delimiter:: +exact_delimiter If supplied, treat additional whitespaces between key, delimiter and value as wrong value. MESSAGES -------- -remove:: +remove Removed existing key and value -insert:: +insert Added key and value -change:: +change Changed value of existing key -create:: +create A new line was inserted in a new file EXAMPLES -------- --------------------------------------------------------------------------------- -# Set the maximum system user id -__key_value SYS_UID_MAX --file /etc/login.defs --value 666 --delimiter ' ' +.. code-block:: sh -# Same with fancy id -__key_value my-fancy-id --file /etc/login.defs --key SYS_UID_MAX --value 666 \ - --delimiter ' ' + # Set the maximum system user id + __key_value SYS_UID_MAX --file /etc/login.defs --value 666 --delimiter ' ' -# Enable packet forwarding -__key_value net.ipv4.ip_forward --file /etc/sysctl.conf --value 1 \ - --delimiter ' = ' --comment '# my linux kernel should act as a router' + # Same with fancy id + __key_value my-fancy-id --file /etc/login.defs --key SYS_UID_MAX --value 666 \ + --delimiter ' ' -# Remove existing key/value -__key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '=' --------------------------------------------------------------------------------- + # Enable packet forwarding + __key_value net.ipv4.ip_forward --file /etc/sysctl.conf --value 1 \ + --delimiter ' = ' --comment '# my linux kernel should act as a router' + + # Remove existing key/value + __key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '=' MORE INFORMATION @@ -85,7 +82,7 @@ So you need to exactly specify the key and delimiter. Delimiter can be of any le SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__line/man.text b/cdist/conf/type/__line/man.rst similarity index 59% rename from cdist/conf/type/__line/man.text rename to cdist/conf/type/__line/man.rst index f39ee929..f6d71a5a 100644 --- a/cdist/conf/type/__line/man.text +++ b/cdist/conf/type/__line/man.rst @@ -1,13 +1,10 @@ cdist-type__line(7) =================== +Manage lines in files + Nico Schottelius -NAME ----- -cdist-type__line - Manage lines in files - - DESCRIPTION ----------- This cdist type allows you to add lines and remove lines from files. @@ -18,16 +15,16 @@ REQUIRED PARAMETERS OPTIONAL PARAMETERS ------------------- -state:: +state 'present' or 'absent', defaults to 'present' -line:: +line Specifies the line which should be absent or present Must be present, if state is present. Must not be combined with regex, if state is absent. -regex:: +regex If state is present, search for this pattern and add given line, if the given regular expression does not match. @@ -38,7 +35,7 @@ regex:: Must not be combined with line, if state is absent. -file:: +file If supplied, use this as the destination file. Otherwise the object_id is used. @@ -46,24 +43,24 @@ file:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Manage the DAEMONS line in rc.conf -__line daemons --file /etc/rc.conf --line 'DAEMONS=(hwclock !network sshd crond postfix)' +.. code-block:: sh -# Ensure the home mount is present in /etc/fstab - explicitly make it present -__line home-fstab \ - --file /etc/fstab \ - --line 'filer.fs:/vol/home /home nfs defaults 0 0' \ - --state present + # Manage the DAEMONS line in rc.conf + __line daemons --file /etc/rc.conf --line 'DAEMONS=(hwclock !network sshd crond postfix)' -# Removes the line specifiend in "include_www" from the file "lighttpd.conf" -__line legacy_timezone --file /etc/rc.conf --regex 'TIMEZONE=.*' --state absent --------------------------------------------------------------------------------- + # Ensure the home mount is present in /etc/fstab - explicitly make it present + __line home-fstab \ + --file /etc/fstab \ + --line 'filer.fs:/vol/home /home nfs defaults 0 0' \ + --state present + + # Removes the line specifiend in "include_www" from the file "lighttpd.conf" + __line legacy_timezone --file /etc/rc.conf --regex 'TIMEZONE=.*' --state absent SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - grep(1) diff --git a/cdist/conf/type/__link/man.text b/cdist/conf/type/__link/man.rst similarity index 51% rename from cdist/conf/type/__link/man.text rename to cdist/conf/type/__link/man.rst index 663087db..654b097b 100644 --- a/cdist/conf/type/__link/man.text +++ b/cdist/conf/type/__link/man.rst @@ -1,13 +1,10 @@ cdist-type__link(7) =================== +Manage links (hard and symbolic) + Nico Schottelius -NAME ----- -cdist-type__link - Manage links (hard and symbolic) - - DESCRIPTION ----------- This cdist type allows you to manage hard and symbolic links. @@ -16,42 +13,42 @@ The given object id is the destination for the link. REQUIRED PARAMETERS ------------------- -source:: +source Specifies the link source. -type:: +type Specifies the link type: Either hard or symoblic. OPTIONAL PARAMETERS ------------------- -state:: +state 'present' or 'absent', defaults to 'present' EXAMPLES -------- --------------------------------------------------------------------------------- -# Create hard link of /etc/shadow -__link /root/shadow --source /etc/shadow --type hard +.. code-block:: sh -# Relative symbolic link -__link /etc/apache2/sites-enabled/www.test.ch \ - --source ../sites-available/www.test.ch \ - --type symbolic + # Create hard link of /etc/shadow + __link /root/shadow --source /etc/shadow --type hard -# Absolute symbolic link -__link /opt/plone --source /home/services/plone --type symbolic + # Relative symbolic link + __link /etc/apache2/sites-enabled/www.test.ch \ + --source ../sites-available/www.test.ch \ + --type symbolic -# Remove link -__link /opt/plone --state absent --------------------------------------------------------------------------------- + # Absolute symbolic link + __link /opt/plone --source /home/services/plone --type symbolic + + # Remove link + __link /opt/plone --state absent SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__locale/man.text b/cdist/conf/type/__locale/man.rst similarity index 53% rename from cdist/conf/type/__locale/man.text rename to cdist/conf/type/__locale/man.rst index 5ccd3eab..df337739 100644 --- a/cdist/conf/type/__locale/man.text +++ b/cdist/conf/type/__locale/man.rst @@ -1,13 +1,10 @@ cdist-type__locale(7) ===================== +Configure locales + Nico Schottelius -NAME ----- -cdist-type__locale - Configure locales - - DESCRIPTION ----------- This cdist type allows you to setup locales. @@ -15,30 +12,30 @@ This cdist type allows you to setup locales. OPTIONAL PARAMETERS ------------------- -state:: +state 'present' or 'absent', defaults to present EXAMPLES -------- --------------------------------------------------------------------------------- -# Add locale de_CH.UTF-8 -__locale de_CH.UTF-8 +.. code-block:: sh -# Same as above, but more explicit -__locale de_CH.UTF-8 --state present + # Add locale de_CH.UTF-8 + __locale de_CH.UTF-8 -# Remove colourful British English -__locale en_GB.UTF-8 --state absent --------------------------------------------------------------------------------- + # Same as above, but more explicit + __locale de_CH.UTF-8 --state present + + # Remove colourful British English + __locale en_GB.UTF-8 --state absent SEE ALSO -------- - locale(1) - localedef(1) -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__motd/man.text b/cdist/conf/type/__motd/man.rst similarity index 63% rename from cdist/conf/type/__motd/man.text rename to cdist/conf/type/__motd/man.rst index a4ca80b5..988e2d02 100644 --- a/cdist/conf/type/__motd/man.text +++ b/cdist/conf/type/__motd/man.rst @@ -1,13 +1,10 @@ cdist-type__motd(7) =================== +Manage message of the day + Nico Schottelius -NAME ----- -cdist-type__motd - Manage message of the day - - DESCRIPTION ----------- This cdist type allows you to easily setup /etc/motd. @@ -20,7 +17,7 @@ None. OPTIONAL PARAMETERS ------------------- -source:: +source If supplied, copy this file from the host running cdist to the target. If not supplied, a default message will be placed onto the target. @@ -28,18 +25,18 @@ source:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Use cdist defaults -__motd +.. code-block:: sh -# Supply source file from a different type -__motd --source "$__type/files/my-motd" --------------------------------------------------------------------------------- + # Use cdist defaults + __motd + + # Supply source file from a different type + __motd --source "$__type/files/my-motd" SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__mount/man.text b/cdist/conf/type/__mount/man.rst similarity index 66% rename from cdist/conf/type/__mount/man.text rename to cdist/conf/type/__mount/man.rst index 7299bdf3..696dfbd4 100644 --- a/cdist/conf/type/__mount/man.text +++ b/cdist/conf/type/__mount/man.rst @@ -1,13 +1,10 @@ cdist-type__mount(7) ==================== +Manage filesystem mounts + Steven Armstrong -NAME ----- -cdist-type__mount - manage filesystem mounts - - DESCRIPTION ----------- Manage filesystem mounts either via /etc/fstab or manually. @@ -20,62 +17,62 @@ None. OPTIONAL PARAMETERS ------------------- -device:: +device device to mount at path, defaults to 'none'. see mount(8) -dump:: +dump value for the dump field in fstab. see fstab(5) defaults to 0. This parameter is ignored, if the nofstab parameter is given. -options:: +options comma separated string of options, see mount(8) -pass:: +pass value for the pass field in fstab. see fstab(5) defaults to 0. This parameter is ignored, if the nofstab parameter is given. -path:: +path mount point where to mount the device, see mount(8). Defaults to __object_id -state:: +state either present or absent. Defaults to present. -type:: +type vfstype, see mount(8) BOOLEAN PARAMETERS ------------------ -nofstab:: +nofstab do not manage an entry in /etc/fstab EXAMPLES -------- --------------------------------------------------------------------------------- -__mount /some/dir \ - --device /dev/sdc3 \ - --type xfs \ - --options "defaults,ro" - --dump 0 \ - --pass 1 +.. code-block:: sh -__mount /var/lib/one \ - --device mfsmount \ - --type fuse \ - --options "mfsmaster=mfsmaster.domain.tld,mfssubfolder=/one,nonempty,_netdev" --------------------------------------------------------------------------------- + __mount /some/dir \ + --device /dev/sdc3 \ + --type xfs \ + --options "defaults,ro" + --dump 0 \ + --pass 1 + + __mount /var/lib/one \ + --device mfsmount \ + --type fuse \ + --options "mfsmaster=mfsmaster.domain.tld,mfssubfolder=/one,nonempty,_netdev" SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__mysql_database/man.text b/cdist/conf/type/__mysql_database/man.rst similarity index 65% rename from cdist/conf/type/__mysql_database/man.text rename to cdist/conf/type/__mysql_database/man.rst index f184a30e..88f1eecd 100644 --- a/cdist/conf/type/__mysql_database/man.text +++ b/cdist/conf/type/__mysql_database/man.rst @@ -1,13 +1,10 @@ cdist-type__mysql_database(7) ============================= +Manage a MySQL database + Benedikt Koeppel -NAME ----- -cdist-type__mysql_database - Manage a MySQL database - - DESCRIPTION ----------- This cdist type allows you to install a MySQL database. @@ -19,28 +16,28 @@ None. OPTIONAL PARAMETERS ------------------- -name:: +name The name of the database to install defaults to the object id -user:: +user A user that should have access to the database -password:: +password The password for the user who manages the database EXAMPLES -------- --------------------------------------------------------------------------------- -__mysql_database "cdist" --name "cdist" --user "myuser" --password "mypwd" --------------------------------------------------------------------------------- +.. code-block:: sh + + __mysql_database "cdist" --name "cdist" --user "myuser" --password "mypwd" SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__package/man.text b/cdist/conf/type/__package/man.rst similarity index 61% rename from cdist/conf/type/__package/man.text rename to cdist/conf/type/__package/man.rst index 90d71e02..1ada06a7 100644 --- a/cdist/conf/type/__package/man.text +++ b/cdist/conf/type/__package/man.rst @@ -1,13 +1,10 @@ cdist-type__package(7) ====================== +Manage packages + Steven Armstrong -NAME ----- -cdist-type__package - Manage packages - - DESCRIPTION ----------- This cdist type allows you to install or uninstall packages on the target. @@ -21,40 +18,41 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name The name of the package to install. Default is to use the object_id as the package name. -version:: +version The version of the package to install. Default is to install the version chosen by the local package manager. -type:: +type The package type to use. Default is determined based on the $os explorer variable. - e.g. __package_apt for Debian - __package_emerge for Gentoo + e.g. + * __package_apt for Debian + * __package_emerge for Gentoo -state:: +state Either "present" or "absent", defaults to "present" EXAMPLES -------- --------------------------------------------------------------------------------- -# Install the package vim on the target -__package vim --state present +.. code-block:: sh -# Same but install specific version -__package vim --state present --version 7.3.50 + # Install the package vim on the target + __package vim --state present -# Force use of a specific package type -__package vim --state present --type __package_apt --------------------------------------------------------------------------------- + # Same but install specific version + __package vim --state present --version 7.3.50 + + # Force use of a specific package type + __package vim --state present --type __package_apt SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__package_apt/man.text b/cdist/conf/type/__package_apt/man.rst similarity index 58% rename from cdist/conf/type/__package_apt/man.text rename to cdist/conf/type/__package_apt/man.rst index c1f8ee1f..ec28c0cc 100644 --- a/cdist/conf/type/__package_apt/man.text +++ b/cdist/conf/type/__package_apt/man.rst @@ -1,13 +1,10 @@ cdist-type__package_apt(7) ========================== +Manage packages with apt-get + Nico Schottelius -NAME ----- -cdist-type__package_apt - Manage packages with apt-get - - DESCRIPTION ----------- apt-get is usually used on Debian and variants (like Ubuntu) to @@ -21,35 +18,35 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -state:: +state Either "present" or "absent", defaults to "present" -target-release:: +target-release Passed on to apt-get install, see apt-get(8). Essentially allows you to retrieve packages from a different release EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure zsh in installed -__package_apt zsh --state present +.. code-block:: sh -# In case you only want *a* webserver, but don't care which one -__package_apt webserver --state present --name nginx + # Ensure zsh in installed + __package_apt zsh --state present -# Remove obsolete package -__package_apt puppet --state absent --------------------------------------------------------------------------------- + # In case you only want *a* webserver, but don't care which one + __package_apt webserver --state present --name nginx + + # Remove obsolete package + __package_apt puppet --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__package_emerge/man.text b/cdist/conf/type/__package_emerge/man.rst similarity index 58% rename from cdist/conf/type/__package_emerge/man.text rename to cdist/conf/type/__package_emerge/man.rst index 983b49a8..fe06031e 100644 --- a/cdist/conf/type/__package_emerge/man.text +++ b/cdist/conf/type/__package_emerge/man.rst @@ -1,13 +1,10 @@ cdist-type__package_emerge(7) ============================= +Manage packages with portage + Thomas Oettli -NAME ----- -cdist-type__package_emerge - Manage packages with portage - - DESCRIPTION ----------- Portage is usually used on the gentoo distribution to manage packages. @@ -23,35 +20,35 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -state:: +state Either "present" or "absent", defaults to "present". -version:: +version If supplied, use to install or uninstall a specific version of the package named. EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure sys-devel/gcc is installed -__package_emerge sys-devel/gcc --state present +.. code-block:: sh -# If you want a specific version of a package -__package_emerge app-portage/gentoolkit --state present --version 0.3.0.8-r2 + # Ensure sys-devel/gcc is installed + __package_emerge sys-devel/gcc --state present -# Remove package -__package_emerge sys-devel/gcc --state absent --------------------------------------------------------------------------------- + # If you want a specific version of a package + __package_emerge app-portage/gentoolkit --state present --version 0.3.0.8-r2 + + # Remove package + __package_emerge sys-devel/gcc --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) -- cdist-type__package_emerge_dependencies(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ +- `cdist-type__package_emerge_dependencies(7) `_ COPYING diff --git a/cdist/conf/type/__package_emerge_dependencies/man.text b/cdist/conf/type/__package_emerge_dependencies/man.rst similarity index 55% rename from cdist/conf/type/__package_emerge_dependencies/man.text rename to cdist/conf/type/__package_emerge_dependencies/man.rst index 0862256b..21af86e3 100644 --- a/cdist/conf/type/__package_emerge_dependencies/man.text +++ b/cdist/conf/type/__package_emerge_dependencies/man.rst @@ -1,19 +1,17 @@ cdist-type__package_emerge_dependencies(7) ========================================== +Install dependencies for __package_emerge + Thomas Oettli -NAME ----- -cdist-type__package_emerge_dependencies - Install dependencies for __package_emerge - - DESCRIPTION ----------- Portage is usually used on the gentoo distribution to manage packages. This type installs the following tools which are required by __package_emerge to work: -app-portage/flaggie -app-portage/gentoolkit + +* app-portage/flaggie +* app-portage/gentoolkit REQUIRED PARAMETERS @@ -29,17 +27,17 @@ None EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure app-portage/flaggie and app-portage/gentoolkit are installed -__package_emerge_dependencies --------------------------------------------------------------------------------- +.. code-block:: sh + + # Ensure app-portage/flaggie and app-portage/gentoolkit are installed + __package_emerge_dependencies SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) -- cdist-type__package_emerge(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ +- `cdist-type__package_emerge(7) `_ COPYING diff --git a/cdist/conf/type/__package_luarocks/man.text b/cdist/conf/type/__package_luarocks/man.rst similarity index 59% rename from cdist/conf/type/__package_luarocks/man.text rename to cdist/conf/type/__package_luarocks/man.rst index 657f68e5..ff7fea83 100644 --- a/cdist/conf/type/__package_luarocks/man.text +++ b/cdist/conf/type/__package_luarocks/man.rst @@ -1,13 +1,10 @@ cdist-type__package_luarocks(7) =============================== +Manage luarocks packages + Christian G. Warden -NAME ----- -cdist-type__package_luarocks - Manage luarocks packages - - DESCRIPTION ----------- LuaRocks is a deployment and management system for Lua modules. @@ -20,29 +17,29 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -state:: +state Either "present" or "absent", defaults to "present" EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure luasocket is installed -__package_luarocks luasocket --state present +.. code-block:: sh -# Remove package -__package_luarocks luasocket --state absent --------------------------------------------------------------------------------- + # Ensure luasocket is installed + __package_luarocks luasocket --state present + + # Remove package + __package_luarocks luasocket --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__package_opkg/man.text b/cdist/conf/type/__package_opkg/man.rst similarity index 57% rename from cdist/conf/type/__package_opkg/man.text rename to cdist/conf/type/__package_opkg/man.rst index aeb0a1c5..9af17988 100644 --- a/cdist/conf/type/__package_opkg/man.text +++ b/cdist/conf/type/__package_opkg/man.rst @@ -1,13 +1,10 @@ cdist-type__package_opkg(7) -========================== +=========================== +Manage packages with opkg + Giel van Schijndel -NAME ----- -cdist-type__package_opkg - Manage packages with opkg - - DESCRIPTION ----------- opkg is usually used on OpenWRT to manage packages. @@ -20,29 +17,29 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -state:: +state Either "present" or "absent", defaults to "present" EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure lsof is installed -__package_opkg lsof --state present +.. code-block:: sh -# Remove obsolete package -__package_opkg dnsmasq --state absent --------------------------------------------------------------------------------- + # Ensure lsof is installed + __package_opkg lsof --state present + + # Remove obsolete package + __package_opkg dnsmasq --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__package_pacman/man.text b/cdist/conf/type/__package_pacman/man.rst similarity index 54% rename from cdist/conf/type/__package_pacman/man.text rename to cdist/conf/type/__package_pacman/man.rst index 2e24ecd9..3d8845a5 100644 --- a/cdist/conf/type/__package_pacman/man.text +++ b/cdist/conf/type/__package_pacman/man.rst @@ -1,13 +1,10 @@ cdist-type__package_pacman(7) ============================= +Manage packages with pacman + Nico Schottelius -NAME ----- -cdist-type__package_pacman - Manage packages with pacman - - DESCRIPTION ----------- Pacman is usually used on the Archlinux distribution to manage packages. @@ -20,32 +17,32 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -state:: +state Either "present" or "absent", defaults to "present" EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure zsh in installed -__package_pacman zsh --state present +.. code-block:: sh -# If you don't want to follow pythonX packages, but always use python -__package_pacman python --state present --name python2 + # Ensure zsh in installed + __package_pacman zsh --state present -# Remove obsolete package -__package_pacman puppet --state absent --------------------------------------------------------------------------------- + # If you don't want to follow pythonX packages, but always use python + __package_pacman python --state present --name python2 + + # Remove obsolete package + __package_pacman puppet --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__package_pip/man.text b/cdist/conf/type/__package_pip/man.rst similarity index 55% rename from cdist/conf/type/__package_pip/man.text rename to cdist/conf/type/__package_pip/man.rst index 5b67e62f..b312fff5 100644 --- a/cdist/conf/type/__package_pip/man.text +++ b/cdist/conf/type/__package_pip/man.rst @@ -1,13 +1,10 @@ cdist-type__package_pip(7) ========================== +Manage packages with pip + Nico Schottelius -NAME ----- -cdist-type__package_pip - Manage packages with pip - - DESCRIPTION ----------- Pip is used in Python environments to install packages. @@ -21,38 +18,38 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -pip:: +pip Instead of using pip from PATH, use the specific pip path. -state:: +state Either "present" or "absent", defaults to "present" -runas:: +runas Run pip as specified user. By default it runs as root. EXAMPLES -------- --------------------------------------------------------------------------------- -# Install a package -__package_pip pyro --state present +.. code-block:: sh -# Use pip in a virtualenv located at /root/shinken_virtualenv -__package_pip pyro --state present --pip /root/shinken_virtualenv/bin/pip + # Install a package + __package_pip pyro --state present -# Use pip in a virtualenv located at /foo/shinken_virtualenv as user foo -__package_pip pyro --state present --pip /foo/shinken_virtualenv/bin/pip --runas foo --------------------------------------------------------------------------------- + # Use pip in a virtualenv located at /root/shinken_virtualenv + __package_pip pyro --state present --pip /root/shinken_virtualenv/bin/pip + + # Use pip in a virtualenv located at /foo/shinken_virtualenv as user foo + __package_pip pyro --state present --pip /foo/shinken_virtualenv/bin/pip --runas foo SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__package_pkg_freebsd/man.text b/cdist/conf/type/__package_pkg_freebsd/man.rst similarity index 53% rename from cdist/conf/type/__package_pkg_freebsd/man.text rename to cdist/conf/type/__package_pkg_freebsd/man.rst index 71387148..c728cc9a 100644 --- a/cdist/conf/type/__package_pkg_freebsd/man.text +++ b/cdist/conf/type/__package_pkg_freebsd/man.rst @@ -1,13 +1,10 @@ cdist-type__package_pkg_freebsd(7) ================================== +Manage FreeBSD packages + Jake Guffey -NAME ----- -cdist-type__package_pkg_freebsd - Manage FreeBSD packages - - DESCRIPTION ----------- This type is usually used on FreeBSD to manage packages. @@ -20,44 +17,44 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -flavor:: +flavor If supplied, use to avoid ambiguity. -version:: +version If supplied, use to install a specific version of the package named. -pkgsite:: +pkgsite If supplied, use to install from a specific package repository. -state:: +state Either "present" or "absent", defaults to "present" EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure zsh is installed -__package_pkg_freebsd zsh --state present +.. code-block:: sh -# Ensure vim is installed, use flavor no_x11 -__package_pkg_freebsd vim --state present --flavor no_x11 + # Ensure zsh is installed + __package_pkg_freebsd zsh --state present -# If you don't want to follow pythonX packages, but always use python -__package_pkg_freebsd python --state present --name python2 + # Ensure vim is installed, use flavor no_x11 + __package_pkg_freebsd vim --state present --flavor no_x11 -# Remove obsolete package -__package_pkg_freebsd puppet --state absent --------------------------------------------------------------------------------- + # If you don't want to follow pythonX packages, but always use python + __package_pkg_freebsd python --state present --name python2 + + # Remove obsolete package + __package_pkg_freebsd puppet --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__package_pkg_openbsd/man.rst b/cdist/conf/type/__package_pkg_openbsd/man.rst new file mode 100644 index 00000000..f9a746b9 --- /dev/null +++ b/cdist/conf/type/__package_pkg_openbsd/man.rst @@ -0,0 +1,63 @@ +cdist-type__package_pkg(7) +========================== +Manage OpenBSD packages + +Andi Brönnimann + + +DESCRIPTION +----------- +This type is usually used on OpenBSD to manage packages. + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +name + If supplied, use the name and not the object id as the package name. + +flavor + If supplied, use to avoid ambiguity. + +state + Either "present" or "absent", defaults to "present" + +pkg_path + Manually specify a PKG_PATH to add packages from. + +EXAMPLES +-------- + +.. code-block:: sh + + # Ensure zsh is installed + __package_pkg_openbsd zsh --state present + + # Ensure vim is installed, use flavor no_x11 + __package_pkg_openbsd vim --state present --flavor no_x11 + + # If you don't want to follow pythonX packages, but always use python + __package_pkg_openbsd python --state present --name python2 + + # Remove obsolete package + __package_pkg_openbsd puppet --state absent + + # Add a package using a particular mirror + __package_pkg_openbsd bash \ + --pkg_path http://openbsd.mirrorcatalogs.com/snapshots/packages/amd64 + + +SEE ALSO +-------- +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ + + +COPYING +------- +Copyright \(C) 2011 Andi Brönnimann. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__package_pkg_openbsd/man.text b/cdist/conf/type/__package_pkg_openbsd/man.text deleted file mode 100644 index c7de2652..00000000 --- a/cdist/conf/type/__package_pkg_openbsd/man.text +++ /dev/null @@ -1,66 +0,0 @@ -cdist-type__package_pkg(7) -========================== -Andi Brönnimann - - -NAME ----- -cdist-type__package_pkg_openbsd - Manage OpenBSD packages - - -DESCRIPTION ------------ -This type is usually used on OpenBSD to manage packages. - - -REQUIRED PARAMETERS -------------------- -None - - -OPTIONAL PARAMETERS -------------------- -name:: - If supplied, use the name and not the object id as the package name. - -flavor:: - If supplied, use to avoid ambiguity. - -state:: - Either "present" or "absent", defaults to "present" - -pkg_path:: - Manually specify a PKG_PATH to add packages from. - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Ensure zsh is installed -__package_pkg_openbsd zsh --state present - -# Ensure vim is installed, use flavor no_x11 -__package_pkg_openbsd vim --state present --flavor no_x11 - -# If you don't want to follow pythonX packages, but always use python -__package_pkg_openbsd python --state present --name python2 - -# Remove obsolete package -__package_pkg_openbsd puppet --state absent - -# Add a package using a particular mirror -__package_pkg_openbsd bash \ - --pkg_path http://openbsd.mirrorcatalogs.com/snapshots/packages/amd64 --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__package(7) - - -COPYING -------- -Copyright \(C) 2011 Andi Brönnimann. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__package_pkgng_freebsd/man.text b/cdist/conf/type/__package_pkgng_freebsd/man.rst similarity index 60% rename from cdist/conf/type/__package_pkgng_freebsd/man.text rename to cdist/conf/type/__package_pkgng_freebsd/man.rst index da44da83..36f1a7d8 100644 --- a/cdist/conf/type/__package_pkgng_freebsd/man.text +++ b/cdist/conf/type/__package_pkgng_freebsd/man.rst @@ -1,13 +1,10 @@ cdist-type__package_pkgng_freebsd(7) -================================== +==================================== +Manage FreeBSD packages with pkg-ng + Jake Guffey -NAME ----- -cdist-type__package_pkgng_freebsd - Manage FreeBSD packages with pkg-ng - - DESCRIPTION ----------- This type is usually used on FreeBSD to manage packages. @@ -20,31 +17,31 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -flavor:: +flavor If supplied, use to avoid ambiguity. -version:: +version If supplied, use to install a specific version of the package named. -repo:: +repo If supplied, use to install the package named from a particular repo. -state:: +state Either "present" or "absent", defaults to "present" BOOLEAN PARAMETERS ------------------ -upgrade:: +upgrade If supplied, allow upgrading to the latest version of a package. CAVEATS ------- -This type requires that repository definitions already exist in /etc/pkg/*.conf. +This type requires that repository definitions already exist in /etc/pkg/\*.conf. Ensure that they exist prior to use of this type with __file. pkg-ng can't upgrade a package to a specific version. If this type needs to @@ -54,41 +51,41 @@ upgrade a package, it can only ugprade to the latest available version. If the MESSAGES -------- -install:: +install The package was installed -remove:: +remove The package was removed -upgrade:: +upgrade The package was upgraded -exist:: +exist The package was already present and thus not installed EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure zsh is installed -__package_pkgng_freebsd zsh --state present +.. code-block:: sh -# Ensure vim is installed, use flavor no_x11 -__package_pkgng_freebsd vim --state present --flavor no_x11 + # Ensure zsh is installed + __package_pkgng_freebsd zsh --state present -# If you don't want to follow pythonX packages, but always use python -__package_pkgng_freebsd python --state present --name python2 + # Ensure vim is installed, use flavor no_x11 + __package_pkgng_freebsd vim --state present --flavor no_x11 -# Install a package from a particular repository when multiples exist -__package_pkgng_freebsd bash --state present --repo myrepo + # If you don't want to follow pythonX packages, but always use python + __package_pkgng_freebsd python --state present --name python2 -# Remove obsolete package -__package_pkgng_freebsd puppet --state absent --------------------------------------------------------------------------------- + # Install a package from a particular repository when multiples exist + __package_pkgng_freebsd bash --state present --repo myrepo + + # Remove obsolete package + __package_pkgng_freebsd puppet --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__package_rubygem/man.text b/cdist/conf/type/__package_rubygem/man.rst similarity index 60% rename from cdist/conf/type/__package_rubygem/man.text rename to cdist/conf/type/__package_rubygem/man.rst index a808c2aa..4cb9af04 100644 --- a/cdist/conf/type/__package_rubygem/man.text +++ b/cdist/conf/type/__package_rubygem/man.rst @@ -1,13 +1,10 @@ cdist-type__package_rubygem(7) ============================== +Manage rubygem packages + Chase Allen James -NAME ----- -cdist-type__package_rubygem - Manage rubygem packages - - DESCRIPTION ----------- Rubygems is the default package management system for the Ruby programming language. @@ -20,29 +17,29 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -state:: +state Either "present" or "absent", defaults to "present" EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure sinatra is installed -__package_rubygem sinatra --state present +.. code-block:: sh -# Remove package -__package_rubygem rails --state absent --------------------------------------------------------------------------------- + # Ensure sinatra is installed + __package_rubygem sinatra --state present + + # Remove package + __package_rubygem rails --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__package_update_index/man.text b/cdist/conf/type/__package_update_index/man.rst similarity index 58% rename from cdist/conf/type/__package_update_index/man.text rename to cdist/conf/type/__package_update_index/man.rst index 6435e51d..a16d29ce 100644 --- a/cdist/conf/type/__package_update_index/man.text +++ b/cdist/conf/type/__package_update_index/man.rst @@ -1,13 +1,10 @@ cdist-type__package_update_index(7) =================================== +Update the package index + Ricardo Catalinas Jiménez -NAME ----- -cdist-type__package_update_index - Update the package index - - DESCRIPTION ----------- This cdist type allows you to update the package index on the target. @@ -21,29 +18,30 @@ None OPTIONAL PARAMETERS ------------------- -type:: +type The package manager to use. Default is determined based on the $os explorer variable. - e.g. apt for Debian - yum for Red Hat - pacman for Arch Linux + e.g. + * apt for Debian + * yum for Red Hat + * pacman for Arch Linux EXAMPLES -------- --------------------------------------------------------------------------------- -# Update the package index on the target -__package_update_index +.. code-block:: sh -# Force use of a specific package manager -__package_update_index --type apt --------------------------------------------------------------------------------- + # Update the package index on the target + __package_update_index + + # Force use of a specific package manager + __package_update_index --type apt SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__package_upgrade_all/man.text b/cdist/conf/type/__package_upgrade_all/man.rst similarity index 58% rename from cdist/conf/type/__package_upgrade_all/man.text rename to cdist/conf/type/__package_upgrade_all/man.rst index 6d3e1338..146a8259 100644 --- a/cdist/conf/type/__package_upgrade_all/man.text +++ b/cdist/conf/type/__package_upgrade_all/man.rst @@ -1,13 +1,10 @@ cdist-type__package_upgrade_all(7) ================================== +Upgrade all the installed packages + Ricardo Catalinas Jiménez -NAME ----- -cdist-type__package_upgrade_all - Upgrade all the installed packages - - DESCRIPTION ----------- This cdist type allows you to upgrade all the installed packages on the @@ -21,29 +18,30 @@ None OPTIONAL PARAMETERS ------------------- -type:: +type The package manager to use. Default is determined based on the $os explorer variable. - e.g. apt for Debian - yum for Red Hat - pacman for Arch Linux + e.g. + * apt for Debian + * yum for Red Hat + * pacman for Arch Linux EXAMPLES -------- --------------------------------------------------------------------------------- -# Upgrade all the installed packages on the target -__package_upgrade_all +.. code-block:: sh -# Force use of a specific package manager -__package_upgrade_all --type apt --------------------------------------------------------------------------------- + # Upgrade all the installed packages on the target + __package_upgrade_all + + # Force use of a specific package manager + __package_upgrade_all --type apt SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__package_yum/man.text b/cdist/conf/type/__package_yum/man.rst similarity index 54% rename from cdist/conf/type/__package_yum/man.text rename to cdist/conf/type/__package_yum/man.rst index 65e1be67..65e56c7a 100644 --- a/cdist/conf/type/__package_yum/man.text +++ b/cdist/conf/type/__package_yum/man.rst @@ -1,13 +1,10 @@ cdist-type__package_yum(7) ========================== +Manage packages with yum + Nico Schottelius -NAME ----- -cdist-type__package_yum - Manage packages with yum - - DESCRIPTION ----------- Yum is usually used on the Fedora distribution to manage packages. @@ -22,37 +19,37 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -state:: +state Either "present" or "absent", defaults to "present" -url:: +url URL to use for the package EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure zsh in installed -__package_yum zsh --state present +.. code-block:: sh -# If you don't want to follow pythonX packages, but always use python -__package_yum python --state present --name python2 + # Ensure zsh in installed + __package_yum zsh --state present -# Remove obsolete package -__package_yum puppet --state absent + # If you don't want to follow pythonX packages, but always use python + __package_yum python --state present --name python2 -__package epel-release-6-8 \ - --url http://mirror.switch.ch/ftp/mirror/epel/6/i386/epel-release-6-8.noarch.rpm --------------------------------------------------------------------------------- + # Remove obsolete package + __package_yum puppet --state absent + + __package epel-release-6-8 \ + --url http://mirror.switch.ch/ftp/mirror/epel/6/i386/epel-release-6-8.noarch.rpm SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__package_zypper/man.text b/cdist/conf/type/__package_zypper/man.rst similarity index 55% rename from cdist/conf/type/__package_zypper/man.text rename to cdist/conf/type/__package_zypper/man.rst index 94786bd9..2df22e72 100644 --- a/cdist/conf/type/__package_zypper/man.text +++ b/cdist/conf/type/__package_zypper/man.rst @@ -1,13 +1,10 @@ cdist-type__package_zypper(7) ============================= +Manage packages with zypper + Daniel Heule -NAME ----- -cdist-type__package_zypper - Manage packages with zypper - - DESCRIPTION ----------- Zypper is usually used on the SuSE distribution to manage packages. @@ -20,46 +17,46 @@ None OPTIONAL PARAMETERS ------------------- -name:: +name If supplied, use the name and not the object id as the package name. -state:: +state Either "present" or "absent", defaults to "present" -version:: +version The version of the package to install. Default is to install the version chosen by the local package manager. For a list of available versions, have a look at the output of "zypper se -s packagename" -ptype:: +ptype Either "package", "patch", "pattern", "product" or "srcpackage", defaults to "package". For a description see man zypper. EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure zsh is installed -__package_zypper zsh --state present +.. code-block:: sh -# If you don't want to follow pythonX packages, but always use python -__package_zypper python --state present --name python2 + # Ensure zsh is installed + __package_zypper zsh --state present -# Ensure binutils is installed and the version is forced to be 2.23.1-0.19.2 -__package_zypper binutils --state present --version 2.23.1-0.19.2 + # If you don't want to follow pythonX packages, but always use python + __package_zypper python --state present --name python2 -# Remove package -__package_zypper cfengine --state absent + # Ensure binutils is installed and the version is forced to be 2.23.1-0.19.2 + __package_zypper binutils --state present --version 2.23.1-0.19.2 -# install all packages which belongs to pattern x11 -__package_zypper x11 --ptype pattern --state present --------------------------------------------------------------------------------- + # Remove package + __package_zypper cfengine --state absent + + # install all packages which belongs to pattern x11 + __package_zypper x11 --ptype pattern --state present SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +- `cdist-type(7) `_ +- `cdist-type__package(7) `_ COPYING diff --git a/cdist/conf/type/__pacman_conf/man.text b/cdist/conf/type/__pacman_conf/man.rst similarity index 59% rename from cdist/conf/type/__pacman_conf/man.text rename to cdist/conf/type/__pacman_conf/man.rst index 9762837f..930035fa 100644 --- a/cdist/conf/type/__pacman_conf/man.text +++ b/cdist/conf/type/__pacman_conf/man.rst @@ -1,13 +1,10 @@ cdist-type__pacman_conf(7) ========================== +Manage pacman configuration + Dominique Roux -NAME ----- -cdist-type__pacman_conf - Manage pacman configuration - - DESCRIPTION ----------- The type allows you to configure options section, add or delete repositories and manage mirrorlists @@ -15,27 +12,27 @@ The type allows you to configure options section, add or delete repositories and REQUIRED PARAMETERS ------------------- -section:: +section 'options' for configure options section Otherwise it specifies a repository or a plain file -key:: +key Specifies the key which will be set If section = 'options' or file is not set the key will be checked against available keys from pacman.conf -value:: +value Specifies the value which will be set against the key OPTIONAL PARAMETERS ------------------- -state:: +state 'present' or 'absent', defaults to 'present' -file:: +file Specifies the filename. The managed file will be named like 'plain_file_filename' @@ -46,23 +43,22 @@ file:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Manage options section in pacman.conf -__pacman_conf options_Architecture --section options --key Architecture --value auto +.. code-block:: sh -# Add new repository -__pacman_conf localrepo_Server --section localrepo --key Server --value "file:///var/cache/pacman/pkg" + # Manage options section in pacman.conf + __pacman_conf options_Architecture --section options --key Architecture --value auto -# Add mirror to a mirrorlist -__pacman_conf customlist_Server --file customlist --section customlist --key Server\ - --value "file:///var/cache/pacman/pkg" + # Add new repository + __pacman_conf localrepo_Server --section localrepo --key Server --value "file:///var/cache/pacman/pkg" --------------------------------------------------------------------------------- + # Add mirror to a mirrorlist + __pacman_conf customlist_Server --file customlist --section customlist --key Server\ + --value "file:///var/cache/pacman/pkg" SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - grep(1) diff --git a/cdist/conf/type/__pacman_conf_integrate/man.text b/cdist/conf/type/__pacman_conf_integrate/man.rst similarity index 57% rename from cdist/conf/type/__pacman_conf_integrate/man.text rename to cdist/conf/type/__pacman_conf_integrate/man.rst index 8eb01d5f..6a856efe 100644 --- a/cdist/conf/type/__pacman_conf_integrate/man.text +++ b/cdist/conf/type/__pacman_conf_integrate/man.rst @@ -1,13 +1,10 @@ cdist-type__pacman_conf_integrate(7) ==================================== +Integrate default pacman.conf to cdist conform and vice versa + Dominique Roux -NAME ----- -cdist-type__pacman_conf_integrate - Integrate default pacman.conf to cdist conform and vice versa - - DESCRIPTION ----------- The type allows you to convert the default pacman.conf to a cdist conform one and vice versa @@ -19,26 +16,25 @@ None. OPTIONAL PARAMETERS ------------------- -state:: +state 'present' or 'absent', defaults to 'present' EXAMPLES -------- --------------------------------------------------------------------------------- -# Convert normal to cdist conform -__pacman_conf_integrate convert +.. code-block:: sh -# Convert cdist conform to normal -__pacman_conf_integrate convert --state absent + # Convert normal to cdist conform + __pacman_conf_integrate convert --------------------------------------------------------------------------------- + # Convert cdist conform to normal + __pacman_conf_integrate convert --state absent SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - grep(1) diff --git a/cdist/conf/type/__pf_apply/man.rst b/cdist/conf/type/__pf_apply/man.rst new file mode 100644 index 00000000..0b440e2d --- /dev/null +++ b/cdist/conf/type/__pf_apply/man.rst @@ -0,0 +1,53 @@ +cdist-type__pf_apply(7) +======================= +Apply pf(4) ruleset on \*BSD + +Jake Guffey + + +NAME +---- + + +DESCRIPTION +----------- +This type is used on \*BSD systems to manage the pf firewall's active ruleset. + + +REQUIRED PARAMETERS +------------------- +NONE + + +OPTIONAL PARAMETERS +------------------- +NONE + + +EXAMPLES +-------- + +.. code-block:: sh + + # Modify the ruleset on $__target_host: + __pf_ruleset --state present --source /my/pf/ruleset.conf + require="__pf_ruleset" \ + __pf_apply + + # Remove the ruleset on $__target_host (implies disabling pf(4): + __pf_ruleset --state absent + require="__pf_ruleset" \ + __pf_apply + + +SEE ALSO +-------- +- `cdist-type(7) `_ +- `cdist-type__pf_ruleset(7) `_ +- pf(4) + + +COPYING +------- +Copyright \(C) 2012 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__pf_apply/man.text b/cdist/conf/type/__pf_apply/man.text deleted file mode 100644 index 2e0d7802..00000000 --- a/cdist/conf/type/__pf_apply/man.text +++ /dev/null @@ -1,52 +0,0 @@ -cdist-type__pf_apply(7) -======================= -Jake Guffey - - -NAME ----- -cdist-type__pf_apply - Apply pf(4) ruleset on *BSD - - -DESCRIPTION ------------ -This type is used on *BSD systems to manage the pf firewall's active ruleset. - - -REQUIRED PARAMETERS -------------------- -NONE - - -OPTIONAL PARAMETERS -------------------- -NONE - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Modify the ruleset on $__target_host: -__pf_ruleset --state present --source /my/pf/ruleset.conf -require="__pf_ruleset" \ - __pf_apply - -# Remove the ruleset on $__target_host (implies disabling pf(4): -__pf_ruleset --state absent -require="__pf_ruleset" \ - __pf_apply --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__pf_ruleset(7) -- pf(4) - - -COPYING -------- -Copyright \(C) 2012 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__pf_ruleset/man.text b/cdist/conf/type/__pf_ruleset/man.rst similarity index 57% rename from cdist/conf/type/__pf_ruleset/man.text rename to cdist/conf/type/__pf_ruleset/man.rst index 29efe065..b3e9b073 100644 --- a/cdist/conf/type/__pf_ruleset/man.text +++ b/cdist/conf/type/__pf_ruleset/man.rst @@ -1,27 +1,24 @@ cdist-type__pf_ruleset(7) ========================= +Copy a pf(4) ruleset to $__target_host + Jake Guffey -NAME ----- -cdist-type__pf_ruleset - Copy a pf(4) ruleset to $__target_host - - DESCRIPTION ----------- -This type is used on *BSD systems to manage the pf firewall's ruleset. +This type is used on \*BSD systems to manage the pf firewall's ruleset. REQUIRED PARAMETERS ------------------- -state:: +state Either "absent" (no ruleset at all) or "present", defaults to "present". OPTIONAL PARAMETERS ------------------- -source:: +source If supplied, use to define the ruleset to load onto the $__target_host for pf(4). Note that this type is almost useless without a ruleset defined, but it's technically not needed, e.g. for the case of disabling the firewall temporarily. @@ -30,19 +27,18 @@ source:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Remove the current ruleset in place -__pf_ruleset --state absent +.. code-block:: sh -# Enable the firewall with the ruleset defined in $__manifest/files/pf.conf -__pf_ruleset --state present --source $__manifest/files/pf.conf + # Remove the current ruleset in place + __pf_ruleset --state absent --------------------------------------------------------------------------------- + # Enable the firewall with the ruleset defined in $__manifest/files/pf.conf + __pf_ruleset --state present --source $__manifest/files/pf.conf SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - pf(4) diff --git a/cdist/conf/type/__postfix/man.text b/cdist/conf/type/__postfix/man.rst similarity index 66% rename from cdist/conf/type/__postfix/man.text rename to cdist/conf/type/__postfix/man.rst index 1a91723a..d10a9960 100644 --- a/cdist/conf/type/__postfix/man.text +++ b/cdist/conf/type/__postfix/man.rst @@ -1,13 +1,10 @@ cdist-type__postfix(7) ====================== +Install postfix + Steven Armstrong -NAME ----- -cdist-type__postfix - install postfix - - DESCRIPTION ----------- This space intentionally left blank. @@ -26,14 +23,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__postfix --------------------------------------------------------------------------------- +.. code-block:: sh + + __postfix SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__postfix_master/man.text b/cdist/conf/type/__postfix_master/man.rst similarity index 51% rename from cdist/conf/type/__postfix_master/man.text rename to cdist/conf/type/__postfix_master/man.rst index 0ec78752..4853e687 100644 --- a/cdist/conf/type/__postfix_master/man.text +++ b/cdist/conf/type/__postfix_master/man.rst @@ -1,13 +1,10 @@ cdist-type__postfix_master(7) ============================= +Configure postfix master.cf + Steven Armstrong -NAME ----- -cdist-type__postfix_master - configure postfix master.cf - - DESCRIPTION ----------- See master(5) for more information. @@ -15,54 +12,62 @@ See master(5) for more information. REQUIRED PARAMETERS ------------------- -type:: +type See master(5) -command:: +command See master(5) BOOLEAN PARAMETERS ------------------ -noreload:: +noreload don't reload postfix after changes OPTIONAL PARAMETERS ------------------- -state:: +state present or absent, defaults to present -service:: -private:: -unpriv:: -chroot:: -wakeup:: -maxproc:: -option:: + +service + +private + +unpriv + +chroot + +wakeup + +maxproc + +option Pass an option to a service. Same as using -o in master.cf. Can be specified multiple times. -comment:: + +comment a textual comment to add with the master.cf entry EXAMPLES -------- --------------------------------------------------------------------------------- -__postfix_master smtp --type inet --command smtpd +.. code-block:: sh -__postfix_master smtp --type inet --chroot y --command smtpd \ - --option smtpd_enforce_tls=yes \ - --option smtpd_sasl_auth_enable=yes \ - --option smtpd_client_restrictions=permit_sasl_authenticated,reject + __postfix_master smtp --type inet --command smtpd -__postfix_master submission --type inet --command smtpd \ - --comment "Run alternative smtp on submission port" --------------------------------------------------------------------------------- + __postfix_master smtp --type inet --chroot y --command smtpd \ + --option smtpd_enforce_tls=yes \ + --option smtpd_sasl_auth_enable=yes \ + --option smtpd_client_restrictions=permit_sasl_authenticated,reject + + __postfix_master submission --type inet --command smtpd \ + --comment "Run alternative smtp on submission port" SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - master(5) diff --git a/cdist/conf/type/__postfix_postconf/man.text b/cdist/conf/type/__postfix_postconf/man.rst similarity index 64% rename from cdist/conf/type/__postfix_postconf/man.text rename to cdist/conf/type/__postfix_postconf/man.rst index 727637b1..e07e136f 100644 --- a/cdist/conf/type/__postfix_postconf/man.text +++ b/cdist/conf/type/__postfix_postconf/man.rst @@ -1,13 +1,10 @@ cdist-type__postfix_postconf(7) =============================== +Configure postfix main.cf + Steven Armstrong -NAME ----- -cdist-type__postfix_postconf - configure postfix main.cf - - DESCRIPTION ----------- See postconf(5) for possible keys and values. @@ -18,30 +15,29 @@ It does not make changes to /etc/postfix/main.cf itself. REQUIRED PARAMETERS ------------------- -value:: +value the value for the postfix parameter OPTIONAL PARAMETERS ------------------- -key:: +key the name of the parameter. Defaults to __object_id EXAMPLES -------- --------------------------------------------------------------------------------- -__postfix_postconf mydomain --value somedomain.com +.. code-block:: sh -__postfix_postconf bind-to-special-ip --key smtp_bind_address --value 127.0.0.5 + __postfix_postconf mydomain --value somedomain.com --------------------------------------------------------------------------------- + __postfix_postconf bind-to-special-ip --key smtp_bind_address --value 127.0.0.5 SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - postconf(5) diff --git a/cdist/conf/type/__postfix_postmap/man.text b/cdist/conf/type/__postfix_postmap/man.rst similarity index 62% rename from cdist/conf/type/__postfix_postmap/man.text rename to cdist/conf/type/__postfix_postmap/man.rst index 37060d04..ecee6722 100644 --- a/cdist/conf/type/__postfix_postmap/man.text +++ b/cdist/conf/type/__postfix_postmap/man.rst @@ -1,13 +1,10 @@ cdist-type__postfix_postmap(7) ============================== +Run postmap on the given file + Steven Armstrong -NAME ----- -cdist-type__postfix_postmap - run postmap on the given file - - DESCRIPTION ----------- This space intentionally left blank. @@ -26,14 +23,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__postfix_postmap /etc/postfix/generic --------------------------------------------------------------------------------- +.. code-block:: sh + + __postfix_postmap /etc/postfix/generic SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__postfix_reload/man.text b/cdist/conf/type/__postfix_reload/man.rst similarity index 63% rename from cdist/conf/type/__postfix_reload/man.text rename to cdist/conf/type/__postfix_reload/man.rst index c63356b5..c5101953 100644 --- a/cdist/conf/type/__postfix_reload/man.text +++ b/cdist/conf/type/__postfix_reload/man.rst @@ -1,13 +1,10 @@ cdist-type__postfix_reload(7) ============================= +Tell postfix to reload its configuration + Steven Armstrong -NAME ----- -cdist-type__postfix_reload - tell postfix to reload its configuration - - DESCRIPTION ----------- This space intentionally left blank. @@ -26,14 +23,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__postfix_reload --------------------------------------------------------------------------------- +.. code-block:: sh + + __postfix_reload SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__postgres_database/man.text b/cdist/conf/type/__postgres_database/man.rst similarity index 60% rename from cdist/conf/type/__postgres_database/man.text rename to cdist/conf/type/__postgres_database/man.rst index c7c0d3cd..152ee910 100644 --- a/cdist/conf/type/__postgres_database/man.text +++ b/cdist/conf/type/__postgres_database/man.rst @@ -1,13 +1,10 @@ cdist-type__postgres_database(7) ================================ +Create/drop postgres databases + Steven Armstrong -NAME ----- -cdist-type__postgres_database - create/drop postgres databases - - DESCRIPTION ----------- This cdist type allows you to create or drop postgres databases. @@ -15,25 +12,25 @@ This cdist type allows you to create or drop postgres databases. OPTIONAL PARAMETERS ------------------- -state:: +state either 'present' or 'absent', defaults to 'present'. -owner:: +owner the role owning this database EXAMPLES -------- --------------------------------------------------------------------------------- -__postgres_database mydbname --owner mydbusername --------------------------------------------------------------------------------- +.. code-block:: sh + + __postgres_database mydbname --owner mydbusername SEE ALSO -------- -- cdist-type(7) -- cdist-type__postgres_role(7) +- `cdist-type(7) `_ +- `cdist-type__postgres_role(7) `_ COPYING diff --git a/cdist/conf/type/__postgres_role/man.text b/cdist/conf/type/__postgres_role/man.rst similarity index 59% rename from cdist/conf/type/__postgres_role/man.text rename to cdist/conf/type/__postgres_role/man.rst index ac87754b..6384568f 100644 --- a/cdist/conf/type/__postgres_role/man.text +++ b/cdist/conf/type/__postgres_role/man.rst @@ -1,13 +1,10 @@ cdist-type__postgres_role(7) ============================ +Manage postgres roles + Steven Armstrong -NAME ----- -cdist-type__postgres_role - manage postgres roles - - DESCRIPTION ----------- This cdist type allows you to create or drop postgres roles. @@ -15,43 +12,43 @@ This cdist type allows you to create or drop postgres roles. OPTIONAL PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present" All other parameters map directly to the corresponding postgres createrole parameters. -password:: +password BOOLEAN PARAMETERS ------------------ All parameter map directly to the corresponding postgres createrole parameters. -login:: -createdb:: -createrole:: -superuser:: -inherit:: +login +createdb +createrole +superuser +inherit EXAMPLES -------- --------------------------------------------------------------------------------- -__postgres_role myrole +.. code-block:: sh -__postgres_role myrole --password 'secret' + __postgres_role myrole -__postgres_role admin --password 'very-secret' --superuser + __postgres_role myrole --password 'secret' -__postgres_role dbcustomer --password 'bla' --createdb --------------------------------------------------------------------------------- + __postgres_role admin --password 'very-secret' --superuser + + __postgres_role dbcustomer --password 'bla' --createdb SEE ALSO -------- -- cdist-type(7) -- cdist-type__postgres_database(7) +- `cdist-type(7) `_ +- `cdist-type__postgres_database(7) `_ - http://www.postgresql.org/docs/current/static/sql-createrole.html diff --git a/cdist/conf/type/__process/man.rst b/cdist/conf/type/__process/man.rst new file mode 100644 index 00000000..09032a1a --- /dev/null +++ b/cdist/conf/type/__process/man.rst @@ -0,0 +1,67 @@ +cdist-type__process(7) +====================== +Start or stop process + +Nico Schottelius + + +DESCRIPTION +----------- +This cdist type allows you to define the state of a process. + + +OPTIONAL PARAMETERS +------------------- +state + Either "present" or "absent", defaults to "present" + +name + Process name to match on when using pgrep -f -x. + + This is useful, if the name starts with a "/", + because the leading slash is stripped away from + the object id by cdist. + +stop + Executable to use for stopping the process. + +start + Executable to use for starting the process. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Start if not running + __process /usr/sbin/syslog-ng --state present + + # Start if not running with a different binary + __process /usr/sbin/nginx --state present --start "/etc/rc.d/nginx start" + + # Stop the process using kill (the type default) - DO NOT USE THIS + __process /usr/sbin/sshd --state absent + + # Stop the process using /etc/rc.d/sshd stop - THIS ONE NOT AS WELL + __process /usr/sbin/sshd --state absent --stop "/etc/rc.d/sshd stop" + + # Ensure cups is running, which runs with -C ...: + __process cups --start "/etc/rc.d/cups start" --state present \ + --name "/usr/sbin/cupsd -C /etc/cups/cupsd.conf" + + # Ensure rpc.statd is running (which usually runs with -L) using a regexp + __process rpcstatd --state present --start "/etc/init.d/statd start" \ + --name "rpc.statd.*" + + +SEE ALSO +-------- +- `cdist-type(7) `_ +- `cdist-type__start_on_boot(7) `_ + + +COPYING +------- +Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__process/man.text b/cdist/conf/type/__process/man.text deleted file mode 100644 index 2fdd27aa..00000000 --- a/cdist/conf/type/__process/man.text +++ /dev/null @@ -1,70 +0,0 @@ -cdist-type__process(7) -====================== -Nico Schottelius - - -NAME ----- -cdist-type__process - Start or stop process - - -DESCRIPTION ------------ -This cdist type allows you to define the state of a process. - - -OPTIONAL PARAMETERS -------------------- -state:: - Either "present" or "absent", defaults to "present" - -name:: - Process name to match on when using pgrep -f -x. - - This is useful, if the name starts with a "/", - because the leading slash is stripped away from - the object id by cdist. - -stop:: - Executable to use for stopping the process. - -start:: - Executable to use for starting the process. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Start if not running -__process /usr/sbin/syslog-ng --state present - -# Start if not running with a different binary -__process /usr/sbin/nginx --state present --start "/etc/rc.d/nginx start" - -# Stop the process using kill (the type default) - DO NOT USE THIS -__process /usr/sbin/sshd --state absent - -# Stop the process using /etc/rc.d/sshd stop - THIS ONE NOT AS WELL -__process /usr/sbin/sshd --state absent --stop "/etc/rc.d/sshd stop" - -# Ensure cups is running, which runs with -C ...: -__process cups --start "/etc/rc.d/cups start" --state present \ - --name "/usr/sbin/cupsd -C /etc/cups/cupsd.conf" - -# Ensure rpc.statd is running (which usually runs with -L) using a regexp -__process rpcstatd --state present --start "/etc/init.d/statd start" \ - --name "rpc.statd.*" --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__start_on_boot(7) - - -COPYING -------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__pyvenv/man.rst b/cdist/conf/type/__pyvenv/man.rst new file mode 100755 index 00000000..bdc1166c --- /dev/null +++ b/cdist/conf/type/__pyvenv/man.rst @@ -0,0 +1,78 @@ +cdist-type__pyvenv(7) +===================== +Create or remove python virtual environment + +Darko Poljak + + +DESCRIPTION +----------- +This cdist type allows you to create or remove python virtual +environment using pyvenv. +It assumes pyvenv is already installed. Concrete package depends +on concrete OS and/or OS version/distribution. +Ensure this for e.g. in your init manifest as in the following example: + +.. code-block sh + + case "$__target_host" in + localhost) + __package python3-venv --state present + require="__package/python3-venv" __pyvenv /home/darko/testenv --pyvenv "pyvenv-3.4" --owner darko --group darko --mode 740 --state present + require="__pyvenv/home/darko/testenv" __package_pip docopt --pip /home/darko/testenv/bin/pip --runas darko --state present + ;; + esac + + +REQUIRED PARAMETERS +------------------- +None + +OPTIONAL PARAMETERS +------------------- +state + Either "present" or "absent", defaults to "present" + +group + Group to chgrp to + +mode + Unix permissions, suitable for chmod + +owner + User to chown to + +pyvenv + Use this specific pyvenv + +venvparams + Specific parameters to pass to pyvenv invocation + + +EXAMPLES +-------- + +.. code-block:: sh + + __pyvenv /home/services/djangoenv + + # Use specific pyvenv + __pyvenv /home/foo/fooenv --pyvenv /usr/local/bin/pyvenv-3.4 + + # Create python virtualenv for user foo. + __pyvenv /home/foo/fooenv --group foo --user foo + + # Create python virtualenv with specific parameters. + __pyvenv /home/services/djangoenv --venvparams "--copies --system-site-packages" + + +SEE ALSO +-------- +- `cdist-type(7) `_ + + +COPYING +------- +Copyright \(C) 2016 Darko Poljak. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). + diff --git a/cdist/conf/type/__pyvenv/man.text b/cdist/conf/type/__pyvenv/man.text deleted file mode 100755 index 71d30ed5..00000000 --- a/cdist/conf/type/__pyvenv/man.text +++ /dev/null @@ -1,80 +0,0 @@ -cdist-type__pyvenv(7) -===================== -Darko Poljak - - -NAME ----- -cdist-type__pyvenv - Create or remove python virtual environment - - -DESCRIPTION ------------ -This cdist type allows you to create or remove python virtual -environment using pyvenv. -It assumes pyvenv is already installed. Concrete package depends -on concrete OS and/or OS version/distribution. -Ensure this for e.g. in your init manifest as in the following example: --------------------------------------------------------------------------------- -case "$__target_host" in - localhost) - __package python3-venv --state present - require="__package/python3-venv" __pyvenv /home/darko/testenv --pyvenv "pyvenv-3.4" --owner darko --group darko --mode 740 --state present - require="__pyvenv/home/darko/testenv" __package_pip docopt --pip /home/darko/testenv/bin/pip --runas darko --state present - ;; -esac --------------------------------------------------------------------------------- - - -REQUIRED PARAMETERS -------------------- -None - -OPTIONAL PARAMETERS -------------------- -state:: - Either "present" or "absent", defaults to "present" - -group:: - Group to chgrp to - -mode:: - Unix permissions, suitable for chmod - -owner:: - User to chown to - -pyvenv:: - Use this specific pyvenv - -venvparams:: - Specific parameters to pass to pyvenv invocation - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -__pyvenv /home/services/djangoenv - -# Use specific pyvenv -__pyvenv /home/foo/fooenv --pyvenv /usr/local/bin/pyvenv-3.4 - -# Create python virtualenv for user foo. -__pyvenv /home/foo/fooenv --group foo --user foo - -# Create python virtualenv with specific parameters. -__pyvenv /home/services/djangoenv --venvparams "--copies --system-site-packages" --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2016 Darko Poljak. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). - diff --git a/cdist/conf/type/__qemu_img/man.text b/cdist/conf/type/__qemu_img/man.rst similarity index 59% rename from cdist/conf/type/__qemu_img/man.text rename to cdist/conf/type/__qemu_img/man.rst index dda54e0d..598e06ab 100644 --- a/cdist/conf/type/__qemu_img/man.text +++ b/cdist/conf/type/__qemu_img/man.rst @@ -1,13 +1,10 @@ cdist-type__qemu_img(7) ======================= +Manage VM disk images + Nico Schottelius -NAME ----- -cdist-type__qemu_img - Manage VM disk images - - DESCRIPTION ----------- The qemu-img program is used to create qemu images for @@ -17,9 +14,9 @@ qemu and (qemu-)kvm. OPTIONAL PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present" -size:: +size Size of the image in qemu-img compatible units. Required if state is "present". @@ -28,18 +25,18 @@ size:: EXAMPLES -------- --------------------------------------------------------------------------------- -# Create a 50G size image -__qemu_img /home/services/kvm/vm/myvmname/system-disk --size 50G +.. code-block:: sh -# Remove image -__qemu_img /home/services/kvm/vm/myoldvm/system-disk --state absent --------------------------------------------------------------------------------- + # Create a 50G size image + __qemu_img /home/services/kvm/vm/myvmname/system-disk --size 50G + + # Remove image + __qemu_img /home/services/kvm/vm/myoldvm/system-disk --state absent SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - qemu-img(1) diff --git a/cdist/conf/type/__rbenv/man.text b/cdist/conf/type/__rbenv/man.rst similarity index 54% rename from cdist/conf/type/__rbenv/man.text rename to cdist/conf/type/__rbenv/man.rst index c6ed5de2..314507fe 100644 --- a/cdist/conf/type/__rbenv/man.text +++ b/cdist/conf/type/__rbenv/man.rst @@ -1,13 +1,10 @@ cdist-type__rbenv(7) ==================== +Manage rbenv installation + Nico Schottelius -NAME ----- -cdist-type__rbenv - Manage rbenv installation - - DESCRIPTION ----------- This cdist type allows you to manage rbenv installations. @@ -16,31 +13,31 @@ It also installs ruby-build. OPTIONAL PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present" -owner:: +owner Which user should own the rbenv installation, defaults to root EXAMPLES -------- --------------------------------------------------------------------------------- -# Install rbenv including ruby-build for nico -__rbenv /home/nico +.. code-block:: sh -# Install rbenv including ruby-build for nico -__rbenv /home/nico --owner nico + # Install rbenv including ruby-build for nico + __rbenv /home/nico -# Bastian does not need rbenv anymore, he began to code C99 -__rbenv /home/bastian --state absent --------------------------------------------------------------------------------- + # Install rbenv including ruby-build for nico + __rbenv /home/nico --owner nico + + # Bastian does not need rbenv anymore, he began to code C99 + __rbenv /home/bastian --state absent SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__rsync/man.text b/cdist/conf/type/__rsync/man.rst similarity index 61% rename from cdist/conf/type/__rsync/man.text rename to cdist/conf/type/__rsync/man.rst index af39b9c5..bc7b1bca 100644 --- a/cdist/conf/type/__rsync/man.text +++ b/cdist/conf/type/__rsync/man.rst @@ -1,13 +1,10 @@ cdist-type__rsync(7) ==================== +Mirror directories using rsync + Nico Schottelius -NAME ----- -cdist-type__rsync - Mirror directories using rsync - - DESCRIPTION ----------- WARNING: This type is of BETA quality: @@ -27,30 +24,31 @@ 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. + REQUIRED PARAMETERS ------------------- -source:: +source Where to take files from OPTIONAL PARAMETERS ------------------- -group:: +group Group to chgrp to. -owner:: +owner User to chown to. -destination:: +destination Use this as the base destination instead of the object id -remote-user:: +remote-user Use this user instead of the default "root" for rsync operations. OPTIONAL MULTIPLE PARAMETERS ---------------------------- -rsync-opts:: +rsync-opts Use this option to give rsync options with. See rsync(1) for available options. Only "--" options are supported. @@ -66,41 +64,40 @@ NONE EXAMPLES -------- --------------------------------------------------------------------------------- -# You can use any source directory -__rsync /tmp/testdir \ - --source /etc +.. code-block:: sh -# Use source from type -__rsync /etc \ - --source "$__type/files/package" + # You can use any source directory + __rsync /tmp/testdir \ + --source /etc -# Allow multiple __rsync objects to write to the same dir -__rsync mystuff \ - --destination /usr/local/bin \ - --source "$__type/files/package" + # Use source from type + __rsync /etc \ + --source "$__type/files/package" -__rsync otherstuff \ - --destination /usr/local/bin \ - --source "$__type/files/package2" + # Allow multiple __rsync objects to write to the same dir + __rsync mystuff \ + --destination /usr/local/bin \ + --source "$__type/files/package" -# Use rsync option --exclude -__rsync /tmp/testdir \ - --source /etc \ - --rsync-opts exclude=sshd_conf + __rsync otherstuff \ + --destination /usr/local/bin \ + --source "$__type/files/package2" -# Use rsync with multiple options --exclude --dry-run -__rsync /tmp/testing \ - --source /home/tester \ - --rsync-opts exclude=id_rsa \ - --rsync-opts dry-run + # 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 -------- -- cdist-type(7) +- `cdist-type(7) `_ - rsync(1) diff --git a/cdist/conf/type/__rvm/man.text b/cdist/conf/type/__rvm/man.rst similarity index 52% rename from cdist/conf/type/__rvm/man.text rename to cdist/conf/type/__rvm/man.rst index 0408d125..8a3f72f5 100644 --- a/cdist/conf/type/__rvm/man.text +++ b/cdist/conf/type/__rvm/man.rst @@ -1,13 +1,10 @@ cdist-type__rvm(7) ================== +Install rvm for a given user + Evax Software -NAME ----- -cdist-type__rvm - Install rvm for a given user - - DESCRIPTION ----------- RVM is the Ruby enVironment Manager for the Ruby programming language. @@ -15,28 +12,28 @@ RVM is the Ruby enVironment Manager for the Ruby programming language. REQUIRED PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present". EXAMPLES -------- --------------------------------------------------------------------------------- -# Install rvm for user billie -__rvm billie --state present +.. code-block:: sh -# Remove rvm -__rvm billie --state absent --------------------------------------------------------------------------------- + # Install rvm for user billie + __rvm billie --state present + + # Remove rvm + __rvm billie --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__rvm_ruby(7) -- cdist-type__rvm_gemset(7) -- cdist-type__rvm_gem(7) +- `cdist-type(7) `_ +- `cdist-type__rvm_ruby(7) `_ +- `cdist-type__rvm_gemset(7) `_ +- `cdist-type__rvm_gem(7) `_ COPYING diff --git a/cdist/conf/type/__rvm_gem/man.rst b/cdist/conf/type/__rvm_gem/man.rst new file mode 100644 index 00000000..39d93065 --- /dev/null +++ b/cdist/conf/type/__rvm_gem/man.rst @@ -0,0 +1,54 @@ +cdist-type__rvm_gemset(7) +========================== +Manage Ruby gems through rvm + +Evax Software + + +DESCRIPTION +----------- +RVM is the Ruby enVironment Manager for the Ruby programming language. + + +REQUIRED PARAMETERS +------------------- +user + The remote user account to use +gemset + The gemset to use +state + Either "present" or "absent", defaults to "present". + +OPTIONAL PARAMETERS +------------------- +default + Make the selected gemset the default + +EXAMPLES +-------- + +.. code-block:: sh + + # Install the rails gem in gemset ruby-1.9.3-p0@myset for user bill + __rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill --state present + + # Do the same and also make ruby-1.9.3-p0@myset the default gemset + __rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill \ + --state present --default + + # Remove it + __rvm_ruby rails --gemset ruby-1.9.3-p0@myset --user bill --state absent + + +SEE ALSO +-------- +- `cdist-type(7) `_ +- `cdist-type__rvm(7) `_ +- `cdist-type__rvm_ruby(7) `_ +- `cdist-type__rvm_gemset(7) `_ + + +COPYING +------- +Copyright \(C) 2012 Evax Software. Free use of this software is granted under +the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__rvm_gem/man.text b/cdist/conf/type/__rvm_gem/man.text deleted file mode 100644 index d7eff3be..00000000 --- a/cdist/conf/type/__rvm_gem/man.text +++ /dev/null @@ -1,57 +0,0 @@ -cdist-type__rvm_gemset(7) -========================== -Evax Software - - -NAME ----- -cdist-type__rvm_gem - Manage Ruby gems through rvm - - -DESCRIPTION ------------ -RVM is the Ruby enVironment Manager for the Ruby programming language. - - -REQUIRED PARAMETERS -------------------- -user:: - The remote user account to use -gemset:: - The gemset to use -state:: - Either "present" or "absent", defaults to "present". - -OPTIONAL PARAMETERS -------------------- -default:: - Make the selected gemset the default - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Install the rails gem in gemset ruby-1.9.3-p0@myset for user bill -__rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill --state present - -# Do the same and also make ruby-1.9.3-p0@myset the default gemset -__rvm_gemset rails --gemset ruby-1.9.3-p0@myset --user bill \ - --state present --default - -# Remove it -__rvm_ruby rails --gemset ruby-1.9.3-p0@myset --user bill --state absent --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__rvm(7) -- cdist-type__rvm_ruby(7) -- cdist-type__rvm_gemset(7) - - -COPYING -------- -Copyright \(C) 2012 Evax Software. Free use of this software is granted under -the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__rvm_gemset/man.rst b/cdist/conf/type/__rvm_gemset/man.rst new file mode 100644 index 00000000..422130cb --- /dev/null +++ b/cdist/conf/type/__rvm_gemset/man.rst @@ -0,0 +1,52 @@ +cdist-type__rvm_gemset(7) +========================== +Manage gemsets through rvm + +Evax Software + + +DESCRIPTION +----------- +RVM is the Ruby enVironment Manager for the Ruby programming language. + + +REQUIRED PARAMETERS +------------------- +user + The remote user account to use +state + Either "present" or "absent", defaults to "present". + +BOOLEAN PARAMETERS +------------------- +default + If present, set the given gemset as default. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Install the gemset @myset for user charles on based on ruby-1.9.3-0 + __rvm_gemset ruby-1.9.3-p0@myset --user charles --state present + + # Do the same and make ruby-1.9.3-p0@myset the default gemset + __rvm_gemset ruby-1.9.3-p0@myset --user charles --state present --default + + # Remove the gemset @myset for user john + __rvm_ruby ruby-1.9.3-p0@myset --user john --state absent + + +SEE ALSO +-------- +- `cdist-type(7) `_ +- `cdist-type__rvm(7) `_ +- `cdist-type__rvm_ruby(7) `_ +- `cdist-type__rvm_gem(7) `_ + + +COPYING +------- +Copyright \(C) 2012 Evax Software. Free use of this software is granted under +the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__rvm_gemset/man.text b/cdist/conf/type/__rvm_gemset/man.text deleted file mode 100644 index e85425f3..00000000 --- a/cdist/conf/type/__rvm_gemset/man.text +++ /dev/null @@ -1,55 +0,0 @@ -cdist-type__rvm_gemset(7) -========================== -Evax Software - - -NAME ----- -cdist-type__rvm_gemset - Manage gemsets through rvm - - -DESCRIPTION ------------ -RVM is the Ruby enVironment Manager for the Ruby programming language. - - -REQUIRED PARAMETERS -------------------- -user:: - The remote user account to use -state:: - Either "present" or "absent", defaults to "present". - -BOOLEAN PARAMETERS -------------------- -default:: - If present, set the given gemset as default. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Install the gemset @myset for user charles on based on ruby-1.9.3-0 -__rvm_gemset ruby-1.9.3-p0@myset --user charles --state present - -# Do the same and make ruby-1.9.3-p0@myset the default gemset -__rvm_gemset ruby-1.9.3-p0@myset --user charles --state present --default - -# Remove the gemset @myset for user john -__rvm_ruby ruby-1.9.3-p0@myset --user john --state absent --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__rvm(7) -- cdist-type__rvm_ruby(7) -- cdist-type__rvm_gem(7) - - -COPYING -------- -Copyright \(C) 2012 Evax Software. Free use of this software is granted under -the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__rvm_ruby/man.rst b/cdist/conf/type/__rvm_ruby/man.rst new file mode 100644 index 00000000..dbb1c9a2 --- /dev/null +++ b/cdist/conf/type/__rvm_ruby/man.rst @@ -0,0 +1,53 @@ +cdist-type__rvm_ruby(7) +======================= +Manage ruby installations through rvm + +Evax Software + + +DESCRIPTION +----------- +RVM is the Ruby enVironment Manager for the Ruby programming language. + + +REQUIRED PARAMETERS +------------------- +user + The remote user account to use +state + Either "present" or "absent", defaults to "present". + + +BOOLEAN PARAMETERS +------------------ +default + Set the given version as default + + +EXAMPLES +-------- + +.. code-block:: sh + + # Install ruby 1.9.3 through rvm for user thelonious + __rvm_ruby ruby-1.9.3-p0 --user thelonious --state present + + # Install ruby 1.9.3 through rvm for user ornette and make it the default + __rvm_ruby ruby-1.9.3-p0 --user ornette --state present --default + + # Remove ruby 1.9.3 for user john + __rvm_ruby ruby-1.9.3-p0 --user john --state absent + + +SEE ALSO +-------- +- `cdist-type(7) `_ +- `cdist-type__rvm(7) `_ +- `cdist-type__rvm_gemset(7) `_ +- `cdist-type__rvm_gem(7) `_ + + +COPYING +------- +Copyright \(C) 2012 Evax Software. Free use of this software is granted under +the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__rvm_ruby/man.text b/cdist/conf/type/__rvm_ruby/man.text deleted file mode 100644 index 6419a4d4..00000000 --- a/cdist/conf/type/__rvm_ruby/man.text +++ /dev/null @@ -1,54 +0,0 @@ -cdist-type__rvm_ruby(7) -======================= -Evax Software - - -NAME ----- -cdist-type__rvm_ruby - Manage ruby installations through rvm - - -DESCRIPTION ------------ -RVM is the Ruby enVironment Manager for the Ruby programming language. - - -REQUIRED PARAMETERS -------------------- -user:: - The remote user account to use -state:: - Either "present" or "absent", defaults to "present". - -BOOLEAN PARAMETERS ------------------- -default: - Set the given version as default - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Install ruby 1.9.3 through rvm for user thelonious -__rvm_ruby ruby-1.9.3-p0 --user thelonious --state present - -# Install ruby 1.9.3 through rvm for user ornette and make it the default -__rvm_ruby ruby-1.9.3-p0 --user ornette --state present --default - -# Remove ruby 1.9.3 for user john -__rvm_ruby ruby-1.9.3-p0 --user john --state absent --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- cdist-type__rvm(7) -- cdist-type__rvm_gemset(7) -- cdist-type__rvm_gem(7) - - -COPYING -------- -Copyright \(C) 2012 Evax Software. Free use of this software is granted under -the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__ssh_authorized_key/man.text b/cdist/conf/type/__ssh_authorized_key/man.rst similarity index 61% rename from cdist/conf/type/__ssh_authorized_key/man.text rename to cdist/conf/type/__ssh_authorized_key/man.rst index b519222c..984ea51b 100644 --- a/cdist/conf/type/__ssh_authorized_key/man.text +++ b/cdist/conf/type/__ssh_authorized_key/man.rst @@ -1,13 +1,10 @@ cdist-type__ssh_authorized_key(7) ================================= +Manage a single ssh authorized key entry + Steven Armstrong -NAME ----- -cdist-type__ssh_authorized_key - manage a single ssh authorized key entry - - DESCRIPTION ----------- Manage a single authorized key entry in an authorized_key file. @@ -16,49 +13,49 @@ This type was created to be used by the __ssh_authorized_keys type. REQUIRED PARAMETERS ------------------- -file:: +file the authorized_keys file to which the given key should be added -key:: +key a string containing the ssh keytype, base 64 encoded key and optional trailing comment which shall be added to the given authorized_keys file. OPTIONAL PARAMETERS ------------------- -comment:: +comment explicit comment instead of the one which may be trailing the given key -option:: +option an option to set for this authorized_key entry. Can be specified multiple times. See sshd(8) for available options. -state:: +state if the given keys should be 'present' or 'absent', defaults to 'present'. EXAMPLES -------- --------------------------------------------------------------------------------- -__ssh_authorized_key some-id \ - --file "/home/user/.ssh/autorized_keys" \ - --key "$(cat ~/.ssh/id_rsa.pub)" +.. code-block:: sh -__ssh_authorized_key some-id \ - --file "/home/user/.ssh/autorized_keys" \ - --key "$(cat ~/.ssh/id_rsa.pub)" \ - --option 'command="/path/to/script"' \ - --option 'environment="FOO=bar"' \ - --comment 'one to rule them all' --------------------------------------------------------------------------------- + __ssh_authorized_key some-id \ + --file "/home/user/.ssh/autorized_keys" \ + --key "$(cat ~/.ssh/id_rsa.pub)" + + __ssh_authorized_key some-id \ + --file "/home/user/.ssh/autorized_keys" \ + --key "$(cat ~/.ssh/id_rsa.pub)" \ + --option 'command="/path/to/script"' \ + --option 'environment="FOO=bar"' \ + --comment 'one to rule them all' SEE ALSO -------- -- cdist-type(7) -- cdist__ssh_authorized_keys(7) +- `cdist-type(7) `_ +- `cdist__ssh_authorized_keys(7) `_ - sshd(8) COPYING diff --git a/cdist/conf/type/__ssh_authorized_keys/man.text b/cdist/conf/type/__ssh_authorized_keys/man.rst similarity index 51% rename from cdist/conf/type/__ssh_authorized_keys/man.text rename to cdist/conf/type/__ssh_authorized_keys/man.rst index d5523a6e..0907c2b3 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.text +++ b/cdist/conf/type/__ssh_authorized_keys/man.rst @@ -1,13 +1,10 @@ cdist-type__ssh_authorized_keys(7) ================================== +Manage ssh authorized_keys files + Steven Armstrong -NAME ----- -cdist-type__ssh_authorized_keys - manage ssh authorized_keys files - - DESCRIPTION ----------- Adds or removes ssh keys from a authorized_keys file. @@ -24,38 +21,38 @@ permissions work with ssh. REQUIRED PARAMETERS ------------------- -key:: +key the ssh key which shall be added to this authorized_keys file. Must be a string and can be specified multiple times. OPTIONAL PARAMETERS ------------------- -comment:: +comment explicit comment instead of the one which may be trailing the given key -file:: +file an alternative destination file, defaults to ~$owner/.ssh/authorized_keys -option:: +option an option to set for all created authorized_key entries. Can be specified multiple times. See sshd(8) for available options. -owner:: +owner the user owning the authorized_keys file, defaults to object_id. -state:: +state if the given keys should be 'present' or 'absent', defaults to 'present'. BOOLEAN PARAMETERS ------------------ -noparent:: +noparent don't create or change ownership and permissions of the directory containing the authorized_keys file -nofile:: +nofile don't manage existence, ownership and permissions of the the authorized_keys file @@ -63,51 +60,51 @@ nofile:: EXAMPLES -------- --------------------------------------------------------------------------------- -# add your ssh key to remote root's authorized_keys file -__ssh_authorized_keys root \ - --key "$(cat ~/.ssh/id_rsa.pub)" +.. code-block:: sh -# allow key to login as user-name -__ssh_authorized_keys user-name \ - --key "ssh-rsa AXYZAAB3NzaC1yc2..." + # add your ssh key to remote root's authorized_keys file + __ssh_authorized_keys root \ + --key "$(cat ~/.ssh/id_rsa.pub)" -# allow key to login as user-name with options and expicit comment -__ssh_authorized_keys user-name \ - --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ - --option no-agent-forwarding \ - --option 'from="*.example.com"' \ - --comment 'backup server' + # allow key to login as user-name + __ssh_authorized_keys user-name \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." -# same as above, but with explicit owner and two keys -# note that the options are set for all given keys -__ssh_authorized_keys some-fancy-id \ - --owner user-name \ - --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ - --key "ssh-rsa AZXYAAB3NzaC1yc2..." \ - --option no-agent-forwarding \ - --option 'from="*.example.com"' \ - --comment 'backup server' + # allow key to login as user-name with options and expicit comment + __ssh_authorized_keys user-name \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ + --option no-agent-forwarding \ + --option 'from="*.example.com"' \ + --comment 'backup server' -# authorized_keys file in non standard location -__ssh_authorized_keys some-fancy-id \ - --file /etc/ssh/keys/user-name/authorized_keys \ - --owner user-name \ - --key "ssh-rsa AXYZAAB3NzaC1yc2..." + # same as above, but with explicit owner and two keys + # note that the options are set for all given keys + __ssh_authorized_keys some-fancy-id \ + --owner user-name \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." \ + --key "ssh-rsa AZXYAAB3NzaC1yc2..." \ + --option no-agent-forwarding \ + --option 'from="*.example.com"' \ + --comment 'backup server' -# same as above, but directory and authorized_keys file is created elswhere -__ssh_authorized_keys some-fancy-id \ - --file /etc/ssh/keys/user-name/authorized_keys \ - --owner user-name \ - --noparent \ - --nofile \ - --key "ssh-rsa AXYZAAB3NzaC1yc2..." --------------------------------------------------------------------------------- + # authorized_keys file in non standard location + __ssh_authorized_keys some-fancy-id \ + --file /etc/ssh/keys/user-name/authorized_keys \ + --owner user-name \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." + + # same as above, but directory and authorized_keys file is created elswhere + __ssh_authorized_keys some-fancy-id \ + --file /etc/ssh/keys/user-name/authorized_keys \ + --owner user-name \ + --noparent \ + --nofile \ + --key "ssh-rsa AXYZAAB3NzaC1yc2..." SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - sshd(8) diff --git a/cdist/conf/type/__ssh_dot_ssh/man.text b/cdist/conf/type/__ssh_dot_ssh/man.rst similarity index 57% rename from cdist/conf/type/__ssh_dot_ssh/man.text rename to cdist/conf/type/__ssh_dot_ssh/man.rst index 2cd2001c..1b84c924 100644 --- a/cdist/conf/type/__ssh_dot_ssh/man.text +++ b/cdist/conf/type/__ssh_dot_ssh/man.rst @@ -1,11 +1,12 @@ cdist-type__ssh_dot_ssh(7) ========================== +Manage .ssh directory + Nico Schottelius NAME ---- -cdist-type__ssh_dot_ssh - Manage .ssh directory DESCRIPTION @@ -14,28 +15,29 @@ Adds or removes .ssh directory to a user home. This type is being used by __ssh_authorized_keys. + OPTIONAL PARAMETERS ------------------- -state:: +state if the directory should be 'present' or 'absent', defaults to 'present'. EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure root has ~/.ssh with the right permissions -__ssh_dot_ssh root +.. code-block:: sh -# Nico does not need ~/.ssh anymore -__ssh_dot_ssh nico --state absent --------------------------------------------------------------------------------- + # Ensure root has ~/.ssh with the right permissions + __ssh_dot_ssh root + + # Nico does not need ~/.ssh anymore + __ssh_dot_ssh nico --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__ssh_authorized_keys(7) +- `cdist-type(7) `_ +- `cdist-type__ssh_authorized_keys(7) `_ COPYING diff --git a/cdist/conf/type/__staged_file/man.text b/cdist/conf/type/__staged_file/man.rst similarity index 69% rename from cdist/conf/type/__staged_file/man.text rename to cdist/conf/type/__staged_file/man.rst index e94e491d..ed977b28 100644 --- a/cdist/conf/type/__staged_file/man.text +++ b/cdist/conf/type/__staged_file/man.rst @@ -1,13 +1,10 @@ cdist-type__staged_file(7) ========================== +Manage staged files + Steven Armstrong -NAME ----- -cdist-type__staged_file - manage staged files - - DESCRIPTION ----------- Manages a staged file that is downloaded on the server (the machine running @@ -16,17 +13,21 @@ cdist) and then deployed to the target host using the __file type. REQUIRED PARAMETERS ------------------- -source:: +source the URL from which to retreive the source file. e.g. - https://dl.bintray.com/mitchellh/consul/0.4.1_linux_amd64.zip - file:///path/to/local/file -cksum:: + + * https://dl.bintray.com/mitchellh/consul/0.4.1_linux_amd64.zip + * file:///path/to/local/file + +cksum the output of running the command: `cksum $source-file` - e.g. + e.g.:: + $ echo foobar > /tmp/foobar $ cksum /tmp/foobar 857691210 7 /tmp/foobar + If either checksum or file size has changed the file will be (re)fetched from the --source. The file name can be omitted and is ignored if given. @@ -34,19 +35,23 @@ cksum:: OPTIONAL PARAMETERS ------------------- -fetch-command:: +fetch-command the command used to fetch the staged file using printf formatting. Where a single %s will be replaced with the value of the given --source parameter. The --fetch-command is expected to output the fetched file to stdout. Defaults to 'curl -s -L "%s"'. -group:: + +group see cdist-type__file -owner:: + +owner see cdist-type__file -mode:: + +mode see cdist-type__file -prepare-command:: + +prepare-command the optional command used to prepare or preprocess the staged file for later use by the file type. If given, it must be a string in printf formatting where a single %s will @@ -59,42 +64,42 @@ prepare-command:: --prepare-command of 'unzip -p "%s"', the code `unzip -p "my-zip.zip"` will be executed in the folder containing the downloaded file my-zip.zip. A more complex example might be --prepare-command 'tar -xz "%s"; cat path/from/archive' -stage-dir:: +stage-dir the directory in which to store downloaded and prepared files. Defaults to '/var/tmp/cdist/__staged_file' -state:: + +state see cdist-type__file EXAMPLES -------- --------------------------------------------------------------------------------- -__staged_file /usr/local/bin/consul \ - --source file:///path/to/local/copy/consul \ - --cksum '428915666 15738724' \ - --state present \ - --group root \ - --owner root \ - --mode 755 +.. code-block:: sh -__staged_file /usr/local/bin/consul \ - --source https://dl.bintray.com/mitchellh/consul/0.4.1_linux_amd64.zip \ - --cksum '428915666 15738724' \ - --fetch-command 'curl -s -L "%s"' \ - --prepare-command 'unzip -p "%s"' \ - --state present \ - --group root \ - --owner root \ - --mode 755 + __staged_file /usr/local/bin/consul \ + --source file:///path/to/local/copy/consul \ + --cksum '428915666 15738724' \ + --state present \ + --group root \ + --owner root \ + --mode 755 --------------------------------------------------------------------------------- + __staged_file /usr/local/bin/consul \ + --source https://dl.bintray.com/mitchellh/consul/0.4.1_linux_amd64.zip \ + --cksum '428915666 15738724' \ + --fetch-command 'curl -s -L "%s"' \ + --prepare-command 'unzip -p "%s"' \ + --state present \ + --group root \ + --owner root \ + --mode 755 SEE ALSO -------- -- cdist-type(7) -- cdist-type__file(7) +- `cdist-type(7) `_ +- `cdist-type__file(7) `_ COPYING diff --git a/cdist/conf/type/__start_on_boot/man.text b/cdist/conf/type/__start_on_boot/man.rst similarity index 57% rename from cdist/conf/type/__start_on_boot/man.text rename to cdist/conf/type/__start_on_boot/man.rst index dfada6d8..2fb2c7d9 100644 --- a/cdist/conf/type/__start_on_boot/man.text +++ b/cdist/conf/type/__start_on_boot/man.rst @@ -1,53 +1,51 @@ cdist-type__start_on_boot(7) ============================ +Manage stuff to be started at boot + Nico Schottelius -NAME ----- -cdist-type__start_on_boot - Manage stuff to be started at boot - - DESCRIPTION ----------- This cdist type allows you to enable or disable stuff to be started at boot of your operating system. Warning: This type has not been tested intensively and is not fully -supported (i.e. *bsd are not implemented). +supported (i.e. \*BSD are not implemented). REQUIRED PARAMETERS ------------------- None. + OPTIONAL PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present" -target_runlevel:: +target_runlevel Runlevel which should be modified, defaults to "default" (only used on gentoo systems). EXAMPLES -------- --------------------------------------------------------------------------------- -# Ensure snmpd is started at boot -__start_on_boot snmpd +.. code-block:: sh -# Same, but more explicit -__start_on_boot snmpd --state present + # Ensure snmpd is started at boot + __start_on_boot snmpd -# Ensure legacy configuration management will not be started -__start_on_boot puppet --state absent --------------------------------------------------------------------------------- + # Same, but more explicit + __start_on_boot snmpd --state present + + # Ensure legacy configuration management will not be started + __start_on_boot puppet --state absent SEE ALSO -------- -- cdist-type(7) -- cdist-type__process(7) +- `cdist-type(7) `_ +- `cdist-type__process(7) `_ COPYING diff --git a/cdist/conf/type/__timezone/man.text b/cdist/conf/type/__timezone/man.rst similarity index 56% rename from cdist/conf/type/__timezone/man.text rename to cdist/conf/type/__timezone/man.rst index 606a54da..083f4fe6 100644 --- a/cdist/conf/type/__timezone/man.text +++ b/cdist/conf/type/__timezone/man.rst @@ -1,13 +1,10 @@ cdist-type__timezone(7) ======================= +Allows one to configure the desired localtime timezone. + Ramon Salvadó -NAME ----- -cdist-type__timezone - Allows one to configure the desired localtime timezone. - - DESCRIPTION ----------- This type creates a symlink (/etc/localtime) to the selected timezone @@ -27,18 +24,18 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -#Set up Europe/Andorra as our timezone. -__timezone Europe/Andorra +.. code-block:: sh -#Set up US/Central as our timezone. -__timezone US/Central --------------------------------------------------------------------------------- + #Set up Europe/Andorra as our timezone. + __timezone Europe/Andorra + + #Set up US/Central as our timezone. + __timezone US/Central SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__update_alternatives/man.text b/cdist/conf/type/__update_alternatives/man.rst similarity index 61% rename from cdist/conf/type/__update_alternatives/man.text rename to cdist/conf/type/__update_alternatives/man.rst index 2bcc1874..477ee88c 100644 --- a/cdist/conf/type/__update_alternatives/man.text +++ b/cdist/conf/type/__update_alternatives/man.rst @@ -1,13 +1,10 @@ cdist-type__update_alternatives(7) ================================== +Configure alternatives + Nico Schottelius -NAME ----- -cdist-type__update_alternatives - Configure alternatives - - DESCRIPTION ----------- On Debian and alike systems update-alternatives(1) can be used @@ -17,23 +14,23 @@ One of the most common used targets is the "editor". REQUIRED PARAMETERS ------------------- -path:: +path Use this path for the given alternative EXAMPLES -------- --------------------------------------------------------------------------------- -# Setup vim as the default editor -__update_alternatives editor --path /usr/bin/vim.basic --------------------------------------------------------------------------------- +.. code-block:: sh + + # Setup vim as the default editor + __update_alternatives editor --path /usr/bin/vim.basic SEE ALSO -------- -- cdist-type(7) -- cdist-type__debconf_set_selections(7) +- `cdist-type(7) `_ +- `cdist-type__debconf_set_selections(7) `_ - update-alternatives(8) diff --git a/cdist/conf/type/__user/man.text b/cdist/conf/type/__user/man.rst similarity index 56% rename from cdist/conf/type/__user/man.text rename to cdist/conf/type/__user/man.rst index be70ec12..c690a559 100644 --- a/cdist/conf/type/__user/man.text +++ b/cdist/conf/type/__user/man.rst @@ -1,13 +1,10 @@ cdist-type__user(7) =================== +Manage users + Steven Armstrong -NAME ----- -cdist-type__user - Manage users - - DESCRIPTION ----------- This cdist type allows you to create or modify users on the target. @@ -20,63 +17,73 @@ None. OPTIONAL PARAMETERS ------------------- -state:: +state absent or present, defaults to present -comment:: + +comment see usermod(8) -home:: + +home see above -gid:: + +gid see above -password:: + +password see above -shell:: + +shell see above -uid:: + +uid see above + BOOLEAN PARAMETERS ------------------ -system:: +system see useradd(8), apply only on user create -create-home:: + +create-home see useradd(8), apply only on user create -remove-home:: + +remove-home see userdel(8), apply only on user delete MESSAGES -------- -mod:: +mod User is modified -add:: + +add New user added EXAMPLES -------- --------------------------------------------------------------------------------- -# Create user account for foobar with operating system default settings -__user foobar +.. code-block:: sh -# Same but with a different shell -__user foobar --shell /bin/zsh + # Create user account for foobar with operating system default settings + __user foobar -# Same but for a system account -__user foobar --system + # Same but with a different shell + __user foobar --shell /bin/zsh -# Set explicit uid and home -__user foobar --uid 1001 --shell /bin/zsh --home /home/foobar + # Same but for a system account + __user foobar --system -# Drop user if exists -__user foobar --state absent --------------------------------------------------------------------------------- + # Set explicit uid and home + __user foobar --uid 1001 --shell /bin/zsh --home /home/foobar + + # Drop user if exists + __user foobar --state absent SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - usermod(8) or pw(8) diff --git a/cdist/conf/type/__user_groups/man.text b/cdist/conf/type/__user_groups/man.rst similarity index 60% rename from cdist/conf/type/__user_groups/man.text rename to cdist/conf/type/__user_groups/man.rst index d45784fe..4458a6cf 100644 --- a/cdist/conf/type/__user_groups/man.text +++ b/cdist/conf/type/__user_groups/man.rst @@ -1,13 +1,10 @@ cdist-type__user_groups(7) ========================== +Manage user groups + Steven Armstrong -NAME ----- -cdist-type__user_groups - manage user groups - - DESCRIPTION ----------- Adds or removes a user from one or more groups. @@ -15,35 +12,35 @@ Adds or removes a user from one or more groups. REQUIRED PARAMETERS ------------------- -group:: +group the group to which this user should be added or removed. Can be specified multiple times. OPTIONAL PARAMETERS ------------------- -user:: +user the name of the user. Defaults to object_id -state:: +state absent or present. Defaults to present. EXAMPLES -------- --------------------------------------------------------------------------------- -__user_groups nginx --group webuser1 --group webuser2 +.. code-block:: sh -# remove user nginx from groups webuser2 -__user_groups nginx-webuser2 --user nginx \ - --group webuser2 --state absent --------------------------------------------------------------------------------- + __user_groups nginx --group webuser1 --group webuser2 + + # remove user nginx from groups webuser2 + __user_groups nginx-webuser2 --user nginx \ + --group webuser2 --state absent SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__yum_repo/man.rst b/cdist/conf/type/__yum_repo/man.rst new file mode 100644 index 00000000..396f271c --- /dev/null +++ b/cdist/conf/type/__yum_repo/man.rst @@ -0,0 +1,121 @@ +cdist-type__yum_repo(7) +======================= +Manage yum repositories + +Steven Armstrong + + +DESCRIPTION +----------- +For all undocumented parameters see yum.conf(5). + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state + 'present' or 'absent'. Defaults to 'present' + +repositoryid + Defaults to __object_id. + +name + +baseurl + Can be specified multiple times. + +metalink + +mirrorlist + +gpgkey + Can be specified multiple times. + +gpgcakey + +gpgcheck + +exclude + +includepkgs + +failovermethod + +timeout + +http_caching + +retries + +throttle + +bandwidth + +sslcacert + +sslverify + +sslclientcert + +sslclientkey + +ssl_check_cert_permissions + +metadata_expire + +mirrorlist_expire + +proxy + +proxy_username + +proxy_password + +username + +password + +cost + + +BOOLEAN PARAMETERS +------------------ +enabled + +repo_gpgcheck + +disablegroups + ! enablegroups + +keepalive + +skip_if_unavailable + + +EXAMPLES +-------- + +.. code-block:: sh + + __yum_repo epel \ + --name 'Extra Packages for Enterprise Linux 6 - $basearch' \ + --mirrorlist 'https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch' \ + --failovermethod priority \ + --enabled \ + --gpgcheck 1 \ + --gpgkey https://fedoraproject.org/static/0608B895.txt + + +SEE ALSO +-------- +- `cdist-type(7) `_ + + +COPYING +------- +Copyright \(C) 2014 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__yum_repo/man.text b/cdist/conf/type/__yum_repo/man.text deleted file mode 100644 index 549cf336..00000000 --- a/cdist/conf/type/__yum_repo/man.text +++ /dev/null @@ -1,91 +0,0 @@ -cdist-type__yum_repo(7) -======================= -Steven Armstrong - - -NAME ----- -cdist-type__yum_repo - manage yum repositories - - -DESCRIPTION ------------ -For all undocumented parameters see yum.conf(5). - - -REQUIRED PARAMETERS -------------------- -None. - - -OPTIONAL PARAMETERS -------------------- -state:: - 'present' or 'absent'. Defaults to 'present' -repositoryid:: - Defaults to __object_id. -name:: -baseurl:: - Can be specified multiple times. -metalink:: -mirrorlist:: -gpgkey:: - Can be specified multiple times. -gpgcakey:: -gpgcheck:: -exclude:: -includepkgs:: -failovermethod:: -timeout:: -http_caching:: -retries:: -throttle:: -bandwidth:: -sslcacert:: -sslverify:: -sslclientcert:: -sslclientkey:: -ssl_check_cert_permissions:: -metadata_expire:: -mirrorlist_expire:: -proxy:: -proxy_username:: -proxy_password:: -username:: -password:: -cost:: - - -BOOLEAN PARAMETERS ------------------- -enabled:: -repo_gpgcheck:: -disablegroups:: - ! enablegroups -keepalive:: -skip_if_unavailable:: - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -__yum_repo epel \ - --name 'Extra Packages for Enterprise Linux 6 - $basearch' \ - --mirrorlist 'https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch' \ - --failovermethod priority \ - --enabled \ - --gpgcheck 1 \ - --gpgkey https://fedoraproject.org/static/0608B895.txt --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__zypper_repo/man.rst b/cdist/conf/type/__zypper_repo/man.rst new file mode 100644 index 00000000..e3bc1d4f --- /dev/null +++ b/cdist/conf/type/__zypper_repo/man.rst @@ -0,0 +1,70 @@ +cdist-type__zypper_repo(7) +========================== +Repository management with zypper + +Daniel Heule + + +DESCRIPTION +----------- +zypper is usually used on the SuSE distribution to manage repositories. + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +state + Either "present" or "absent" or "enabled" or "disabled", defaults to "present" + + * **present** - make sure that the repo is available, needs uri and repo_desc for all following states, the repo can be searched via repo_id or uri + * **absent** - drop the repo if found + + * **enabled** - a repo can have state disabled if installed via zypper service (ris), in this case, you can enable the repo + * **disabled** - instead of absent (drop), a repo can also set to disabled, which makes it inaccessible + +uri + If supplied, use the uri and not the object id as repo uri. + +repo_desc + If supplied, use the description and not the object id as repo description, only used if the state is present and the repo has to be created + +repo_id + If supplied, use the id and not the object id as repo id, can be used with state absent, enabled and disabled + + +EXAMPLES +-------- + +.. code-block:: sh + + # Ensure testrepo in installed + __zypper_repo testrepo --state present --uri http://url.to.your.repo/with/path + + # Drop repo by repo uri + __zypper_repo testrepo --state absent --uri http://url.to.your.repo/with/path + + # Drop repo by id number (attention: repos are always numbered from 1 to max) + __zypper_repo testrepo --state absent --repo_id 1 + + # enable repo by id + __zypper_repo testrepo2 --state enabled --repo_id 2 + + # enable repo by uri + __zypper_repo testrepo3 --state enabled --uri http://url.to.your.repo/with/path + + # disable a repo works like enabling it + __zypper_repo testrepo4 --state disabled --repo_id 4 + + +SEE ALSO +-------- +- `cdist-type(7) `_ + + +COPYING +------- +Copyright \(C) 2013 Daniel Heule. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__zypper_repo/man.text b/cdist/conf/type/__zypper_repo/man.text deleted file mode 100644 index a1dd9565..00000000 --- a/cdist/conf/type/__zypper_repo/man.text +++ /dev/null @@ -1,73 +0,0 @@ -cdist-type__zypper_repo(7) -========================== -Daniel Heule - - -NAME ----- -cdist-type__zypper_repo - repository management with zypper - - -DESCRIPTION ------------ -zypper is usually used on the SuSE distribution to manage repositories. - - -REQUIRED PARAMETERS -------------------- -None - - -OPTIONAL PARAMETERS -------------------- -state:: - Either "present" or "absent" or "enabled" or "disabled", defaults to "present" + - #present# - make sure that the repo is available, needs uri and repo_desc + - for all following states, the repo can be searched via repo_id or uri + - #absent# - drop the repo if found + - #enabled# - a repo can have state disabled if installed via zypper service (ris), in this case, you can enable the repo + - #disabled# - instead of absent (drop), a repo can also set to disabled, which makes it inaccessible + - -uri:: - If supplied, use the uri and not the object id as repo uri. - -repo_desc:: - If supplied, use the description and not the object id as repo description, only used if the state is present and the repo has to be created - -repo_id:: - If supplied, use the id and not the object id as repo id, can be used with state absent, enabled and disabled - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Ensure testrepo in installed -__zypper_repo testrepo --state present --uri http://url.to.your.repo/with/path - -# Drop repo by repo uri -__zypper_repo testrepo --state absent --uri http://url.to.your.repo/with/path - -# Drop repo by id number (attention: repos are always numbered from 1 to max) -__zypper_repo testrepo --state absent --repo_id 1 - -# enable repo by id -__zypper_repo testrepo2 --state enabled --repo_id 2 - -# enable repo by uri -__zypper_repo testrepo3 --state enabled --uri http://url.to.your.repo/with/path - -# disable a repo works like enabling it -__zypper_repo testrepo4 --state disabled --repo_id 4 --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2013 Daniel Heule. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__zypper_service/man.rst b/cdist/conf/type/__zypper_service/man.rst new file mode 100644 index 00000000..377d30e1 --- /dev/null +++ b/cdist/conf/type/__zypper_service/man.rst @@ -0,0 +1,63 @@ +cdist-type__zypper_service(7) +============================= +Service management with zypper + +Daniel Heule + + +DESCRIPTION +----------- +zypper is usually used on SuSE systems to manage services. + + +REQUIRED PARAMETERS +------------------- +uri + Uri of the service + + +OPTIONAL PARAMETERS +------------------- +service_desc + If supplied, use the service_desc and not the object id as descritpion for the service. + +state + Either "present" or "absent", defaults to "present" + +type + Defaults to "ris", the standard type of services at SLES11. For other values, see manpage of zypper. + + +BOOLEAN PARAMETERS +------------------ +remove-all-other-services + Drop all other services found on the target host before adding the new one. + +remove-all-repos + If supplied, remove all existing repos prior to setup the new service. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Ensure that internal SLES11 SP3 RIS is in installed and all other services and repos are discarded + __zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --uri "http://path/to/your/ris/dir" --remove-all-other-services --remove-all-repos + + # Ensure that internal SLES11 SP3 RIS is in installed, no changes to ohter services or repos + __zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --uri "http://path/to/your/ris/dir" + + # Drop service by uri, no changes to ohter services or repos + __zypper_service INTERNAL_SLES11_SP3 --state absent --uri "http://path/to/your/ris/dir" + + +SEE ALSO +-------- +- `cdist-type(7) `_ + + +COPYING +------- +Copyright \(C) 2013 Daniel Heule. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__zypper_service/man.text b/cdist/conf/type/__zypper_service/man.text deleted file mode 100644 index b6bba660..00000000 --- a/cdist/conf/type/__zypper_service/man.text +++ /dev/null @@ -1,67 +0,0 @@ -cdist-type__zypper_service(7) -============================= -Daniel Heule - - -NAME ----- -cdist-type__zypper_service - service management with zypper - - -DESCRIPTION ------------ -zypper is usually used on SuSE systems to manage services. - - -REQUIRED PARAMETERS -------------------- -uri:: - Uri of the service - - -OPTIONAL PARAMETERS -------------------- -service_desc:: - If supplied, use the service_desc and not the object id as descritpion for the service. - -state:: - Either "present" or "absent", defaults to "present" - -type:: - Defaults to "ris", the standard type of services at SLES11. For other values, see manpage of zypper. - - -BOOLEAN PARAMETERS ------------------- -remove-all-other-services:: - Drop all other services found on the target host before adding the new one. - -remove-all-repos:: - If supplied, remove all existing repos prior to setup the new service. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Ensure that internal SLES11 SP3 RIS is in installed and all other services and repos are discarded -__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --uri "http://path/to/your/ris/dir" --remove-all-other-services --remove-all-repos - -# Ensure that internal SLES11 SP3 RIS is in installed, no changes to ohter services or repos -__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --uri "http://path/to/your/ris/dir" - -# Drop service by uri, no changes to ohter services or repos -__zypper_service INTERNAL_SLES11_SP3 --state absent --uri "http://path/to/your/ris/dir" - --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2013 Daniel Heule. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/Makefile b/docs/man/Makefile new file mode 100644 index 00000000..721acaf6 --- /dev/null +++ b/docs/man/Makefile @@ -0,0 +1,230 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) + $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cdist-docs.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cdist-docs.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/cdist-docs" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cdist-docs" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.rst.sh similarity index 85% rename from docs/man/cdist-reference.text.sh rename to docs/man/cdist-reference.rst.sh index 012bcf5d..ae73169e 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.rst.sh @@ -37,11 +37,9 @@ exec > "$dest" cat << eof cdist-reference(7) ================== -Nico Schottelius +Variable, path and type reference for cdist -NAME ----- -cdist-reference - Variable, path and type reference for cdist +Nico Schottelius EXPLORERS @@ -60,97 +58,97 @@ cat << eof PATHS ----- -\$HOME/.cdist:: +\$HOME/.cdist The standard cdist configuration directory relative to your home directory This is usually the place you want to store your site specific configuration -cdist/conf/:: +cdist/conf/ The distribution configuration directory This contains types and explorers to be used -confdir:: +confdir Cdist will use all available configuration directories and create a temporary confdir containing links to the real configuration directories. This way it is possible to merge configuration directories. By default it consists of everything in \$HOME/.cdist and cdist/conf/. For more details see cdist(1) -confdir/manifest/init:: +confdir/manifest/init This is the central entry point. It is an executable (+x bit set) shell script that can use values from the explorers to decide which configuration to create for the specified target host. Its intent is to used to define mapping from configurations to hosts. -confdir/manifest/*:: +confdir/manifest/* All other files in this directory are not directly used by cdist, but you can separate configuration mappings, if you have a lot of code in the conf/manifest/init file. This may also be helpful to have different admins maintain different groups of hosts. -confdir/explorer/:: +confdir/explorer/ Contains explorers to be run on the target hosts, see cdist-explorer(7). -confdir/type/:: +confdir/type/ Contains all available types, which are used to provide some kind of functionality. See cdist-type(7). -confdir/type//:: +confdir/type// Home of the type . This directory is referenced by the variable __type (see below). -confdir/type//man.text:: - Manpage in Asciidoc format (required for inclusion into upstream) +confdir/type//man.rst + Manpage in reStructuredText format (required for inclusion into upstream) -confdir/type//manifest:: +confdir/type//manifest Used to generate additional objects from a type. -confdir/type//gencode-local:: +confdir/type//gencode-local Used to generate code to be executed on the source host -confdir/type//gencode-remote:: +confdir/type//gencode-remote Used to generate code to be executed on the target host -confdir/type//parameter/required:: +confdir/type//parameter/required Parameters required by type, \n separated list. -confdir/type//parameter/optional:: +confdir/type//parameter/optional Parameters optionally accepted by type, \n separated list. -confdir/type//parameter/default/*:: +confdir/type//parameter/default/* Default values for optional parameters. Assuming an optional parameter name of 'foo', it's default value would be read from the file confdir/type//parameter/default/foo. -confdir/type//parameter/boolean:: +confdir/type//parameter/boolean Boolean parameters accepted by type, \n separated list. -confdir/type//explorer:: +confdir/type//explorer Location of the type specific explorers. This directory is referenced by the variable __type_explorer (see below). See cdist-explorer(7). -confdir/type//files:: +confdir/type//files This directory is reserved for user data and will not be used by cdist at any time. It can be used for storing supplementary files (like scripts to act as a template or configuration files). -out/:: +out/ This directory contains output of cdist and is usually located in a temporary directory and thus will be removed after the run. This directory is referenced by the variable __global (see below). -out/explorer:: +out/explorer Output of general explorers. -out/object:: +out/object Objects created for the host. -out/object/:: +out/object/ Contains all object specific information. This directory is referenced by the variable __object (see below). -out/object//explorers:: +out/object//explorers Output of type specific explorers, per object. TYPES @@ -159,14 +157,15 @@ The following types are available: eof -for type in man7/cdist-type__*.text; do +for type in man7/cdist-type__*.rst; do no_dir="${type#man7/}"; no_type="${no_dir#cdist-type}"; - name="${no_type%.text}"; + name="${no_type%.rst}"; name_no_underline="$(echo $name | sed 's/^__/\\__/g')" - man="${no_dir%.text}(7)" + manref="${no_dir%.rst}" + man="${manref}(7)" - echo "- $name_no_underline" "($man)" + echo "- $name_no_underline" "(\`${man} <${manref}.html>\`_)" done cat << eof @@ -177,14 +176,14 @@ OBJECTS For object to object communication and tests, the following paths are usable within a object directory: -files:: +files This directory is reserved for user data and will not be used by cdist at any time. It can be used freely by the type (for instance to store template results). -changed:: +changed This empty file exists in an object directory, if the object has code to be executed (either remote or local) -stdin:: +stdin This file exists and contains data, if data was provided on stdin when the type was called. @@ -193,40 +192,40 @@ ENVIRONMENT VARIABLES (FOR READING) ----------------------------------- The following environment variables are exported by cdist: -__explorer:: +__explorer Directory that contains all global explorers. Available for: initial manifest, explorer, type explorer, shell -__manifest:: +__manifest Directory that contains the initial manifest. Available for: initial manifest, type manifest, shell -__global:: +__global Directory that contains generic output like explorer. Available for: initial manifest, type manifest, type gencode, shell -__messages_in:: +__messages_in File to read messages from. Available for: initial manifest, type manifest, type gencode -__messages_out:: +__messages_out File to write messages. Available for: initial manifest, type manifest, type gencode -__object:: +__object Directory that contains the current object. Available for: type manifest, type explorer, type gencode and code scripts -__object_id:: +__object_id The type unique object id. Available for: type manifest, type explorer, type gencode and code scripts Note: The leading and the trailing "/" will always be stripped (caused by the filesystem database and ensured by the core). Note: Double slashes ("//") will not be fixed and result in an error. -__object_name:: +__object_name The full qualified name of the current object. Available for: type manifest, type explorer, type gencode -__target_host:: +__target_host The host we are deploying to. Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell -__type:: +__type Path to the current type. Available for: type manifest, type gencode -__type_explorer:: +__type_explorer Directory that contains the type explorers. Available for: type explorer @@ -234,30 +233,30 @@ ENVIRONMENT VARIABLES (FOR WRITING) ----------------------------------- The following environment variables influence the behaviour of cdist: -require:: +require Setup dependencies between objects (see cdist-manifest(7)) -CDIST_LOCAL_SHELL:: +CDIST_LOCAL_SHELL Use this shell locally instead of /bin/sh to execute scripts -CDIST_REMOTE_SHELL:: +CDIST_REMOTE_SHELL Use this shell remotely instead of /bin/sh to execute scripts -CDIST_OVERRIDE:: +CDIST_OVERRIDE Allow overwriting type parameters (see cdist-manifest(7)) -CDIST_ORDER_DEPENDENCY:: +CDIST_ORDER_DEPENDENCY Create dependencies based on the execution order (see cdist-manifest(7)) -CDIST_REMOTE_EXEC:: +CDIST_REMOTE_EXEC Use this command for remote execution (should behave like ssh) -CDIST_REMOTE_COPY:: +CDIST_REMOTE_COPY Use this command for remote copy (should behave like scp) SEE ALSO -------- -- cdist(1) +- \`cdist(1) <../man1/cdist.html>\`_ COPYING diff --git a/docs/man/conf.py b/docs/man/conf.py new file mode 100644 index 00000000..0cf8bc61 --- /dev/null +++ b/docs/man/conf.py @@ -0,0 +1,305 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# cdist-docs documentation build configuration file, created by +# sphinx-quickstart on Fri May 6 21:45:28 2016. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +source_suffix = ['.rst'] + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'cdist' +#copyright = '2016, Darko Poljak' +#author = 'Darko Poljak' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +import cdist.version +version = cdist.version.VERSION +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +import sphinx_rtd_theme +html_theme = 'sphinx_rtd_theme' +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +#html_title = 'cdist-docs v0.0.1' + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +#html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None +#html_file_suffix = "" + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'cdistdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'cdist.tex', 'cdist Documentation', + 'Darko Poljak', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +mandir = os.path.dirname(os.path.realpath(__file__)) +man_pages = [] +for mansubdir in ('man1', 'man7'): + for root, dirs, files in os.walk(os.path.join(mandir, mansubdir)): + for fname in files: + froot, fext = os.path.splitext(fname) + if fext == '.rst': + man_page = (os.path.join(mansubdir, froot), froot, '', + [], 7) + man_pages.append(man_page) + +#man_pages = [ +# ('cdist-type', 'cdist-type', 'cdist-type documentation', +# [author], 1), +# ('man7/cdist-type__file', 'cdist-type__file', +# '', [], 1), +# ('cdist-type__directory', 'cdist-type__directory', +# 'cdist-type__directory documentation', [author], 1), +#] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'cdist', 'cdist Documentation', + '', 'cdist', 'Configuration management system.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/docs/man/index.rst b/docs/man/index.rst new file mode 100644 index 00000000..f0638779 --- /dev/null +++ b/docs/man/index.rst @@ -0,0 +1,12 @@ +Welcome to cdist documentation +============================== + +Contents: + +.. toctree:: + :titlesonly: + :glob: + :numbered: + + man1/* + man7/* diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.rst similarity index 60% rename from docs/man/man1/cdist.text rename to docs/man/man1/cdist.rst index e29ae3ae..0178215c 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.rst @@ -1,22 +1,22 @@ cdist(1) ======== +Usable Configuration Management + Nico Schottelius -NAME ----- -cdist - Usable Configuration Management - - SYNOPSIS -------- -cdist [-h] [-d] [-v] [-V] {banner,config,shell} ... -cdist banner [-h] [-d] [-v] +:: -cdist config [-h] [-d] [-V] [-c CONF_DIR] [-i MANIFEST] [-p] [-s] host [host ...] + cdist [-h] [-d] [-v] [-V] {banner,config,shell} ... -cdist shell [-h] [-d] [-v] [-s SHELL] + cdist banner [-h] [-d] [-v] + + cdist config [-h] [-d] [-V] [-c CONF_DIR] [-i MANIFEST] [-p] [-s] host [host ...] + + cdist shell [-h] [-d] [-v] [-s SHELL] DESCRIPTION @@ -28,16 +28,20 @@ GENERAL ------- All commands accept the following options: --d, --debug:: +.. option:: -d, --debug + Set log level to debug --h, --help:: +.. option:: -h, --help + Show the help screen --v, --verbose:: +.. option:: -v, --verbose + Set log level to info, be more verbose --V, --version:: +.. option:: -V, --version + Show version and exit @@ -51,10 +55,12 @@ CONFIG ------ Configure one or more hosts --h, --help:: +.. option:: -h, --help + Show the help screen --c CONF_DIR, --conf-dir CONF_DIR:: +.. option:: -c CONF_DIR, --conf-dir CONF_DIR + Add a configuration directory. Can be specified multiple times. If configuration directories contain conflicting types, explorers or manifests, then the last one found is used. Additionally this can also @@ -63,19 +69,24 @@ Configure one or more hosts --conf-dir argument have higher precedence over those set through the environment variable. --i MANIFEST, --initial-manifest MANIFEST:: +.. option:: -i MANIFEST, --initial-manifest MANIFEST + Path to a cdist manifest or - to read from stdin --p, --parallel:: +.. option:: -p, --parallel + Operate on multiple hosts in parallel --s, --sequential:: +.. option:: -s, --sequential + Operate on multiple hosts sequentially ---remote-copy REMOTE_COPY:: +.. option:: --remote-copy REMOTE_COPY + Command to use for remote copy (should behave like scp) ---remote-exec REMOTE_EXEC:: +.. option:: --remote-exec REMOTE_EXEC + Command to use for remote execution (should behave like ssh) SHELL @@ -85,79 +96,78 @@ to the types as commands. It can be thought as an "interactive manifest" environment. See below for example usage. Its primary use is for debugging type parameters. --s/--shell:: +.. option:: -s/--shell + Select shell to use, defaults to current shell EXAMPLES -------- --------------------------------------------------------------------------------- -# Configure ikq05.ethz.ch with debug enabled -% cdist config -d ikq05.ethz.ch +.. code-block:: sh -# Configure hosts in parallel and use a different configuration directory -% cdist config -c ~/p/cdist-nutzung \ - -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch + # Configure ikq05.ethz.ch with debug enabled + % cdist config -d ikq05.ethz.ch -# Use custom remote exec / copy commands -% cdist config --remote-exec /path/to/my/remote/exec \ - --remote-copy /path/to/my/remote/copy \ - -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch + # Configure hosts in parallel and use a different configuration directory + % cdist config -c ~/p/cdist-nutzung \ + -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch -# Display banner -cdist banner + # Use custom remote exec / copy commands + % cdist config --remote-exec /path/to/my/remote/exec \ + --remote-copy /path/to/my/remote/copy \ + -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch -# Show help -% cdist --help + # Display banner + cdist banner -# Show Version -% cdist --version + # Show help + % cdist --help -# Enter a shell that has access to emulated types -% cdist shell -% __git -usage: __git --source SOURCE [--state STATE] [--branch BRANCH] - [--group GROUP] [--owner OWNER] [--mode MODE] object_id + # Show Version + % cdist --version - --------------------------------------------------------------------------------- + # Enter a shell that has access to emulated types + % cdist shell + % __git + usage: __git --source SOURCE [--state STATE] [--branch BRANCH] + [--group GROUP] [--owner OWNER] [--mode MODE] object_id ENVIRONMENT ----------- -TMPDIR, TEMP, TMP:: +TMPDIR, TEMP, TMP Setup the base directory for the temporary directory. See http://docs.python.org/py3k/library/tempfile.html for more information. This is rather useful, if the standard directory used does not allow executables. -CDIST_LOCAL_SHELL:: +CDIST_LOCAL_SHELL Selects shell for local script execution, defaults to /bin/sh -CDIST_REMOTE_SHELL:: +CDIST_REMOTE_SHELL Selects shell for remote scirpt execution, defaults to /bin/sh -CDIST_REMOTE_EXEC:: +CDIST_REMOTE_EXEC Use this command for remote execution (should behave like ssh) -CDIST_REMOTE_COPY:: +CDIST_REMOTE_COPY Use this command for remote copy (should behave like scp) EXIT STATUS ----------- The following exit values shall be returned: -0:: +0 Successful completion -1:: +1 One or more host configurations failed SEE ALSO -------- -- cdist(7) -- cdist-reference(7) +- `cdist-type(7) <../man7/cdist-type.html>`_ +- `cdist-reference(7) <../man7/cdist-reference.html>`_ COPYING diff --git a/docs/man/man7/cdist-best-practice.rst b/docs/man/man7/cdist-best-practice.rst new file mode 100644 index 00000000..13d65cce --- /dev/null +++ b/docs/man/man7/cdist-best-practice.rst @@ -0,0 +1,238 @@ +cdist-best-practice(7) +====================== +Practices used in real environments + +Nico Schottelius + + +PASSWORDLESS CONNECTIONS +------------------------ +It is recommended to run cdist with public key authentication. +This requires a private/public key pair and the entry +"PermitRootLogin without-password" in the sshd server. +See sshd_config(5) and ssh-keygen(1). + + +SPEEDING UP SSH CONNECTIONS +--------------------------- +When connecting to a new host, the initial delay with ssh connections +is pretty big. You can work around this by +"sharing of multiple sessions over a single network connection" +(quote from ssh_config(5)). The following code is suitable for +inclusion into your ~/.ssh/config:: + + Host * + ControlPath ~/.ssh/master-%l-%r@%h:%p + ControlMaster auto + ControlPersist 10 + + +SPEEDING UP SHELL EXECUTION +---------------------------- +On the source host, ensure that /bin/sh is *not* bash: bash is quite slow for +script execution. Instead, you could use dash after installing it:: + + ln -sf /bin/dash /bin/sh + + +MULTI MASTER OR ENVIRONMENT SETUPS +---------------------------------- +If you plan to distribute cdist among servers or use different +environments, you can do so easily with the included version +control git. For instance if you plan to use the typical three +environments production, integration and development, you can +realise this with git branches:: + + # Go to cdist checkout + cd /path/to/cdist + + # Create branches + git branch development + git branch integration + git branch production + + # Make use of a branch, for instance production + git checkout production + +Similar if you want to have cdist checked out at multiple machines, +you can clone it multiple times:: + + machine-a % git clone git://your-git-server/cdist + machine-b % git clone git://your-git-server/cdist + + +SEPERATING WORK BY GROUPS +------------------------- +If you are working with different groups on one cdist-configuration, +you can delegate to other manifests and have the groups edit only +their manifests. You can use the following snippet in +**conf/manifests/init**:: + + # Include other groups + sh -e "$__manifest/systems" + + sh -e "$__manifest/cbrg" + + +MAINTAINING MULTIPLE CONFIGURATIONS +----------------------------------- +When you need to manage multiple sites with cdist, like company_a, company_b +and private for instance, you can easily use git for this purpose. +Including a possible common base that is reused across the different sites:: + + # create branches + git branch company_a company_b common private + + # make stuff for company a + git checkout company_a + # work, commit, etc. + + # make stuff for company b + git checkout company_b + # work, commit, etc. + + # make stuff relevant for all sites + git checkout common + # work, commit, etc. + + # change to private and include latest common stuff + git checkout private + git merge common + + +The following **.git/config** is taken from a a real world scenario:: + + # Track upstream, merge from time to time + [remote "upstream"] + url = git://git.schottelius.org/cdist + fetch = +refs/heads/*:refs/remotes/upstream/* + + # Same as upstream, but works when being offline + [remote "local"] + fetch = +refs/heads/*:refs/remotes/local/* + url = /home/users/nico/p/cdist + + # Remote containing various ETH internal branches + [remote "eth"] + url = sans.ethz.ch:/home/services/sans/git/cdist-eth + fetch = +refs/heads/*:refs/remotes/eth/* + + # Public remote that contains my private changes to cdist upstream + [remote "nico"] + url = git.schottelius.org:/home/services/git/cdist-nico + fetch = +refs/heads/*:refs/remotes/nico/* + + # The "nico" branch will be synced with the remote nico, branch master + [branch "nico"] + remote = nico + merge = refs/heads/master + + # ETH stable contains rock solid configurations used in various places + [branch "eth-stable"] + remote = eth + merge = refs/heads/stable + +Have a look at git-remote(1) to adjust the remote configuration, which allows + + +MULTIPLE DEVELOPERS WITH DIFFERENT TRUST +---------------------------------------- +If you are working in an environment that requires different people to +work on the same configuration, but having different privileges, you can +implement this scenario with a gateway host and sudo: + +- Create a dedicated user (for instance **cdist**) +- Setup the ssh-pubkey for this user that has the right to configure all hosts +- Create a wrapper to update the cdist configuration in ~cdist/cdist +- Allow every developer to execute this script via sudo as the user cdist +- Allow run of cdist as user cdist on specific hosts on a per user/group base + + - f.i. nico ALL=(ALL) NOPASSWD: /home/cdist/bin/cdist config hostabc + +For more details consult sudoers(5) + + +TEMPLATING +---------- +* create directory files/ in your type (convention) +* create the template as an executable file like files/basic.conf.sh, it will output text using shell variables for the values + +.. code-block:: sh + + #!/bin/sh + # in the template, use cat << eof (here document) to output the text + # and use standard shell variables in the template + # output everything in the template script to stdout + cat << EOF + server { + listen 80; + server_name $SERVERNAME; + root $ROOT; + + access_log /var/log/nginx/$SERVERNAME_access.log + error_log /var/log/nginx/$SERVERNAME_error.log + } + EOF + +* in the manifest, export the relevant variables and add the following lines in your manifest: + +.. code-block:: console + + # export variables needed for the template + export SERVERNAME='test" + export ROOT='/var/www/test' + # render the template + mkdir -p "$__object/files" + "$__type/files/basic.conf.sh" > "$__object/files/basic.conf" + # send the rendered template + __file /etc/nginx/sites-available/test.conf \ + --state present + --source "$__object/files/basic.conf" + + +TESTING A NEW TYPE +------------------ +If you want to test a new type on a node, you can tell cdist to only use an +object of this type: Use the '--initial-manifest' parameter +with - (stdin) as argument and feed object into stdin +of cdist: + +.. code-block:: sh + + # Singleton type without parameter + echo __ungleich_munin_server | cdist --initial-manifest - munin.panter.ch + + # Singleton type with parameter + echo __ungleich_munin_node --allow 1.2.3.4 | \ + cdist --initial-manifest - rails-19.panter.ch + + # Normal type + echo __file /tmp/stdintest --mode 0644 | \ + cdist --initial-manifest - cdist-dev-01.ungleich.ch + + +OTHER CONTENT IN CDIST REPOSITORY +--------------------------------- +Usually the cdist repository contains all configuration +items. Sometimes you may have additional resources that +you would like to store in your central configuration +repositiory (like password files from KeepassX, +Libreoffice diagrams, etc.). + +It is recommended to use a subfolder named "non-cdist" +in the repository for such content: It allows you to +easily distinguish what is used by cdist and what not +and also to store all important files in one +repository. + + +SEE ALSO +-------- +- `cdist(1) <../man1/cdist.html>`_ +- `cdist-tutorial(7) `_ + + +COPYING +------- +Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-best-practice.text b/docs/man/man7/cdist-best-practice.text deleted file mode 100644 index 953b8272..00000000 --- a/docs/man/man7/cdist-best-practice.text +++ /dev/null @@ -1,247 +0,0 @@ -cdist-best-practice(7) -====================== -Nico Schottelius - -NAME ----- -cdist-best-practice - Practices used in real environments - - -PASSWORDLESS CONNECTIONS ------------------------- -It is recommended to run cdist with public key authentication. -This requires a private/public key pair and the entry -"PermitRootLogin without-password" in the sshd server. -See sshd_config(5) and ssh-keygen(1). - - -SPEEDING UP SSH CONNECTIONS ---------------------------- -When connecting to a new host, the initial delay with ssh connections -is pretty big. You can work around this by -"sharing of multiple sessions over a single network connection" -(quote from ssh_config(5)). The following code is suitable for -inclusion into your ~/.ssh/config: - --------------------------------------------------------------------------------- -Host * - ControlPath ~/.ssh/master-%l-%r@%h:%p - ControlMaster auto - ControlPersist 10 --------------------------------------------------------------------------------- - -SPEEDING UP SHELL EXECUTION ----------------------------- -On the source host, ensure that /bin/sh is *not* bash: bash is quite slow for -script execution. Instead, you could use dash after installing it: - --------------------------------------------------------------------------------- -ln -sf /bin/dash /bin/sh --------------------------------------------------------------------------------- - - -MULTI MASTER OR ENVIRONMENT SETUPS ----------------------------------- -If you plan to distribute cdist among servers or use different -environments, you can do so easily with the included version -control git. For instance if you plan to use the typical three -environments production, integration and development, you can -realise this with git branches: - --------------------------------------------------------------------------------- -# Go to cdist checkout -cd /path/to/cdist - -# Create branches -git branch development -git branch integration -git branch production - -# Make use of a branch, for instance production -git checkout production --------------------------------------------------------------------------------- - -Similar if you want to have cdist checked out at multiple machines, -you can clone it multiple times: - --------------------------------------------------------------------------------- -machine-a % git clone git://your-git-server/cdist -machine-b % git clone git://your-git-server/cdist --------------------------------------------------------------------------------- - -SEPERATING WORK BY GROUPS -------------------------- -If you are working with different groups on one cdist-configuration, -you can delegate to other manifests and have the groups edit only -their manifests. You can use the following snippet in -**conf/manifests/init**: - --------------------------------------------------------------------------------- -# Include other groups -sh -e "$__manifest/systems" - -sh -e "$__manifest/cbrg" --------------------------------------------------------------------------------- - - -MAINTAINING MULTIPLE CONFIGURATIONS ------------------------------------ -When you need to manage multiple sites with cdist, like company_a, company_b -and private for instance, you can easily use git for this purpose. -Including a possible common base that is reused across the different sites: - --------------------------------------------------------------------------------- -# create branches -git branch company_a company_b common private - -# make stuff for company a -git checkout company_a -# work, commit, etc. - -# make stuff for company b -git checkout company_b -# work, commit, etc. - -# make stuff relevant for all sites -git checkout common -# work, commit, etc. - -# change to private and include latest common stuff -git checkout private -git merge common --------------------------------------------------------------------------------- - -The following **.git/config** is taken from a a real world scenario: --------------------------------------------------------------------------------- -# Track upstream, merge from time to time -[remote "upstream"] - url = git://git.schottelius.org/cdist - fetch = +refs/heads/*:refs/remotes/upstream/* - -# Same as upstream, but works when being offline -[remote "local"] - fetch = +refs/heads/*:refs/remotes/local/* - url = /home/users/nico/p/cdist - -# Remote containing various ETH internal branches -[remote "eth"] - url = sans.ethz.ch:/home/services/sans/git/cdist-eth - fetch = +refs/heads/*:refs/remotes/eth/* - -# Public remote that contains my private changes to cdist upstream -[remote "nico"] - url = git.schottelius.org:/home/services/git/cdist-nico - fetch = +refs/heads/*:refs/remotes/nico/* - -# The "nico" branch will be synced with the remote nico, branch master -[branch "nico"] - remote = nico - merge = refs/heads/master - -# ETH stable contains rock solid configurations used in various places -[branch "eth-stable"] - remote = eth - merge = refs/heads/stable --------------------------------------------------------------------------------- - -Have a look at git-remote(1) to adjust the remote configuration, which allows - - -MULTIPLE DEVELOPERS WITH DIFFERENT TRUST ----------------------------------------- -If you are working in an environment that requires different people to -work on the same configuration, but having different privileges, you can -implement this scenario with a gateway host and sudo: - -- Create a dedicated user (for instance **cdist**) -- Setup the ssh-pubkey for this user that has the right to configure all hosts -- Create a wrapper to update the cdist configuration in ~cdist/cdist -- Allow every developer to execute this script via sudo as the user cdist -- Allow run of cdist as user cdist on specific hosts on a per user/group base - - f.i. nico ALL=(ALL) NOPASSWD: /home/cdist/bin/cdist config hostabc - -For more details consult sudoers(5) - -TEMPLATING ----------- -* create directory files/ in your type (convention) -* create the template as an executable file like files/basic.conf.sh, it will output text using shell variables for the values - --------------------------------------------------------------------------------- -#!/bin/sh -# in the template, use cat << eof (here document) to output the text -# and use standard shell variables in the template -# output everything in the template script to stdout -cat << EOF -server { - listen 80; - server_name $SERVERNAME; - root $ROOT; - - access_log /var/log/nginx/$SERVERNAME_access.log - error_log /var/log/nginx/$SERVERNAME_error.log -} -EOF --------------------------------------------------------------------------------- - -* in the manifest, export the relevant variables and add the following lines in your manifest: --------------------------------------------------------------------------------- -# export variables needed for the template - export SERVERNAME='test" - export ROOT='/var/www/test' -# render the template - mkdir -p "$__object/files" - "$__type/files/basic.conf.sh" > "$__object/files/basic.conf" -# send the rendered template - __file /etc/nginx/sites-available/test.conf \ - --state present - --source "$__object/files/basic.conf" --------------------------------------------------------------------------------- - - -TESTING A NEW TYPE ------------------- -If you want to test a new type on a node, you can tell cdist to only use an -object of this type: Use the '--initial-manifest' parameter -with - (stdin) as argument and feed object into stdin -of cdist: - --------------------------------------------------------------------------------- -# Singleton type without parameter -echo __ungleich_munin_server | cdist --initial-manifest - munin.panter.ch - -# Singleton type with parameter -echo __ungleich_munin_node --allow 1.2.3.4 | \ - cdist --initial-manifest - rails-19.panter.ch - -# Normal type -echo __file /tmp/stdintest --mode 0644 | \ - cdist --initial-manifest - cdist-dev-01.ungleich.ch --------------------------------------------------------------------------------- - - -OTHER CONTENT IN CDIST REPOSITORY ---------------------------------- -Usually the cdist repository contains all configuration -items. Sometimes you may have additional resources that -you would like to store in your central configuration -repositiory (like password files from KeepassX, -Libreoffice diagrams, etc.). - -It is recommended to use a subfolder named "non-cdist" -in the repository for such content: It allows you to -easily distinguish what is used by cdist and what not -and also to store all important files in one -repository. - - -SEE ALSO --------- -- cdist(1) -- cdist-tutorial(7) - - -COPYING -------- -Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-bootstrap.text b/docs/man/man7/cdist-bootstrap.rst similarity index 59% rename from docs/man/man7/cdist-bootstrap.text rename to docs/man/man7/cdist-bootstrap.rst index 5852bad0..df55e2af 100644 --- a/docs/man/man7/cdist-bootstrap.text +++ b/docs/man/man7/cdist-bootstrap.rst @@ -1,13 +1,10 @@ cdist-bootstrap(7) ================== +Setup cdist environment + Nico Schottelius -NAME ----- -cdist-bootstrap - setup cdist environment - - INTRODUCTION ------------ This document describes the usual steps recommended for a new @@ -42,23 +39,21 @@ you are on the **master** branch. The master branch reflects the latest development of cdist. As this is the development branch, it may or may not work. There are also version branches available, which are kept in a stable state. Let's use **git branch -r** -to list all branches: +to list all branches:: --------------------------------------------------------------------------------- -cdist% git branch -r - origin/1.0 - origin/1.1 - origin/1.2 - origin/1.3 - origin/1.4 - origin/1.5 - origin/1.6 - origin/1.7 - origin/2.0 - origin/HEAD -> origin/master - origin/archive_shell_function_approach - origin/master --------------------------------------------------------------------------------- + cdist% git branch -r + origin/1.0 + origin/1.1 + origin/1.2 + origin/1.3 + origin/1.4 + origin/1.5 + origin/1.6 + origin/1.7 + origin/2.0 + origin/HEAD -> origin/master + origin/archive_shell_function_approach + origin/master So **2.0** is the latest version branch in this example. All versions (2.0.x) within one version branch (2.0) are compatible to each @@ -75,16 +70,14 @@ your own work. Now it's time to create your branch, which contains your local changes. I usually name it by the company/area I am working for: ethz-systems, localch, customerX, ... But this is pretty much up to you. -In this tutorial I use the branch **mycompany**: +In this tutorial I use the branch **mycompany**:: --------------------------------------------------------------------------------- -cdist% git checkout -b mycompany origin/master -Branch mycompany set up to track remote branch master from origin. -Switched to a new branch 'mycompany' -cdist-user% git branch - master -* mycompany --------------------------------------------------------------------------------- + cdist% git checkout -b mycompany origin/master + Branch mycompany set up to track remote branch master from origin. + Switched to a new branch 'mycompany' + cdist-user% git branch + master + * mycompany From now on, you can use git as usual to commit your changes in your own branch. @@ -95,51 +88,47 @@ Usually a development machine like a notebook should be considered temporary only. For this reason and to enable shareability, the configuration should be published to another device as early as possible. The following example shows how to publish the configuration to another host that is -reachable via ssh and has git installed: +reachable via ssh and has git installed:: --------------------------------------------------------------------------------- -# Create bare git repository on the host named "loch" -cdist% ssh loch "GIT_DIR=/home/nutzer/cdist git init" -Initialized empty Git repository in /home/nutzer/cdist/ + # Create bare git repository on the host named "loch" + cdist% ssh loch "GIT_DIR=/home/nutzer/cdist git init" + Initialized empty Git repository in /home/nutzer/cdist/ -# Add remote git repo to git config -cdist% git remote add loch loch:/home/nutzer/cdist + # Add remote git repo to git config + cdist% git remote add loch loch:/home/nutzer/cdist -# Configure the mycompany branch to push to loch -cdist% git config branch.mycompany.remote loch + # Configure the mycompany branch to push to loch + cdist% git config branch.mycompany.remote loch -# Configure mycompany branch to push into remote master branch -cdist% git config branch.mycompany.merge refs/heads/master + # Configure mycompany branch to push into remote master branch + cdist% git config branch.mycompany.merge refs/heads/master -# Push mycompany branch to remote branch master initially -cdist% git push loch mycompany:refs/heads/master --------------------------------------------------------------------------------- + # Push mycompany branch to remote branch master initially + cdist% git push loch mycompany:refs/heads/master Now you have setup the git repository to synchronise the **mycompany** branch with the **master** branch on the host **loch**. Thus you can commit -as usual in your branch and push out changes by entering ***git push***. +as usual in your branch and push out changes by entering **git push**. UPDATING FROM ORIGIN -------------------- -Whenever you want to update your cdist installation, you can use git to do so: +Whenever you want to update your cdist installation, you can use git to do so:: --------------------------------------------------------------------------------- -# Update git repository with latest changes from origin -cdist% git fetch origin + # Update git repository with latest changes from origin + cdist% git fetch origin -# Update current branch with master branch from origin -cdist% git merge origin/master + # Update current branch with master branch from origin + cdist% git merge origin/master -# Alternative: Update current branch with 2.0 branch from origin -cdist% git merge origin/2.0 --------------------------------------------------------------------------------- + # Alternative: Update current branch with 2.0 branch from origin + cdist% git merge origin/2.0 SEE ALSO -------- -- cdist(1) -- cdist-tutorial(7) +- `cdist(1) <../man1/cdist.html>`_ +- `cdist-tutorial(7) `_ COPYING diff --git a/docs/man/man7/cdist-explorer.text b/docs/man/man7/cdist-explorer.rst similarity index 59% rename from docs/man/man7/cdist-explorer.text rename to docs/man/man7/cdist-explorer.rst index a99be050..1bbd7e75 100644 --- a/docs/man/man7/cdist-explorer.text +++ b/docs/man/man7/cdist-explorer.rst @@ -1,13 +1,10 @@ cdist-explorer(7) ================= +Explore the target systems + Nico Schottelius -NAME ----- -cdist-explorer - Explore the target systems - - DESCRIPTION ----------- Explorer are small shell scripts, which will be executed on the target @@ -21,9 +18,17 @@ type explorers. Both work almost exactly the same way, with the difference that the values of the general explorers are stored in a general location and the type specific below the object. -Explorers can reuse other explorers on the target system by calling -$__explorer/ (general and type explorer) or -$__type_explorer/ (type explorer). +Explorers can reuse other explorers on the target system by calling + +:: + + $__explorer/ (general and type explorer) + +or + +:: + + $__type_explorer/ (type explorer). In case of significant errors, the explorer may exit non-zero and return an error message on stderr, which will cause cdist to abort. @@ -33,33 +38,31 @@ explorer. EXAMPLES -------- -A very simple explorer may look like this: +A very simple explorer may look like this:: --------------------------------------------------------------------------------- -hostname --------------------------------------------------------------------------------- + hostname -Which is in practise the ***hostname*** explorer. +Which is in practise the **hostname** explorer. A type explorer, which could check for the status of a package may look like this: --------------------------------------------------------------------------------- -if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" -else - name="$__object_id" -fi +.. code-block:: sh -# Expect dpkg failing, if package is not known / installed -dpkg -s "$name" 2>/dev/null || exit 0 --------------------------------------------------------------------------------- + if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" + else + name="$__object_id" + fi + + # Expect dpkg failing, if package is not known / installed + dpkg -s "$name" 2>/dev/null || exit 0 SEE ALSO -------- -- cdist(1) -- cdist-reference(7) -- cdist-stages(7) +- `cdist(1) <../man1/cdist.html>`_ +- `cdist-reference(7) `_ +- `cdist-stages(7) `_ COPYING diff --git a/docs/man/man7/cdist-hacker.text b/docs/man/man7/cdist-hacker.rst similarity index 60% rename from docs/man/man7/cdist-hacker.text rename to docs/man/man7/cdist-hacker.rst index 2cbf5a8b..1d0e7f2e 100644 --- a/docs/man/man7/cdist-hacker.text +++ b/docs/man/man7/cdist-hacker.rst @@ -1,13 +1,10 @@ cdist-hacker(7) =============== +How to get (stuff) into cdist + Nico Schottelius -NAME ----- -cdist-hacker - How to get (stuff) into cdist - - WELCOME ------- Welcome dear hacker! I invite you to a tour of pointers to @@ -33,6 +30,7 @@ nearby, so grepping for FIXME gives all positions that need to be fixed. Indention is 4 spaces (welcome to the python world). + HOW TO SUBMIT STUFF FOR INCLUSION INTO UPSTREAM CDIST ----------------------------------------------------- If you did some cool changes to cdist, which you value as a benefit for @@ -46,7 +44,9 @@ work nor kill the authors brain: - Do not add cdist/conf/manifest/init - This file should only be touched in your private branch! - Code to be included should be branched of the upstream "master" branch + - Exception: Bugfixes to a version branch + - On a merge request, always name the branch I should pull from - Always ensure **all** manpages build. Use **./build man** to test. - If you developed more than **one** feature, consider submitting them in @@ -69,82 +69,76 @@ AND asciidoc is able to compile it (i.e. do NOT have to many "=" in the second line). Warning: Submitting "exec" or "run" types that simply echo their parameter in -gencode* will not be accepted, because they are of no use. Every type can output +**gencode** will not be accepted, because they are of no use. Every type can output code and thus such a type introduces redundant functionality that is given by core cdist already. EXAMPLE GIT WORKFLOW --------------------- -The following workflow works fine for most developers: +The following workflow works fine for most developers:: --------------------------------------------------------------------------------- -# get latest upstream master branch -git clone https://github.com/telmich/cdist.git + # get latest upstream master branch + git clone https://github.com/telmich/cdist.git -# update if already existing -cd cdist; git fetch -v; git merge origin/master + # update if already existing + cd cdist; git fetch -v; git merge origin/master -# create a new branch for your feature/bugfix -cd cdist # if you haven't done before -git checkout -b documentation_cleanup + # create a new branch for your feature/bugfix + cd cdist # if you haven't done before + git checkout -b documentation_cleanup -# *hack* -*hack* + # *hack* + *hack* -# clone the cdist repository on github if you haven't done so + # clone the cdist repository on github if you haven't done so -# configure your repo to know about your clone (only once) -git remote add github git@github.com:YOURUSERNAME/cdist.git + # configure your repo to know about your clone (only once) + git remote add github git@github.com:YOURUSERNAME/cdist.git -# push the new branch to github -git push github documentation_cleanup + # push the new branch to github + git push github documentation_cleanup -# (or everything) -git push --mirror github + # (or everything) + git push --mirror github -# create a pull request at github (use a browser) -# *fixthingsbecausequalityassurancefoundissuesinourpatch* -*hack* + # create a pull request at github (use a browser) + # *fixthingsbecausequalityassurancefoundissuesinourpatch* + *hack* -# push code to github again -git push ... # like above + # push code to github again + git push ... # like above -# add comment that everything should be green now (use a browser) + # add comment that everything should be green now (use a browser) -# go back to master branch -git checkout master + # go back to master branch + git checkout master -# update master branch that includes your changes now -git fetch -v origin -git diff master..origin/master -git merge origin/master --------------------------------------------------------------------------------- + # update master branch that includes your changes now + git fetch -v origin + git diff master..origin/master + git merge origin/master If at any point you want to go back to the original master branch, you can -use **git stash** to stash your changes away: +use **git stash** to stash your changes away:: --------------------------------------------------------------------------------- -# assume you are on documentation_cleanup -git stash + # assume you are on documentation_cleanup + git stash -# change to master and update to most recent upstream version -git checkout master -git fetch -v origin -git merge origin/master --------------------------------------------------------------------------------- + # change to master and update to most recent upstream version + git checkout master + git fetch -v origin + git merge origin/master Similar when you want to develop another new feature, you go back -to the master branch and create another branch based on it: +to the master branch and create another branch based on it:: --------------------------------------------------------------------------------- -# change to master and update to most recent upstream version -git checkout master -git fetch -v origin -git merge origin/master + # change to master and update to most recent upstream version + git checkout master + git fetch -v origin + git merge origin/master -git checkout -b another_feature --------------------------------------------------------------------------------- + git checkout -b another_feature (you can repeat the code above for as many features as you want to develop in parallel) @@ -152,7 +146,7 @@ in parallel) SEE ALSO -------- -- cdist(7) +- `cdist(1) <../man1/cdist.html>`_ - git(1) - git-checkout(1) - git-stash(1) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.rst similarity index 52% rename from docs/man/man7/cdist-manifest.text rename to docs/man/man7/cdist-manifest.rst index 12cc91c8..c8984acf 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.rst @@ -1,20 +1,17 @@ cdist-manifest(7) ================= +(Re-)Use types + Nico Schottelius -NAME ----- -cdist-manifest - (Re-)Use types - - DESCRIPTION ----------- Manifests are used to define which objects to create. Objects are instances of **types**, like in object oriented programming languages. An object is represented by the combination of **type + slash + object name**: **\__file/etc/cdist-configured** is an -object of the type ***__file*** with the name ***etc/cdist-configured***. +object of the type **__file** with the name **etc/cdist-configured**. All available types can be found in the **cdist/conf/type/** directory, use **ls cdist/conf/type** to get the list of available types. If you have @@ -23,14 +20,13 @@ the reference with pointers to the manpages. Types in manifests are used like normal command line tools. Let's have a look -at an example: --------------------------------------------------------------------------------- -# Create object of type __package with the parameter state = absent -__package apache2 --state absent +at an example:: -# Same with the __directory type -__directory /tmp/cdist --state present --------------------------------------------------------------------------------- + # Create object of type __package with the parameter state = absent + __package apache2 --state absent + + # Same with the __directory type + __directory /tmp/cdist --state present These two lines create objects, which will later be used to realise the configuration on the target host. @@ -62,23 +58,21 @@ Cdist expects the initial manifest at **cdist/conf/manifest/init**. Within this initial manifest you define, which objects should be created on which host. To distinguish between hosts, you can use the environment variable **__target_host**. Let's have a look at a simple -example: +example:: --------------------------------------------------------------------------------- -__cdistmarker + __cdistmarker -case "$__target_host" in - localhost) - __directory /home/services/kvm-vm --parents yes - ;; -esac --------------------------------------------------------------------------------- + case "$__target_host" in + localhost) + __directory /home/services/kvm-vm --parents yes + ;; + esac This manifest says: Independent of the host, always use the type -***__cdistmarker***, which creates the file **/etc/cdist-configured**, +**__cdistmarker**, which creates the file **/etc/cdist-configured**, with the timestamp as content. -The directory ***/home/services/kvm-vm***, including all parent directories, -is only created on the host ***localhost***. +The directory **/home/services/kvm-vm**, including all parent directories, +is only created on the host **localhost**. As you can see, there is no magic involved, the manifest is simple shell code that utilises cdist types. Every available type can be executed like a normal @@ -89,18 +83,16 @@ SPLITTING UP THE INITIAL MANIFEST --------------------------------- If you want to split up your initial manifest, you can create other shell scripts in **cdist/conf/manifest/** and include them in **cdist/conf/manifest/init**. -Cdist provides the environment variable ***__manifest*** to reference +Cdist provides the environment variable **__manifest** to reference the directory containing the initial manifest (see cdist-reference(7)). -The following example would include every file with a **.sh** suffix: +The following example would include every file with a **.sh** suffix:: --------------------------------------------------------------------------------- -# Include *.sh -for manifest in $__manifest/*.sh; do - # And source scripts into our shell environment - . "$manifest" -done --------------------------------------------------------------------------------- + # Include *.sh + for manifest in $__manifest/*.sh; do + # And source scripts into our shell environment + . "$manifest" + done DEPENDENCIES @@ -109,20 +101,19 @@ If you want to describe that something requires something else, just setup the variable "require" to contain the requirements. Multiple requirements can be added white space separated. --------------------------------------------------------------------------------- +:: - 1 # No dependency - 2 __file /etc/cdist-configured - 3 - 4 # Require above object - 5 require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \ - 6 --source /etc/cdist-configured --type symbolic - 7 - 8 # Require two objects - 9 require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ -10 __file /tmp/cdist-another-testfile + 1 # No dependency + 2 __file /etc/cdist-configured + 3 + 4 # Require above object + 5 require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \ + 6 --source /etc/cdist-configured --type symbolic + 7 + 8 # Require two objects + 9 require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \ + 10 __file /tmp/cdist-another-testfile --------------------------------------------------------------------------------- Above the "require" variable is only set for the command that is immediately following it. Dependencies should always be declared that way. @@ -141,23 +132,22 @@ export the "require" variable as well. But then, if you need to add extra dependencies to a specific type, you have to make sure that you append these to the globally already defined one. --------------------------------------------------------------------------------- +:: -# First of all, update the package index -__package_update_index -# Upgrade all the installed packages afterwards -require="__package_update_index" __package_upgrade_all -# Create a common dependency for all the next types so that they get to -# be executed only after the package upgrade has finished -export require="__package_upgrade_all" + # First of all, update the package index + __package_update_index + # Upgrade all the installed packages afterwards + require="__package_update_index" __package_upgrade_all + # Create a common dependency for all the next types so that they get to + # be executed only after the package upgrade has finished + export require="__package_upgrade_all" -# Ensure that lighttpd is installed after we have upgraded all the packages -__package lighttpd --state present -# Ensure that munin is installed after lighttpd is present and after all -# the packages are upgraded -require="$require __package/lighttpd" __package munin --state present + # Ensure that lighttpd is installed after we have upgraded all the packages + __package lighttpd --state present + # Ensure that munin is installed after lighttpd is present and after all + # the packages are upgraded + require="$require __package/lighttpd" __package munin --state present --------------------------------------------------------------------------------- All objects that are created in a type manifest are automatically required from the type that is calling them. This is called "autorequirement" in @@ -166,6 +156,7 @@ cdist jargon. You can find an more in depth description of the flow execution of manifests in cdist-stages(7) and of how types work in cdist-type(7). + CREATE DEPENDENCIES FROM EXECUTION ORDER ----------------------------------------- You can tell cdist to execute all types in the order in which they are created @@ -193,90 +184,85 @@ CDIST_ORDER_DEPENDENCY will be ignored, because adding a dependency in case of overrides would result in circular dependencies, which is an error. - - EXAMPLES -------- The initial manifest may for instance contain the following code: --------------------------------------------------------------------------------- -# Always create this file, so other sysadmins know cdist is used. -__file /etc/cdist-configured +.. code-block:: sh -case "$__target_host" in - my.server.name) - __directory /root/bin/ - __file /etc/issue.net --source "$__manifest/issue.net - ;; -esac --------------------------------------------------------------------------------- + # Always create this file, so other sysadmins know cdist is used. + __file /etc/cdist-configured + + case "$__target_host" in + my.server.name) + __directory /root/bin/ + __file /etc/issue.net --source "$__manifest/issue.net + ;; + esac The manifest of the type "nologin" may look like this: --------------------------------------------------------------------------------- -__file /etc/nologin --source "$__type/files/default.nologin" --------------------------------------------------------------------------------- +.. code-block:: sh + + __file /etc/nologin --source "$__type/files/default.nologin" This example makes use of dependencies: --------------------------------------------------------------------------------- -# Ensure that lighttpd is installed -__package lighttpd --state present -# Ensure that munin makes use of lighttpd instead of the default webserver -# package as decided by the package manager -require="__package/lighttpd" __package munin --state present --------------------------------------------------------------------------------- +.. code-block:: sh + + # Ensure that lighttpd is installed + __package lighttpd --state present + # Ensure that munin makes use of lighttpd instead of the default webserver + # package as decided by the package manager + require="__package/lighttpd" __package munin --state present How to override objects: --------------------------------------------------------------------------------- -# for example in the inital manifest +.. code-block:: sh -# create user account foobar with some hash for password -__user foobar --password 'some_fancy_hash' --home /home/foobarexample + # for example in the inital manifest -# ... many statements and includes in the manifest later ... -# somewhere in a conditionally sourced manifest -# (e.g. for example only sourced if a special application is on the target host) + # create user account foobar with some hash for password + __user foobar --password 'some_fancy_hash' --home /home/foobarexample -# this leads to an error ... -__user foobar --password 'some_other_hash' + # ... many statements and includes in the manifest later ... + # somewhere in a conditionally sourced manifest + # (e.g. for example only sourced if a special application is on the target host) -# this tells cdist, that you know that this is an override and should be accepted -CDIST_OVERRIDE=yes __user foobar --password 'some_other_hash' -# it's only an override, means the parameter --home is not touched -# and stays at the original value of /home/foobarexample --------------------------------------------------------------------------------- + # this leads to an error ... + __user foobar --password 'some_other_hash' + + # this tells cdist, that you know that this is an override and should be accepted + CDIST_OVERRIDE=yes __user foobar --password 'some_other_hash' + # it's only an override, means the parameter --home is not touched + # and stays at the original value of /home/foobarexample Dependencies defined by execution order work as following: --------------------------------------------------------------------------------- +.. code-block:: sh -# Tells cdist to execute all types in the order in which they are created ... -export CDIST_ORDER_DEPENDENCY=on -__sample_type 1 -require="__some_type_somewhere/id" __sample_type 2 -__example_type 23 -# Now this types are executed in the creation order until the variable is unset -unset CDIST_ORDER_DEPENDENCY -# all now following types cdist makes the order .. -__not_in_order_type 42 - -# how it works : -# this lines above are translated to: -__sample_type 1 -require="__some_type_somewhere/id __sample_type/1" __sample_type 2 -require="__sample_type/2" __example_type 23 -__not_in_order_type 42 - --------------------------------------------------------------------------------- + # Tells cdist to execute all types in the order in which they are created ... + export CDIST_ORDER_DEPENDENCY=on + __sample_type 1 + require="__some_type_somewhere/id" __sample_type 2 + __example_type 23 + # Now this types are executed in the creation order until the variable is unset + unset CDIST_ORDER_DEPENDENCY + # all now following types cdist makes the order .. + __not_in_order_type 42 + # how it works : + # this lines above are translated to: + __sample_type 1 + require="__some_type_somewhere/id __sample_type/1" __sample_type 2 + require="__sample_type/2" __example_type 23 + __not_in_order_type 42 SEE ALSO -------- -- cdist-tutorial(7) -- cdist-type(7) +- `cdist-tutorial(7) `_ +- `cdist-type(7) `_ COPYING diff --git a/docs/man/man7/cdist-messaging.rst b/docs/man/man7/cdist-messaging.rst new file mode 100644 index 00000000..6f29a363 --- /dev/null +++ b/docs/man/man7/cdist-messaging.rst @@ -0,0 +1,111 @@ +cdist-messaging(7) +================== +How the initial manifest and types can communication + +Nico Schottelius + +DESCRIPTION +----------- +cdist has a simple but powerful way of allowing communication between +the initial manifest and types as well as types and types. + +Whenever execution is passed from cdist to one of the +scripts described below, cdist generate 2 new temporary files +and exports the environment variables **__messages_in** and +**__messages_out** to point to them. + +Before handing over the control, the content of the global message +file is copied into the file referenced by **$__messages_in**. + +After cdist gained control back, the content of the file referenced +by **$__messages_out** is appended to the global message file. + +This way overwriting any of the two files by accident does not +interfere with other types. + +The order of execution is not defined unless you create dependencies +between the different objects (see cdist-manifest(7)) and thus you +can only react reliably on messages by objects that you depend on. + + +AVAILABILITY +------------ +Messaging is possible between all **local** scripts: + +- initial manifest +- type/manifest +- type/gencode-local +- type/gencode-remote + + +EXAMPLES +-------- +When you want to emit a message use: + +.. code-block:: sh + + echo "something" >> "$__messages_out" + +When you want to react on a message use: + +.. code-block:: sh + + if grep -q "^__your_type/object/id:something" "$__messages_in"; then + echo "I do something else" + fi + +Some real life examples: + +.. code-block:: sh + + # Reacting on changes from block for keepalive + if grep -q "^__block/keepalive-vrrp" "$__messages_in"; then + echo /etc/init.d/keepalived restart + fi + + # Reacting on changes of configuration files + if grep -q "^__file/etc/one" $__messages_in; then + echo 'for init in /etc/init.d/opennebula*; do $init restart; done' + fi + +Restart sshd on changes + +.. code-block:: sh + + os="$(cat "$__global/explorer/os")" + + case "$os" in + centos|redhat|suse) + restart="/etc/init.d/sshd restart" + ;; + debian|ubuntu) + restart="/etc/init.d/ssh restart" + ;; + *) + cat << eof >&2 + Unsupported os $os. + If you would like to have this type running on $os, + you can either develop the changes and send a pull + request or ask for a quote at www.ungleich.ch + eof + exit 1 + ;; + esac + + if grep -q "^__key_value/PermitRootLogin" "$__messages_in"; then + echo $restart + fi + + +SEE ALSO +-------- +- `cdist(1) <../man1/cdist.html>`_ +- `cdist-manifest(7) `_ +- `cdist-reference(7) `_ +- `cdist-type(7) `_ + + +COPYING +------- +Copyright \(C) 2013 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-messaging.text b/docs/man/man7/cdist-messaging.text deleted file mode 100644 index a6258564..00000000 --- a/docs/man/man7/cdist-messaging.text +++ /dev/null @@ -1,114 +0,0 @@ -cdist-messaging(7) -================== -Nico Schottelius - -NAME ----- -cdist-messaging - How the initial manifest and types can communication - - -DESCRIPTION ------------ -cdist has a simple but powerful way of allowing communication between -the initial manifest and types as well as types and types. - -Whenever execution is passed from cdist to one of the -scripts described below, cdist generate 2 new temporary files -and exports the environment variables __messages_in and -__messages_out to point to them. - -Before handing over the control, the content of the global message -file is copied into the file referenced by $__messages_in. - -After cdist gained control back, the content of the file referenced -by $__messages_out is appended to the global message file. - -This way overwriting any of the two files by accident does not -interfere with other types. - -The order of execution is not defined unless you create dependencies -between the different objects (see cdist-manifest(7)) and thus you -can only react reliably on messages by objects that you depend on. - - -AVAILABILITY ------------- -Messaging is possible between all **local** scripts: - -- initial manifest -- type/manifest -- type/gencode-local -- type/gencode-remote - - -EXAMPLES --------- -When you want to emit a message use: - --------------------------------------------------------------------------------- -echo "something" >> "$__messages_out" --------------------------------------------------------------------------------- - -When you want to react on a message use: - --------------------------------------------------------------------------------- -if grep -q "^__your_type/object/id:something" "$__messages_in"; then - echo "I do something else" -fi --------------------------------------------------------------------------------- - -Some real life examples: --------------------------------------------------------------------------------- -# Reacting on changes from block for keepalive -if grep -q "^__block/keepalive-vrrp" "$__messages_in"; then - echo /etc/init.d/keepalived restart -fi - -# Reacting on changes of configuration files -if grep -q "^__file/etc/one" $__messages_in; then - echo 'for init in /etc/init.d/opennebula*; do $init restart; done' -fi --------------------------------------------------------------------------------- - -Restart sshd on changes --------------------------------------------------------------------------------- -os="$(cat "$__global/explorer/os")" - -case "$os" in - centos|redhat|suse) - restart="/etc/init.d/sshd restart" - ;; - debian|ubuntu) - restart="/etc/init.d/ssh restart" - ;; - *) - cat << eof >&2 -Unsupported os $os. -If you would like to have this type running on $os, -you can either develop the changes and send a pull -request or ask for a quote at www.ungleich.ch -eof - exit 1 - ;; -esac - -if grep -q "^__key_value/PermitRootLogin" "$__messages_in"; then - echo $restart -fi --------------------------------------------------------------------------------- - - - - -SEE ALSO --------- -- cdist(1) -- cdist-manifest(7) -- cdist-reference(7) -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-quickstart.text b/docs/man/man7/cdist-quickstart.rst similarity index 50% rename from docs/man/man7/cdist-quickstart.text rename to docs/man/man7/cdist-quickstart.rst index 8b754650..d1186ffe 100644 --- a/docs/man/man7/cdist-quickstart.text +++ b/docs/man/man7/cdist-quickstart.rst @@ -1,13 +1,10 @@ cdist-quickstart(7) =================== +Jump in and enjoy cdist + Nico Schottelius -NAME ----- -cdist-quickstart - jump in and enjoy cdist - - INTRODUCTION ------------ This tutorial is aimed at people learning cdist and shows @@ -31,62 +28,55 @@ and usually logs into the **target host** as the **root** user. So you need to configure the **ssh server** of the target host to allow root logins: Edit the file **/etc/ssh/sshd_config** and add one of the following -lines: +lines:: --------------------------------------------------------------------------------- -# Allow login only via public key -PermitRootLogin without-password + # Allow login only via public key + PermitRootLogin without-password -# Allow login via password and public key -PermitRootLogin yes --------------------------------------------------------------------------------- + # Allow login via password and public key + PermitRootLogin yes As cdist uses ssh intensively, it is recommended to setup authentication -with public keys: +with public keys:: --------------------------------------------------------------------------------- -# Generate pubkey pair as a normal user -ssh-keygen + # Generate pubkey pair as a normal user + ssh-keygen -# Copy pubkey over to target host -ssh-copy-id root@localhost --------------------------------------------------------------------------------- + # Copy pubkey over to target host + ssh-copy-id root@localhost Have a look at ssh-agent(1) and ssh-add(1) on how to cache the password for -your public key. Usually it looks like this: +your public key. Usually it looks like this:: --------------------------------------------------------------------------------- -# Start agent and export variables -eval `ssh-agent` + # Start agent and export variables + eval `ssh-agent` -# Add keys (requires password for every identity file) -ssh-add --------------------------------------------------------------------------------- + # Add keys (requires password for every identity file) + ssh-add -At this point you should be able to ***ssh root@localhost*** without +At this point you should be able to **ssh root@localhost** without re-entering the password. If something failed until here, ensure that all steps went successfully and you have read and understood the documentation. As soon as you are able to login without password to localhost, we can use cdist to configure it. You can copy and paste the following -code into your shell to get started and configure localhost: --------------------------------------------------------------------------------- -# Get cdist -# Mirrors can be found on -# http://www.nico.schottelius.org/software/cdist/install/#index2h4 -git clone git://git.schottelius.org/cdist +code into your shell to get started and configure localhost:: -# Create manifest (maps configuration to host(s) -cd cdist -echo '__file /etc/cdist-configured' > cdist/conf/manifest/init + # Get cdist + # Mirrors can be found on + # http://www.nico.schottelius.org/software/cdist/install/#index2h4 + git clone git://git.schottelius.org/cdist -# Configure localhost in verbose mode -./bin/cdist config -v localhost + # Create manifest (maps configuration to host(s) + cd cdist + echo '__file /etc/cdist-configured' > cdist/conf/manifest/init -# Find out that cdist created /etc/cdist-configured -ls -l /etc/cdist-configured --------------------------------------------------------------------------------- + # Configure localhost in verbose mode + ./bin/cdist config -v localhost + + # Find out that cdist created /etc/cdist-configured + ls -l /etc/cdist-configured That's it, you've successfully used cdist to configure your first host! Continue reading the next sections, to understand what you did and how @@ -95,8 +85,8 @@ to create a more sophisticated configuration. SEE ALSO -------- -- cdist(1) -- cdist-tutorial(7) +- `cdist(1) <../man1/cdist.html>`_ +- `cdist-tutorial(7) `_ COPYING diff --git a/docs/man/man7/cdist-reference.rst b/docs/man/man7/cdist-reference.rst new file mode 100644 index 00000000..bef0e452 --- /dev/null +++ b/docs/man/man7/cdist-reference.rst @@ -0,0 +1,313 @@ +cdist-reference(7) +================== +Variable, path and type reference for cdist + +Nico Schottelius + + +EXPLORERS +--------- +The following global explorers are available: + +- cpu_cores +- cpu_sockets +- hostname +- init +- interfaces +- lsb_codename +- lsb_description +- lsb_id +- lsb_release +- machine +- machine_type +- memory +- os +- os_version +- runlevel + +PATHS +----- +$HOME/.cdist + The standard cdist configuration directory relative to your home directory + This is usually the place you want to store your site specific configuration + +cdist/conf/ + The distribution configuration directory + This contains types and explorers to be used + +confdir + Cdist will use all available configuration directories and create + a temporary confdir containing links to the real configuration directories. + This way it is possible to merge configuration directories. + By default it consists of everything in $HOME/.cdist and cdist/conf/. + For more details see cdist(1) + +confdir/manifest/init + This is the central entry point. + It is an executable (+x bit set) shell script that can use + values from the explorers to decide which configuration to create + for the specified target host. + Its intent is to used to define mapping from configurations to hosts. + +confdir/manifest/* + All other files in this directory are not directly used by cdist, but you + can separate configuration mappings, if you have a lot of code in the + conf/manifest/init file. This may also be helpful to have different admins + maintain different groups of hosts. + +confdir/explorer/ + Contains explorers to be run on the target hosts, see cdist-explorer(7). + +confdir/type/ + Contains all available types, which are used to provide + some kind of functionality. See cdist-type(7). + +confdir/type// + Home of the type . + This directory is referenced by the variable __type (see below). + +confdir/type//man.rst + Manpage in reStructuredText format (required for inclusion into upstream) + +confdir/type//manifest + Used to generate additional objects from a type. + +confdir/type//gencode-local + Used to generate code to be executed on the source host + +confdir/type//gencode-remote + Used to generate code to be executed on the target host + +confdir/type//parameter/required + Parameters required by type, \n separated list. + +confdir/type//parameter/optional + Parameters optionally accepted by type, \n separated list. + +confdir/type//parameter/default/* + Default values for optional parameters. + Assuming an optional parameter name of 'foo', it's default value would + be read from the file confdir/type//parameter/default/foo. + +confdir/type//parameter/boolean + Boolean parameters accepted by type, \n separated list. + +confdir/type//explorer + Location of the type specific explorers. + This directory is referenced by the variable __type_explorer (see below). + See cdist-explorer(7). + +confdir/type//files + This directory is reserved for user data and will not be used + by cdist at any time. It can be used for storing supplementary + files (like scripts to act as a template or configuration files). + +out/ + This directory contains output of cdist and is usually located + in a temporary directory and thus will be removed after the run. + This directory is referenced by the variable __global (see below). + +out/explorer + Output of general explorers. + +out/object + Objects created for the host. + +out/object/ + Contains all object specific information. + This directory is referenced by the variable __object (see below). + +out/object//explorers + Output of type specific explorers, per object. + +TYPES +----- +The following types are available: + +- \__apt_key (`cdist-type__apt_key(7) `_) +- \__apt_key_uri (`cdist-type__apt_key_uri(7) `_) +- \__apt_norecommends (`cdist-type__apt_norecommends(7) `_) +- \__apt_ppa (`cdist-type__apt_ppa(7) `_) +- \__apt_source (`cdist-type__apt_source(7) `_) +- \__apt_update_index (`cdist-type__apt_update_index(7) `_) +- \__block (`cdist-type__block(7) `_) +- \__ccollect_source (`cdist-type__ccollect_source(7) `_) +- \__cdist (`cdist-type__cdist(7) `_) +- \__cdistmarker (`cdist-type__cdistmarker(7) `_) +- \__config_file (`cdist-type__config_file(7) `_) +- \__consul (`cdist-type__consul(7) `_) +- \__consul_agent (`cdist-type__consul_agent(7) `_) +- \__consul_check (`cdist-type__consul_check(7) `_) +- \__consul_reload (`cdist-type__consul_reload(7) `_) +- \__consul_service (`cdist-type__consul_service(7) `_) +- \__consul_template (`cdist-type__consul_template(7) `_) +- \__consul_template_template (`cdist-type__consul_template_template(7) `_) +- \__consul_watch_checks (`cdist-type__consul_watch_checks(7) `_) +- \__consul_watch_event (`cdist-type__consul_watch_event(7) `_) +- \__consul_watch_key (`cdist-type__consul_watch_key(7) `_) +- \__consul_watch_keyprefix (`cdist-type__consul_watch_keyprefix(7) `_) +- \__consul_watch_nodes (`cdist-type__consul_watch_nodes(7) `_) +- \__consul_watch_service (`cdist-type__consul_watch_service(7) `_) +- \__consul_watch_services (`cdist-type__consul_watch_services(7) `_) +- \__cron (`cdist-type__cron(7) `_) +- \__debconf_set_selections (`cdist-type__debconf_set_selections(7) `_) +- \__directory (`cdist-type__directory(7) `_) +- \__dog_vdi (`cdist-type__dog_vdi(7) `_) +- \__file (`cdist-type__file(7) `_) +- \__firewalld_rule (`cdist-type__firewalld_rule(7) `_) +- \__git (`cdist-type__git(7) `_) +- \__group (`cdist-type__group(7) `_) +- \__hostname (`cdist-type__hostname(7) `_) +- \__iptables_apply (`cdist-type__iptables_apply(7) `_) +- \__iptables_rule (`cdist-type__iptables_rule(7) `_) +- \__issue (`cdist-type__issue(7) `_) +- \__jail (`cdist-type__jail(7) `_) +- \__key_value (`cdist-type__key_value(7) `_) +- \__line (`cdist-type__line(7) `_) +- \__link (`cdist-type__link(7) `_) +- \__locale (`cdist-type__locale(7) `_) +- \__motd (`cdist-type__motd(7) `_) +- \__mount (`cdist-type__mount(7) `_) +- \__mysql_database (`cdist-type__mysql_database(7) `_) +- \__package (`cdist-type__package(7) `_) +- \__package_apt (`cdist-type__package_apt(7) `_) +- \__package_emerge (`cdist-type__package_emerge(7) `_) +- \__package_emerge_dependencies (`cdist-type__package_emerge_dependencies(7) `_) +- \__package_luarocks (`cdist-type__package_luarocks(7) `_) +- \__package_opkg (`cdist-type__package_opkg(7) `_) +- \__package_pacman (`cdist-type__package_pacman(7) `_) +- \__package_pip (`cdist-type__package_pip(7) `_) +- \__package_pkg_freebsd (`cdist-type__package_pkg_freebsd(7) `_) +- \__package_pkg_openbsd (`cdist-type__package_pkg_openbsd(7) `_) +- \__package_pkgng_freebsd (`cdist-type__package_pkgng_freebsd(7) `_) +- \__package_rubygem (`cdist-type__package_rubygem(7) `_) +- \__package_update_index (`cdist-type__package_update_index(7) `_) +- \__package_upgrade_all (`cdist-type__package_upgrade_all(7) `_) +- \__package_yum (`cdist-type__package_yum(7) `_) +- \__package_zypper (`cdist-type__package_zypper(7) `_) +- \__pacman_conf (`cdist-type__pacman_conf(7) `_) +- \__pacman_conf_integrate (`cdist-type__pacman_conf_integrate(7) `_) +- \__pf_apply (`cdist-type__pf_apply(7) `_) +- \__pf_ruleset (`cdist-type__pf_ruleset(7) `_) +- \__postfix (`cdist-type__postfix(7) `_) +- \__postfix_master (`cdist-type__postfix_master(7) `_) +- \__postfix_postconf (`cdist-type__postfix_postconf(7) `_) +- \__postfix_postmap (`cdist-type__postfix_postmap(7) `_) +- \__postfix_reload (`cdist-type__postfix_reload(7) `_) +- \__postgres_database (`cdist-type__postgres_database(7) `_) +- \__postgres_role (`cdist-type__postgres_role(7) `_) +- \__process (`cdist-type__process(7) `_) +- \__pyvenv (`cdist-type__pyvenv(7) `_) +- \__qemu_img (`cdist-type__qemu_img(7) `_) +- \__rbenv (`cdist-type__rbenv(7) `_) +- \__rsync (`cdist-type__rsync(7) `_) +- \__rvm (`cdist-type__rvm(7) `_) +- \__rvm_gem (`cdist-type__rvm_gem(7) `_) +- \__rvm_gemset (`cdist-type__rvm_gemset(7) `_) +- \__rvm_ruby (`cdist-type__rvm_ruby(7) `_) +- \__ssh_authorized_key (`cdist-type__ssh_authorized_key(7) `_) +- \__ssh_authorized_keys (`cdist-type__ssh_authorized_keys(7) `_) +- \__ssh_dot_ssh (`cdist-type__ssh_dot_ssh(7) `_) +- \__staged_file (`cdist-type__staged_file(7) `_) +- \__start_on_boot (`cdist-type__start_on_boot(7) `_) +- \__timezone (`cdist-type__timezone(7) `_) +- \__update_alternatives (`cdist-type__update_alternatives(7) `_) +- \__user (`cdist-type__user(7) `_) +- \__user_groups (`cdist-type__user_groups(7) `_) +- \__yum_repo (`cdist-type__yum_repo(7) `_) +- \__zypper_repo (`cdist-type__zypper_repo(7) `_) +- \__zypper_service (`cdist-type__zypper_service(7) `_) + + +OBJECTS +------- +For object to object communication and tests, the following paths are +usable within a object directory: + +files + This directory is reserved for user data and will not be used + by cdist at any time. It can be used freely by the type + (for instance to store template results). +changed + This empty file exists in an object directory, if the object has + code to be executed (either remote or local) +stdin + This file exists and contains data, if data was provided on stdin + when the type was called. + + +ENVIRONMENT VARIABLES (FOR READING) +----------------------------------- +The following environment variables are exported by cdist: + +__explorer + Directory that contains all global explorers. + Available for: initial manifest, explorer, type explorer, shell +__manifest + Directory that contains the initial manifest. + Available for: initial manifest, type manifest, shell +__global + Directory that contains generic output like explorer. + Available for: initial manifest, type manifest, type gencode, shell +__messages_in + File to read messages from. + Available for: initial manifest, type manifest, type gencode +__messages_out + File to write messages. + Available for: initial manifest, type manifest, type gencode +__object + Directory that contains the current object. + Available for: type manifest, type explorer, type gencode and code scripts +__object_id + The type unique object id. + Available for: type manifest, type explorer, type gencode and code scripts + Note: The leading and the trailing "/" will always be stripped (caused by + the filesystem database and ensured by the core). + Note: Double slashes ("//") will not be fixed and result in an error. +__object_name + The full qualified name of the current object. + Available for: type manifest, type explorer, type gencode +__target_host + The host we are deploying to. + Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell +__type + Path to the current type. + Available for: type manifest, type gencode +__type_explorer + Directory that contains the type explorers. + Available for: type explorer + +ENVIRONMENT VARIABLES (FOR WRITING) +----------------------------------- +The following environment variables influence the behaviour of cdist: + +require + Setup dependencies between objects (see cdist-manifest(7)) + +CDIST_LOCAL_SHELL + Use this shell locally instead of /bin/sh to execute scripts + +CDIST_REMOTE_SHELL + Use this shell remotely instead of /bin/sh to execute scripts + +CDIST_OVERRIDE + Allow overwriting type parameters (see cdist-manifest(7)) + +CDIST_ORDER_DEPENDENCY + Create dependencies based on the execution order (see cdist-manifest(7)) + +CDIST_REMOTE_EXEC + Use this command for remote execution (should behave like ssh) + +CDIST_REMOTE_COPY + Use this command for remote copy (should behave like scp) + +SEE ALSO +-------- +- `cdist(1) <../man1/cdist.html>`_ + + +COPYING +------- +Copyright \(C) 2011-2014 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-remote-exec-copy.text b/docs/man/man7/cdist-remote-exec-copy.rst similarity index 84% rename from docs/man/man7/cdist-remote-exec-copy.text rename to docs/man/man7/cdist-remote-exec-copy.rst index 298891d6..27b78d42 100644 --- a/docs/man/man7/cdist-remote-exec-copy.text +++ b/docs/man/man7/cdist-remote-exec-copy.rst @@ -1,23 +1,22 @@ cdist-remote-exec-copy(7) ========================= +How to use remote exec and copy + Nico Schottelius -NAME ----- -cdist-remote-exec-copy - How to use remote exec and copy - - INTRO ----- Cdist interacts with the target host in two ways: + - it executes code (__remote_exec) - and it copies files (__remote_copy) By default this is accomplished with ssh and scp respectively. -The default implementations used by cdist are: -__remote_exec: ssh -o User=root -q -__remote_copy: scp -o User=root -q +The default implementations used by cdist are:: + + __remote_exec: ssh -o User=root -q + __remote_copy: scp -o User=root -q The user can override these defaults by providing custom implementations and passing them to cdist with the --remote-exec and/or --remote-copy arguments. @@ -37,7 +36,7 @@ See cdist/other/examples/remote/ for some example implementations. SEE ALSO -------- -- cdist(7) +- `cdist(1) <../man1/cdist.html>`_ COPYING diff --git a/docs/man/man7/cdist-stages.text b/docs/man/man7/cdist-stages.rst similarity index 95% rename from docs/man/man7/cdist-stages.text rename to docs/man/man7/cdist-stages.rst index 5f2d2e4c..4b29585d 100644 --- a/docs/man/man7/cdist-stages.text +++ b/docs/man/man7/cdist-stages.rst @@ -1,12 +1,9 @@ cdist-stages(7) =============== +Stages used during configuration deployment + Nico Schottelius -NAME ----- -cdist-stages - Stages used during configuration deployment - - DESCRIPTION ----------- Starting the execution of deployment with cdist, cdist passes @@ -79,8 +76,8 @@ will be applied to the target. SEE ALSO -------- -- cdist(1) -- cdist-reference(7) +- `cdist(1) <../man1/cdist.html>`_ +- `cdist-reference(7) `_ COPYING diff --git a/docs/man/man7/cdist-troubleshooting.text b/docs/man/man7/cdist-troubleshooting.rst similarity index 52% rename from docs/man/man7/cdist-troubleshooting.text rename to docs/man/man7/cdist-troubleshooting.rst index 7c5e7612..075c3480 100644 --- a/docs/man/man7/cdist-troubleshooting.text +++ b/docs/man/man7/cdist-troubleshooting.rst @@ -1,28 +1,25 @@ cdist-troubleshooting(7) ======================== +Common problems and their solutions + Nico Schottelius -NAME ----- -cdist-troubleshooting - common problems and their solutions - - ERROR IN MANIFEST IS NOT CONSIDERED AN ERROR BY CDIST ----------------------------------------------------- Situation: You are executing other scripts from a manifest. This script fails, but cdist does not recognise the error. An example script would be something like this: --------------------------------------------------------------------------------- -% cat ~/.cdist/manifest/init -"$__manifest/special" -% cat ~/.cdist/manifest/special -#!/bin/sh -echo "Here is an unclean exiting script" -somecommandthatdoesnotexist -echo "I continue here although previous command failed" --------------------------------------------------------------------------------- +.. code-block:: sh + + % cat ~/.cdist/manifest/init + "$__manifest/special" + % cat ~/.cdist/manifest/special + #!/bin/sh + echo "Here is an unclean exiting script" + somecommandthatdoesnotexist + echo "I continue here although previous command failed" We can clearly see that **somecommandthatdoesnotexist** will fail in ~/.cdist/manifest/special. But as the custom @@ -33,28 +30,29 @@ code of the last echo line instead of the failing command. All scripts executed by cdist carry the -e flag. To prevent the above from happening, there are three solutions available, two of which can be used in the calling script: --------------------------------------------------------------------------------- -# Execute as before, but abort on failure -sh -e "$__manifest/special" -# Source the script in our namespace, runs in a set -e environment: -. "$__manifest/special" --------------------------------------------------------------------------------- +.. code-block:: sh + + # Execute as before, but abort on failure + sh -e "$__manifest/special" + + # Source the script in our namespace, runs in a set -e environment: + . "$__manifest/special" The third solution is to include a shebang header in every script you write to use the -e flag: --------------------------------------------------------------------------------- -% cat ~/.cdist/manifest/special -#!/bin/sh -e -... --------------------------------------------------------------------------------- +.. code-block:: sh + + % cat ~/.cdist/manifest/special + #!/bin/sh -e + ... SEE ALSO -------- -- cdist(1) -- cdist-tutorial(7) +- `cdist(1) <../man1/cdist.html>`_ +- `cdist-tutorial(7) `_ COPYING diff --git a/docs/man/man7/cdist-tutorial.text b/docs/man/man7/cdist-tutorial.rst similarity index 78% rename from docs/man/man7/cdist-tutorial.text rename to docs/man/man7/cdist-tutorial.rst index 85419025..4899dcb0 100644 --- a/docs/man/man7/cdist-tutorial.text +++ b/docs/man/man7/cdist-tutorial.rst @@ -1,13 +1,10 @@ cdist-tutorial(7) ================= +A guided introduction into cdist + Nico Schottelius -NAME ----- -cdist-tutorial - a guided introduction into cdist - - INTRODUCTION ------------ This document gives you a pointer on what to read in @@ -16,40 +13,40 @@ So in case you are just starting, just "begin at the beginning" (Brave New World). You can see the target audience in [] brackets after the description. -cdist-quickstart:: +cdist-quickstart New to cdist? Want to get your hands dirty? Read this. [beginner] -cdist-bootstrap:: +cdist-bootstrap The comprehensive guide to your first cdist installation [beginner] -cdist-manifest:: +cdist-manifest Learn how to define which hosts get which configurations [beginner] -cdist-type:: +cdist-type Understand how types are working and created [intermediate] -cdist-best-practice:: +cdist-best-practice Hints from real life experience to help you to organise cdist [intermediate] -cdist-reference:: +cdist-reference The type, explorers and environment variables reference [intermediate] -cdist-explorer:: +cdist-explorer Interested in getting more information about the target system? [intermediate] -cdist-stages:: +cdist-stages Understand the internal workflow of cdist. [advanced] -cdist-hacker:: +cdist-hacker README, if you want to extend or modify cdist. [hacker] SEE ALSO -------- -- cdist(1) -- cdist-type(7) -- cdist-best-practice(7) -- cdist-stages(7) +- `cdist(1) <../man1/cdist.html>`_ +- `cdist-type(7) `_ +- `cdist-best-practice(7) `_ +- `cdist-stages(7) `_ - Brave New World by Aldous Huxley COPYING diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.rst similarity index 54% rename from docs/man/man7/cdist-type.text rename to docs/man/man7/cdist-type.rst index 71d04ab3..cfd331e1 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.rst @@ -1,18 +1,17 @@ cdist-type(7) ============= +Functionality bundled + Nico Schottelius -NAME ----- -cdist-type - Functionality bundled - - SYNOPSIS -------- -__TYPE ID --parameter value [--parameter value ...] -__TYPE --parameter value [--parameter value ...] (for singletons) +:: + + __TYPE ID --parameter value [--parameter value ...] + __TYPE --parameter value [--parameter value ...] (for singletons) DESCRIPTION @@ -27,13 +26,13 @@ HOW TO USE A TYPE You can use types from the initial manifest or the type manifest like a normal shell command: --------------------------------------------------------------------------------- -# Creates empty file /etc/cdist-configured -__file /etc/cdist-configured --type file +.. code-block:: sh -# Ensure tree is installed -__package tree --state installed --------------------------------------------------------------------------------- + # Creates empty file /etc/cdist-configured + __file /etc/cdist-configured --type file + + # Ensure tree is installed + __package tree --state installed A list of supported types can be found in the cdist-reference(7) manpage. @@ -44,14 +43,16 @@ If a type is flagged as a singleton, it may be used only once per host. This is useful for types which can be used only once on a system. Singleton types do not take an object name as argument. -Example: --------------------------------------------------------------------------------- -# __issue type manages /etc/issue -__issue -# Probably your own type - singletons may use parameters -__myfancysingleton --colour green --------------------------------------------------------------------------------- +Example: + +.. code-block:: sh + + # __issue type manages /etc/issue + __issue + + # Probably your own type - singletons may use parameters + __myfancysingleton --colour green HOW TO WRITE A NEW TYPE @@ -73,9 +74,9 @@ To implement a new type, create the directory **cdist/conf/type/__NAME**. DEFINING PARAMETERS ------------------- Every type consists of required, optional and boolean parameters, which must -each be declared in a newline separated file in ***parameter/required***, -***parameter/required_multiple***, ***parameter/optional***, -***parameter/optional_multiple*** and ***parameter/boolean***. +each be declared in a newline separated file in **parameter/required**, +**parameter/required_multiple**, **parameter/optional**, +**parameter/optional_multiple** and **parameter/boolean**. Parameters which are allowed multiple times should be listed in required_multiple or optional_multiple respectively. All other parameters follow the standard unix behaviour "the last given wins". @@ -83,18 +84,19 @@ If either is missing, the type will have no required, no optional, no boolean or no parameters at all. Default values for optional parameters can be predefined in -***parameter/default/***. +**parameter/default/**. Example: --------------------------------------------------------------------------------- -echo servername >> cdist/conf/type/__nginx_vhost/parameter/required -echo logdirectory >> cdist/conf/type/__nginx_vhost/parameter/optional -echo loglevel >> cdist/conf/type/__nginx_vhost/parameter/optional -mkdir cdist/conf/type/__nginx_vhost/parameter/default -echo warning > cdist/conf/type/__nginx_vhost/parameter/default/loglevel -echo server_alias >> cdist/conf/type/__nginx_vhost/parameter/optional_multiple -echo use_ssl >> cdist/conf/type/__nginx_vhost/parameter/boolean --------------------------------------------------------------------------------- + +.. code-block:: sh + + echo servername >> cdist/conf/type/__nginx_vhost/parameter/required + echo logdirectory >> cdist/conf/type/__nginx_vhost/parameter/optional + echo loglevel >> cdist/conf/type/__nginx_vhost/parameter/optional + mkdir cdist/conf/type/__nginx_vhost/parameter/default + echo warning > cdist/conf/type/__nginx_vhost/parameter/default/loglevel + echo server_alias >> cdist/conf/type/__nginx_vhost/parameter/optional_multiple + echo use_ssl >> cdist/conf/type/__nginx_vhost/parameter/boolean USING PARAMETERS @@ -105,60 +107,62 @@ represented by file existence. File exists -> True, file does not exist -> False Example: (e.g. in cdist/conf/type/__nginx_vhost/manifest) --------------------------------------------------------------------------------- -# required parameter -servername="$(cat "$__object/parameter/servername")" -# optional parameter -if [ -f "$__object/parameter/logdirectory" ]; then - logdirectory="$(cat "$__object/parameter/logdirectory")" -fi +.. code-block:: sh -# optional parameter with predefined default -loglevel="$(cat "$__object/parameter/loglevel")" + # required parameter + servername="$(cat "$__object/parameter/servername")" -# boolean parameter -if [ -f "$__object/parameter/use_ssl" ]; then - # file exists -> True - # do some fancy ssl stuff -fi + # optional parameter + if [ -f "$__object/parameter/logdirectory" ]; then + logdirectory="$(cat "$__object/parameter/logdirectory")" + fi -# parameter with multiple values -if [ -f "$__object/parameter/server_alias" ]; then - for alias in $(cat "$__object/parameter/server_alias"); do - echo $alias > /some/where/usefull - done -fi + # optional parameter with predefined default + loglevel="$(cat "$__object/parameter/loglevel")" --------------------------------------------------------------------------------- + # boolean parameter + if [ -f "$__object/parameter/use_ssl" ]; then + # file exists -> True + # do some fancy ssl stuff + fi + + # parameter with multiple values + if [ -f "$__object/parameter/server_alias" ]; then + for alias in $(cat "$__object/parameter/server_alias"); do + echo $alias > /some/where/usefull + done + fi INPUT FROM STDIN ---------------- Every type can access what has been written on stdin when it has been called. -The result is saved into the ***stdin*** file in the object directory. +The result is saved into the **stdin** file in the object directory. Example use of a type: (e.g. in cdist/conf/type/__archlinux_hostname) --------------------------------------------------------------------------------- -__file /etc/rc.conf --source - << eof -... -HOSTNAME="$__target_host" -... -eof --------------------------------------------------------------------------------- + +.. code-block:: sh + + __file /etc/rc.conf --source - << eof + ... + HOSTNAME="$__target_host" + ... + eof + If you have not seen this syntax (<< eof) before, it may help you to read about "here documents". In the __file type, stdin is used as source for the file, if - is used for source: --------------------------------------------------------------------------------- +.. code-block:: sh + if [ -f "$__object/parameter/source" ]; then source="$(cat "$__object/parameter/source")" if [ "$source" = "-" ]; then source="$__object/stdin" fi .... --------------------------------------------------------------------------------- WRITING THE MANIFEST @@ -167,20 +171,20 @@ In the manifest of a type you can use other types, so your type extends their functionality. A good example is the __package type, which in a shortened version looks like this: --------------------------------------------------------------------------------- -os="$(cat "$__global/explorer/os")" -case "$os" in - archlinux) type="pacman" ;; - debian|ubuntu) type="apt" ;; - gentoo) type="emerge" ;; - *) - echo "Don't know how to manage packages on: $os" >&2 - exit 1 - ;; -esac +.. code-block:: sh -__package_$type "$@" --------------------------------------------------------------------------------- + os="$(cat "$__global/explorer/os")" + case "$os" in + archlinux) type="pacman" ;; + debian|ubuntu) type="apt" ;; + gentoo) type="emerge" ;; + *) + echo "Don't know how to manage packages on: $os" >&2 + exit 1 + ;; + esac + + __package_$type "$@" As you can see, the type can reference different environment variables, which are documented in cdist-reference(7). @@ -195,15 +199,15 @@ If you want to ensure that a type can only be used once per target, you can mark it as a singleton: Just create the (empty) file "singleton" in your type directory: --------------------------------------------------------------------------------- -touch cdist/conf/type/__NAME/singleton --------------------------------------------------------------------------------- +.. code-block:: sh + + touch cdist/conf/type/__NAME/singleton This will also change the way your type must be called: --------------------------------------------------------------------------------- -__YOURTYPE --parameter value --------------------------------------------------------------------------------- +.. code-block:: sh + + __YOURTYPE --parameter value As you can see, the object ID is omitted, because it does not make any sense, if your type can be used only once. @@ -218,22 +222,22 @@ The explorers are stored under the "explorer" directory below the type. It could for instance contain code to check the md5sum of a file on the client, like this (shortened version from the type __file): --------------------------------------------------------------------------------- -if [ -f "$__object/parameter/destination" ]; then - destination="$(cat "$__object/parameter/destination")" -else - destination="/$__object_id" -fi +.. code-block:: sh -if [ -e "$destination" ]; then - md5sum < "$destination" -fi --------------------------------------------------------------------------------- + if [ -f "$__object/parameter/destination" ]; then + destination="$(cat "$__object/parameter/destination")" + else + destination="/$__object_id" + fi + + if [ -e "$destination" ]; then + md5sum < "$destination" + fi WRITING THE GENCODE SCRIPT -------------------------- -There are two gencode scripts: ***gencode-local*** and ***gencode-remote***. +There are two gencode scripts: **gencode-local** and **gencode-remote**. The output of gencode-local is executed locally, whereas the output of gencode-remote is executed on the target. The gencode scripts can make use of the parameters, the global explorers @@ -243,13 +247,13 @@ If the gencode scripts encounters an error, it should print diagnostic messages to stderr and exit non-zero. If you need to debug the gencode script, you can write to stderr: --------------------------------------------------------------------------------- -# Debug output to stderr -echo "My fancy debug line" >&2 +.. code-block:: sh -# Output to be saved by cdist for execution on the target -echo "touch /etc/cdist-configured" --------------------------------------------------------------------------------- + # Debug output to stderr + echo "My fancy debug line" >&2 + + # Output to be saved by cdist for execution on the target + echo "touch /etc/cdist-configured" VARIABLE ACCESS FROM THE GENERATED SCRIPTS @@ -264,13 +268,13 @@ files after the script execution. So when you generate a script with the following content, it will work: --------------------------------------------------------------------------------- -if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" -else - name="$__object_id" -fi --------------------------------------------------------------------------------- +.. code-block:: sh + + if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" + else + name="$__object_id" + fi HINTS FOR TYPEWRITERS @@ -298,10 +302,10 @@ how to submit it. SEE ALSO -------- -- cdist-explorer(7) -- cdist-hacker(7) -- cdist-stages(7) -- cdist-tutorial(7) +- `cdist-explorer(7) `_ +- `cdist-hacker(7) `_ +- `cdist-stages(7) `_ +- `cdist-tutorial(7) `_ COPYING diff --git a/docs/man/man7/cdist-type__apt_key.rst b/docs/man/man7/cdist-type__apt_key.rst new file mode 120000 index 00000000..12d532ee --- /dev/null +++ b/docs/man/man7/cdist-type__apt_key.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__apt_key/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_key_uri.rst b/docs/man/man7/cdist-type__apt_key_uri.rst new file mode 120000 index 00000000..e90fda00 --- /dev/null +++ b/docs/man/man7/cdist-type__apt_key_uri.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__apt_key_uri/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_norecommends.rst b/docs/man/man7/cdist-type__apt_norecommends.rst new file mode 120000 index 00000000..2ce4bdea --- /dev/null +++ b/docs/man/man7/cdist-type__apt_norecommends.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__apt_norecommends/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_ppa.rst b/docs/man/man7/cdist-type__apt_ppa.rst new file mode 120000 index 00000000..efdc1de2 --- /dev/null +++ b/docs/man/man7/cdist-type__apt_ppa.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__apt_ppa/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_source.rst b/docs/man/man7/cdist-type__apt_source.rst new file mode 120000 index 00000000..2d2c77b7 --- /dev/null +++ b/docs/man/man7/cdist-type__apt_source.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__apt_source/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_update_index.rst b/docs/man/man7/cdist-type__apt_update_index.rst new file mode 120000 index 00000000..f2ee88e7 --- /dev/null +++ b/docs/man/man7/cdist-type__apt_update_index.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__apt_update_index/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__block.rst b/docs/man/man7/cdist-type__block.rst new file mode 120000 index 00000000..74d8e18f --- /dev/null +++ b/docs/man/man7/cdist-type__block.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__block/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__ccollect_source.rst b/docs/man/man7/cdist-type__ccollect_source.rst new file mode 120000 index 00000000..8398eb0f --- /dev/null +++ b/docs/man/man7/cdist-type__ccollect_source.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__ccollect_source/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__cdist.rst b/docs/man/man7/cdist-type__cdist.rst new file mode 120000 index 00000000..483afed8 --- /dev/null +++ b/docs/man/man7/cdist-type__cdist.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__cdist/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__cdistmarker.rst b/docs/man/man7/cdist-type__cdistmarker.rst new file mode 120000 index 00000000..3b4db6a6 --- /dev/null +++ b/docs/man/man7/cdist-type__cdistmarker.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__cdistmarker/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__config_file.rst b/docs/man/man7/cdist-type__config_file.rst new file mode 120000 index 00000000..714be1a6 --- /dev/null +++ b/docs/man/man7/cdist-type__config_file.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__config_file/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul.rst b/docs/man/man7/cdist-type__consul.rst new file mode 120000 index 00000000..5548772f --- /dev/null +++ b/docs/man/man7/cdist-type__consul.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_agent.rst b/docs/man/man7/cdist-type__consul_agent.rst new file mode 120000 index 00000000..89101b6e --- /dev/null +++ b/docs/man/man7/cdist-type__consul_agent.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_agent/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_check.rst b/docs/man/man7/cdist-type__consul_check.rst new file mode 120000 index 00000000..767cfc78 --- /dev/null +++ b/docs/man/man7/cdist-type__consul_check.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_check/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_reload.rst b/docs/man/man7/cdist-type__consul_reload.rst new file mode 120000 index 00000000..9344d259 --- /dev/null +++ b/docs/man/man7/cdist-type__consul_reload.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_reload/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_service.rst b/docs/man/man7/cdist-type__consul_service.rst new file mode 120000 index 00000000..697b6de7 --- /dev/null +++ b/docs/man/man7/cdist-type__consul_service.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_service/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_template.rst b/docs/man/man7/cdist-type__consul_template.rst new file mode 120000 index 00000000..73cb7f66 --- /dev/null +++ b/docs/man/man7/cdist-type__consul_template.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_template/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_template_template.rst b/docs/man/man7/cdist-type__consul_template_template.rst new file mode 120000 index 00000000..ea2fa00e --- /dev/null +++ b/docs/man/man7/cdist-type__consul_template_template.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_template_template/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_checks.rst b/docs/man/man7/cdist-type__consul_watch_checks.rst new file mode 120000 index 00000000..241f2c86 --- /dev/null +++ b/docs/man/man7/cdist-type__consul_watch_checks.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_watch_checks/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_event.rst b/docs/man/man7/cdist-type__consul_watch_event.rst new file mode 120000 index 00000000..710f69bb --- /dev/null +++ b/docs/man/man7/cdist-type__consul_watch_event.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_watch_event/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_key.rst b/docs/man/man7/cdist-type__consul_watch_key.rst new file mode 120000 index 00000000..d3987862 --- /dev/null +++ b/docs/man/man7/cdist-type__consul_watch_key.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_watch_key/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_keyprefix.rst b/docs/man/man7/cdist-type__consul_watch_keyprefix.rst new file mode 120000 index 00000000..f5a58339 --- /dev/null +++ b/docs/man/man7/cdist-type__consul_watch_keyprefix.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_watch_keyprefix/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_nodes.rst b/docs/man/man7/cdist-type__consul_watch_nodes.rst new file mode 120000 index 00000000..20b29324 --- /dev/null +++ b/docs/man/man7/cdist-type__consul_watch_nodes.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_watch_nodes/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_service.rst b/docs/man/man7/cdist-type__consul_watch_service.rst new file mode 120000 index 00000000..0965c7ca --- /dev/null +++ b/docs/man/man7/cdist-type__consul_watch_service.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_watch_service/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_services.rst b/docs/man/man7/cdist-type__consul_watch_services.rst new file mode 120000 index 00000000..06610a8c --- /dev/null +++ b/docs/man/man7/cdist-type__consul_watch_services.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__consul_watch_services/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__cron.rst b/docs/man/man7/cdist-type__cron.rst new file mode 120000 index 00000000..783ef87d --- /dev/null +++ b/docs/man/man7/cdist-type__cron.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__cron/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__debconf_set_selections.rst b/docs/man/man7/cdist-type__debconf_set_selections.rst new file mode 120000 index 00000000..88c233ae --- /dev/null +++ b/docs/man/man7/cdist-type__debconf_set_selections.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__debconf_set_selections/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__directory.rst b/docs/man/man7/cdist-type__directory.rst new file mode 120000 index 00000000..8c25832f --- /dev/null +++ b/docs/man/man7/cdist-type__directory.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__directory/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__dog_vdi.rst b/docs/man/man7/cdist-type__dog_vdi.rst new file mode 120000 index 00000000..4ffbb2db --- /dev/null +++ b/docs/man/man7/cdist-type__dog_vdi.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__dog_vdi/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__file.rst b/docs/man/man7/cdist-type__file.rst new file mode 120000 index 00000000..60aa8b88 --- /dev/null +++ b/docs/man/man7/cdist-type__file.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__file/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__firewalld_rule.rst b/docs/man/man7/cdist-type__firewalld_rule.rst new file mode 120000 index 00000000..756b8d20 --- /dev/null +++ b/docs/man/man7/cdist-type__firewalld_rule.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__firewalld_rule/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__git.rst b/docs/man/man7/cdist-type__git.rst new file mode 120000 index 00000000..14057be3 --- /dev/null +++ b/docs/man/man7/cdist-type__git.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__git/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__group.rst b/docs/man/man7/cdist-type__group.rst new file mode 120000 index 00000000..a35a5779 --- /dev/null +++ b/docs/man/man7/cdist-type__group.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__group/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__hostname.rst b/docs/man/man7/cdist-type__hostname.rst new file mode 120000 index 00000000..46eaec8b --- /dev/null +++ b/docs/man/man7/cdist-type__hostname.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__hostname/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__iptables_apply.rst b/docs/man/man7/cdist-type__iptables_apply.rst new file mode 120000 index 00000000..cc4c25d7 --- /dev/null +++ b/docs/man/man7/cdist-type__iptables_apply.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__iptables_apply/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__iptables_rule.rst b/docs/man/man7/cdist-type__iptables_rule.rst new file mode 120000 index 00000000..4e5c50f4 --- /dev/null +++ b/docs/man/man7/cdist-type__iptables_rule.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__iptables_rule/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__issue.rst b/docs/man/man7/cdist-type__issue.rst new file mode 120000 index 00000000..9dad6d0d --- /dev/null +++ b/docs/man/man7/cdist-type__issue.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__issue/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__jail.rst b/docs/man/man7/cdist-type__jail.rst new file mode 120000 index 00000000..75ad8a18 --- /dev/null +++ b/docs/man/man7/cdist-type__jail.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__jail/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__key_value.rst b/docs/man/man7/cdist-type__key_value.rst new file mode 120000 index 00000000..0dd8b882 --- /dev/null +++ b/docs/man/man7/cdist-type__key_value.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__key_value/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__line.rst b/docs/man/man7/cdist-type__line.rst new file mode 120000 index 00000000..3d6b98d5 --- /dev/null +++ b/docs/man/man7/cdist-type__line.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__line/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__link.rst b/docs/man/man7/cdist-type__link.rst new file mode 120000 index 00000000..ecb21b4a --- /dev/null +++ b/docs/man/man7/cdist-type__link.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__link/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__locale.rst b/docs/man/man7/cdist-type__locale.rst new file mode 120000 index 00000000..b1506d28 --- /dev/null +++ b/docs/man/man7/cdist-type__locale.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__locale/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__motd.rst b/docs/man/man7/cdist-type__motd.rst new file mode 120000 index 00000000..300ad9bd --- /dev/null +++ b/docs/man/man7/cdist-type__motd.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__motd/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__mount.rst b/docs/man/man7/cdist-type__mount.rst new file mode 120000 index 00000000..e2ee3a56 --- /dev/null +++ b/docs/man/man7/cdist-type__mount.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__mount/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__mysql_database.rst b/docs/man/man7/cdist-type__mysql_database.rst new file mode 120000 index 00000000..3d0ebe5f --- /dev/null +++ b/docs/man/man7/cdist-type__mysql_database.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__mysql_database/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package.rst b/docs/man/man7/cdist-type__package.rst new file mode 120000 index 00000000..da9a827a --- /dev/null +++ b/docs/man/man7/cdist-type__package.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_apt.rst b/docs/man/man7/cdist-type__package_apt.rst new file mode 120000 index 00000000..c1c21110 --- /dev/null +++ b/docs/man/man7/cdist-type__package_apt.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_apt/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_emerge.rst b/docs/man/man7/cdist-type__package_emerge.rst new file mode 120000 index 00000000..33312455 --- /dev/null +++ b/docs/man/man7/cdist-type__package_emerge.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_emerge/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_emerge_dependencies.rst b/docs/man/man7/cdist-type__package_emerge_dependencies.rst new file mode 120000 index 00000000..785ccd97 --- /dev/null +++ b/docs/man/man7/cdist-type__package_emerge_dependencies.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_emerge_dependencies/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_luarocks.rst b/docs/man/man7/cdist-type__package_luarocks.rst new file mode 120000 index 00000000..e87cc0ee --- /dev/null +++ b/docs/man/man7/cdist-type__package_luarocks.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_luarocks/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_opkg.rst b/docs/man/man7/cdist-type__package_opkg.rst new file mode 120000 index 00000000..0ea6199b --- /dev/null +++ b/docs/man/man7/cdist-type__package_opkg.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_opkg/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pacman.rst b/docs/man/man7/cdist-type__package_pacman.rst new file mode 120000 index 00000000..30d0efd1 --- /dev/null +++ b/docs/man/man7/cdist-type__package_pacman.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_pacman/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pip.rst b/docs/man/man7/cdist-type__package_pip.rst new file mode 120000 index 00000000..1d8202ff --- /dev/null +++ b/docs/man/man7/cdist-type__package_pip.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_pip/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pkg_freebsd.rst b/docs/man/man7/cdist-type__package_pkg_freebsd.rst new file mode 120000 index 00000000..2fcbb36b --- /dev/null +++ b/docs/man/man7/cdist-type__package_pkg_freebsd.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_pkg_freebsd/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pkg_openbsd.rst b/docs/man/man7/cdist-type__package_pkg_openbsd.rst new file mode 120000 index 00000000..01676166 --- /dev/null +++ b/docs/man/man7/cdist-type__package_pkg_openbsd.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_pkg_openbsd/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pkgng_freebsd.rst b/docs/man/man7/cdist-type__package_pkgng_freebsd.rst new file mode 120000 index 00000000..2cac19eb --- /dev/null +++ b/docs/man/man7/cdist-type__package_pkgng_freebsd.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_pkgng_freebsd/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_rubygem.rst b/docs/man/man7/cdist-type__package_rubygem.rst new file mode 120000 index 00000000..e9b394fd --- /dev/null +++ b/docs/man/man7/cdist-type__package_rubygem.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_rubygem/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_update_index.rst b/docs/man/man7/cdist-type__package_update_index.rst new file mode 120000 index 00000000..1d4175a9 --- /dev/null +++ b/docs/man/man7/cdist-type__package_update_index.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_update_index/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_upgrade_all.rst b/docs/man/man7/cdist-type__package_upgrade_all.rst new file mode 120000 index 00000000..7fb535e2 --- /dev/null +++ b/docs/man/man7/cdist-type__package_upgrade_all.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_upgrade_all/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_yum.rst b/docs/man/man7/cdist-type__package_yum.rst new file mode 120000 index 00000000..eebce5b1 --- /dev/null +++ b/docs/man/man7/cdist-type__package_yum.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_yum/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_zypper.rst b/docs/man/man7/cdist-type__package_zypper.rst new file mode 120000 index 00000000..b35d0f25 --- /dev/null +++ b/docs/man/man7/cdist-type__package_zypper.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__package_zypper/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pacman_conf.rst b/docs/man/man7/cdist-type__pacman_conf.rst new file mode 120000 index 00000000..99901486 --- /dev/null +++ b/docs/man/man7/cdist-type__pacman_conf.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__pacman_conf/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pacman_conf_integrate.rst b/docs/man/man7/cdist-type__pacman_conf_integrate.rst new file mode 120000 index 00000000..298576dc --- /dev/null +++ b/docs/man/man7/cdist-type__pacman_conf_integrate.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__pacman_conf_integrate/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pf_apply.rst b/docs/man/man7/cdist-type__pf_apply.rst new file mode 120000 index 00000000..6897ffad --- /dev/null +++ b/docs/man/man7/cdist-type__pf_apply.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__pf_apply/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pf_ruleset.rst b/docs/man/man7/cdist-type__pf_ruleset.rst new file mode 120000 index 00000000..6f484a26 --- /dev/null +++ b/docs/man/man7/cdist-type__pf_ruleset.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__pf_ruleset/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix.rst b/docs/man/man7/cdist-type__postfix.rst new file mode 120000 index 00000000..43001302 --- /dev/null +++ b/docs/man/man7/cdist-type__postfix.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__postfix/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix_master.rst b/docs/man/man7/cdist-type__postfix_master.rst new file mode 120000 index 00000000..7e35f771 --- /dev/null +++ b/docs/man/man7/cdist-type__postfix_master.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__postfix_master/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix_postconf.rst b/docs/man/man7/cdist-type__postfix_postconf.rst new file mode 120000 index 00000000..2e66b0fc --- /dev/null +++ b/docs/man/man7/cdist-type__postfix_postconf.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__postfix_postconf/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix_postmap.rst b/docs/man/man7/cdist-type__postfix_postmap.rst new file mode 120000 index 00000000..5fab5328 --- /dev/null +++ b/docs/man/man7/cdist-type__postfix_postmap.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__postfix_postmap/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix_reload.rst b/docs/man/man7/cdist-type__postfix_reload.rst new file mode 120000 index 00000000..b60fc927 --- /dev/null +++ b/docs/man/man7/cdist-type__postfix_reload.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__postfix_reload/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postgres_database.rst b/docs/man/man7/cdist-type__postgres_database.rst new file mode 120000 index 00000000..22697ebb --- /dev/null +++ b/docs/man/man7/cdist-type__postgres_database.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__postgres_database/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postgres_role.rst b/docs/man/man7/cdist-type__postgres_role.rst new file mode 120000 index 00000000..ffd8cfc2 --- /dev/null +++ b/docs/man/man7/cdist-type__postgres_role.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__postgres_role/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__process.rst b/docs/man/man7/cdist-type__process.rst new file mode 120000 index 00000000..6385603a --- /dev/null +++ b/docs/man/man7/cdist-type__process.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__process/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pyvenv.rst b/docs/man/man7/cdist-type__pyvenv.rst new file mode 120000 index 00000000..b7fdf05e --- /dev/null +++ b/docs/man/man7/cdist-type__pyvenv.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__pyvenv/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__qemu_img.rst b/docs/man/man7/cdist-type__qemu_img.rst new file mode 120000 index 00000000..88797991 --- /dev/null +++ b/docs/man/man7/cdist-type__qemu_img.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__qemu_img/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rbenv.rst b/docs/man/man7/cdist-type__rbenv.rst new file mode 120000 index 00000000..6f990abf --- /dev/null +++ b/docs/man/man7/cdist-type__rbenv.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__rbenv/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rsync.rst b/docs/man/man7/cdist-type__rsync.rst new file mode 120000 index 00000000..c581bd7b --- /dev/null +++ b/docs/man/man7/cdist-type__rsync.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__rsync/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rvm.rst b/docs/man/man7/cdist-type__rvm.rst new file mode 120000 index 00000000..ad7c1fde --- /dev/null +++ b/docs/man/man7/cdist-type__rvm.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__rvm/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rvm_gem.rst b/docs/man/man7/cdist-type__rvm_gem.rst new file mode 120000 index 00000000..fd1c83c1 --- /dev/null +++ b/docs/man/man7/cdist-type__rvm_gem.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__rvm_gem/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rvm_gemset.rst b/docs/man/man7/cdist-type__rvm_gemset.rst new file mode 120000 index 00000000..49da138a --- /dev/null +++ b/docs/man/man7/cdist-type__rvm_gemset.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__rvm_gemset/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rvm_ruby.rst b/docs/man/man7/cdist-type__rvm_ruby.rst new file mode 120000 index 00000000..48fec75d --- /dev/null +++ b/docs/man/man7/cdist-type__rvm_ruby.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__rvm_ruby/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__ssh_authorized_key.rst b/docs/man/man7/cdist-type__ssh_authorized_key.rst new file mode 120000 index 00000000..b82695cb --- /dev/null +++ b/docs/man/man7/cdist-type__ssh_authorized_key.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__ssh_authorized_key/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__ssh_authorized_keys.rst b/docs/man/man7/cdist-type__ssh_authorized_keys.rst new file mode 120000 index 00000000..71794a71 --- /dev/null +++ b/docs/man/man7/cdist-type__ssh_authorized_keys.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__ssh_authorized_keys/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__ssh_dot_ssh.rst b/docs/man/man7/cdist-type__ssh_dot_ssh.rst new file mode 120000 index 00000000..e88fc415 --- /dev/null +++ b/docs/man/man7/cdist-type__ssh_dot_ssh.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__ssh_dot_ssh/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__staged_file.rst b/docs/man/man7/cdist-type__staged_file.rst new file mode 120000 index 00000000..17e94c67 --- /dev/null +++ b/docs/man/man7/cdist-type__staged_file.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__staged_file/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__start_on_boot.rst b/docs/man/man7/cdist-type__start_on_boot.rst new file mode 120000 index 00000000..f0223931 --- /dev/null +++ b/docs/man/man7/cdist-type__start_on_boot.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__start_on_boot/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__timezone.rst b/docs/man/man7/cdist-type__timezone.rst new file mode 120000 index 00000000..fd6db767 --- /dev/null +++ b/docs/man/man7/cdist-type__timezone.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__timezone/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__update_alternatives.rst b/docs/man/man7/cdist-type__update_alternatives.rst new file mode 120000 index 00000000..6337c09d --- /dev/null +++ b/docs/man/man7/cdist-type__update_alternatives.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__update_alternatives/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__user.rst b/docs/man/man7/cdist-type__user.rst new file mode 120000 index 00000000..feea364d --- /dev/null +++ b/docs/man/man7/cdist-type__user.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__user/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__user_groups.rst b/docs/man/man7/cdist-type__user_groups.rst new file mode 120000 index 00000000..92de8259 --- /dev/null +++ b/docs/man/man7/cdist-type__user_groups.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__user_groups/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__yum_repo.rst b/docs/man/man7/cdist-type__yum_repo.rst new file mode 120000 index 00000000..213fc81e --- /dev/null +++ b/docs/man/man7/cdist-type__yum_repo.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__yum_repo/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__zypper_repo.rst b/docs/man/man7/cdist-type__zypper_repo.rst new file mode 120000 index 00000000..8e6e7d14 --- /dev/null +++ b/docs/man/man7/cdist-type__zypper_repo.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__zypper_repo/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__zypper_service.rst b/docs/man/man7/cdist-type__zypper_service.rst new file mode 120000 index 00000000..7b238e8f --- /dev/null +++ b/docs/man/man7/cdist-type__zypper_service.rst @@ -0,0 +1 @@ +../../../cdist/conf/type/__zypper_service/man.rst \ No newline at end of file diff --git a/other/archived_types/__autofs/man.text b/other/archived_types/__autofs/man.rst similarity index 65% rename from other/archived_types/__autofs/man.text rename to other/archived_types/__autofs/man.rst index 9b343309..4f02720e 100644 --- a/other/archived_types/__autofs/man.text +++ b/other/archived_types/__autofs/man.rst @@ -1,13 +1,10 @@ cdist-type__autofs(7) ===================== +Install and start autofs + Steven Armstrong -NAME ----- -cdist-type__autofs - install and start autofs - - DESCRIPTION ----------- This space intentionally left blank. @@ -26,14 +23,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__autofs --------------------------------------------------------------------------------- +.. code-block:: sh + + __autofs SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/other/archived_types/__autofs_map/man.text b/other/archived_types/__autofs_map/man.rst similarity index 62% rename from other/archived_types/__autofs_map/man.text rename to other/archived_types/__autofs_map/man.rst index 50ce2fa8..dfb79a27 100644 --- a/other/archived_types/__autofs_map/man.text +++ b/other/archived_types/__autofs_map/man.rst @@ -1,13 +1,10 @@ cdist-type__autofs_map(7) ========================= +Manage autofs maps + Steven Armstrong -NAME ----- -cdist-type__autofs_map - Manage autofs maps - - DESCRIPTION ----------- This cdist type allows you to define maps for autofs. @@ -20,48 +17,50 @@ The object_id is used as the mount-point as described in auto.master(5). REQUIRED PARAMETERS ------------------- -map:: +map Name of the map to use. See auto.master(5). OPTIONAL PARAMETERS ------------------- -type:: +type Type of map used for this mount point. Defaults to 'file'. See map-type in auto.master(5) for possible values. -options:: + +options See auto.master(5). -comment:: + +comment A comment describing this map. Is added to the generated entry in auto.master. BOOLEAN PARAMETERS ------------------ -noreload:: +noreload don't reload autofs after the entry has been changed EXAMPLES -------- --------------------------------------------------------------------------------- -# Add auto mounter at /net and reload -__autofs_map /net --map /etc/auto.net --type program +.. code-block:: sh -# Add auto mounter at /pub and don't reload -__autofs_map /pub \ - --map /etc/auto.pub \ - --type file \ - --options "nosuid,rw,bg,hard,intr --ghost" \ - --noreload --------------------------------------------------------------------------------- + # Add auto mounter at /net and reload + __autofs_map /net --map /etc/auto.net --type program + + # Add auto mounter at /pub and don't reload + __autofs_map /pub \ + --map /etc/auto.pub \ + --type file \ + --options "nosuid,rw,bg,hard,intr --ghost" \ + --noreload SEE ALSO -------- -- cdist-type(7) -- cdist-type__autofs_reload(7) +- `cdist-type(7) `_ +- `cdist-type__autofs_reload(7) `_ COPYING diff --git a/other/archived_types/__autofs_reload/man.text b/other/archived_types/__autofs_reload/man.rst similarity index 63% rename from other/archived_types/__autofs_reload/man.text rename to other/archived_types/__autofs_reload/man.rst index d2085a98..101e9965 100644 --- a/other/archived_types/__autofs_reload/man.text +++ b/other/archived_types/__autofs_reload/man.rst @@ -1,13 +1,10 @@ cdist-type__autofs_reload(7) ============================ +Tell automounter to reload config file + Steven Armstrong -NAME ----- -cdist-type__autofs_reload - tell automounter to reload config file - - DESCRIPTION ----------- This space intentionally left blank. @@ -26,14 +23,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__autofs_reload --------------------------------------------------------------------------------- +.. code-block:: sh + + __autofs_reload SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/other/types_submitted_for_inclusion/__init_script/man.text b/other/types_submitted_for_inclusion/__init_script/man.rst similarity index 63% rename from other/types_submitted_for_inclusion/__init_script/man.text rename to other/types_submitted_for_inclusion/__init_script/man.rst index c33ff7b7..9d9220d4 100644 --- a/other/types_submitted_for_inclusion/__init_script/man.text +++ b/other/types_submitted_for_inclusion/__init_script/man.rst @@ -1,13 +1,10 @@ cdist-type__init_script(7) ========================== +Use the init scripts + Daniel Roth -NAME ----- -cdist-type__init_script - Use the init scripts - - DESCRIPTION ----------- This type can be used to control your init scripts. @@ -15,34 +12,35 @@ This type can be used to control your init scripts. REQUIRED PARAMETERS ------------------- -mode:: +mode Specifies what shall be done with the init script (usually one of 'start'|'stop'|'restart'|'reload' or 'force-reload') OPTIONAL PARAMETERS ------------------- -script:: +script If supplied, use this as the init-script. Otherwise the object_id is used. -base_dir:: +base_dir If supplied, this type uses this directory instead of '/etc/init.d'. The parameter will not need an ending slash. + EXAMPLES -------- --------------------------------------------------------------------------------- -# Reloads the configuration for lighttpd -__init_script lighttpd --mode force-reload +.. code-block:: sh -# Reloads the configuration for lighttpd -__init_script lighty --script lighttpd --mode force-reload --------------------------------------------------------------------------------- + # Reloads the configuration for lighttpd + __init_script lighttpd --mode force-reload + + # Reloads the configuration for lighttpd + __init_script lighty --script lighttpd --mode force-reload SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/other/types_submitted_for_inclusion/__mysql_server/man.text b/other/types_submitted_for_inclusion/__mysql_server/man.rst similarity index 58% rename from other/types_submitted_for_inclusion/__mysql_server/man.text rename to other/types_submitted_for_inclusion/__mysql_server/man.rst index f8573051..c561117c 100644 --- a/other/types_submitted_for_inclusion/__mysql_server/man.text +++ b/other/types_submitted_for_inclusion/__mysql_server/man.rst @@ -1,13 +1,10 @@ cdist-type__mysql_server(7) =========================== +Manage a MySQL server + Benedikt Koeppel -NAME ----- -cdist-type__mysql_server - Manage a MySQL server - - DESCRIPTION ----------- This cdist type allows you to install a MySQL database server. The @@ -18,13 +15,13 @@ with MySQL. REQUIRED PARAMETERS ------------------- -password:: +password The root password to set. OPTIONAL PARAMETERS ------------------- -no_my_cnf:: +no_my_cnf The /root/.my.cnf file is used to temporary store the root password when doing the mysql_secure_installation. If you want to have your own .my.cnf file, then specify --no_my_cnf "true". @@ -34,24 +31,24 @@ no_my_cnf:: EXAMPLES -------- --------------------------------------------------------------------------------- -# to install a MySQL server -__mysql_server +.. code-block:: sh -# to install a MySQL server, remove remote access, remove test databases -# similar to mysql_secure_installation, specify the root password -__mysql_server --password "Uu9jooKe" -# this will also write a /root/.my.cnf file + # to install a MySQL server + __mysql_server -# if you don't want cdist to write a /root/.my.cnf file permanently, specify -# the --no_my_cnf option -__mysql_server --password "Uu9jooKe" --no_my_cnf --------------------------------------------------------------------------------- + # to install a MySQL server, remove remote access, remove test databases + # similar to mysql_secure_installation, specify the root password + __mysql_server --password "Uu9jooKe" + # this will also write a /root/.my.cnf file + + # if you don't want cdist to write a /root/.my.cnf file permanently, specify + # the --no_my_cnf option + __mysql_server --password "Uu9jooKe" --no_my_cnf SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/other/types_submitted_for_inclusion/__nfs_client/man.text b/other/types_submitted_for_inclusion/__nfs_client/man.rst similarity index 67% rename from other/types_submitted_for_inclusion/__nfs_client/man.text rename to other/types_submitted_for_inclusion/__nfs_client/man.rst index 3f0808a7..3c582958 100644 --- a/other/types_submitted_for_inclusion/__nfs_client/man.text +++ b/other/types_submitted_for_inclusion/__nfs_client/man.rst @@ -1,13 +1,10 @@ cdist-type__nfs_client(7) ========================= +nfs client + Steven Armstrong -NAME ----- -cdist-type__nfs_client - nfs client - - DESCRIPTION ----------- Install, start, do whatever is necessary to have a working nfs client. @@ -26,14 +23,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__nfs_client --------------------------------------------------------------------------------- +.. code-block:: sh + + __nfs_client SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/other/types_submitted_for_inclusion/__nfs_export/man.text b/other/types_submitted_for_inclusion/__nfs_export/man.rst similarity index 67% rename from other/types_submitted_for_inclusion/__nfs_export/man.text rename to other/types_submitted_for_inclusion/__nfs_export/man.rst index 41ff64e8..4dd164ec 100644 --- a/other/types_submitted_for_inclusion/__nfs_export/man.text +++ b/other/types_submitted_for_inclusion/__nfs_export/man.rst @@ -1,13 +1,10 @@ cdist-type__nfs_export(7) ========================= +Manage nfs exports + Steven Armstrong -NAME ----- -cdist-type__nfs_export - manage nfs exports - - DESCRIPTION ----------- This cdist type allows you to manage entries in /etc/exports.d. @@ -17,35 +14,35 @@ For older distributions (currently ubuntu lucid) that don't support REQUIRED PARAMETERS ------------------- -client:: +client space delimited list of client ip/networks for use in /etc/exports. See exports(5) OPTIONAL PARAMETERS ------------------- -options:: +options export options for use in /etc/exports. See exports(5) -export:: +export the directory to export. Defaults to object_id -state:: +state Either present or absent. Defaults to present. EXAMPLES -------- --------------------------------------------------------------------------------- -__nfs_export /local/chroot/lucid-amd64 \ - --client "192.168.0.1/24 10.0.0.1/16" \ - --options "ro,async,no_all_squash,no_root_squash,subtree_check" --------------------------------------------------------------------------------- +.. code-block:: sh + + __nfs_export /local/chroot/lucid-amd64 \ + --client "192.168.0.1/24 10.0.0.1/16" \ + --options "ro,async,no_all_squash,no_root_squash,subtree_check" SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ - exports(5) diff --git a/other/types_submitted_for_inclusion/__nfs_server/man.text b/other/types_submitted_for_inclusion/__nfs_server/man.rst similarity index 67% rename from other/types_submitted_for_inclusion/__nfs_server/man.text rename to other/types_submitted_for_inclusion/__nfs_server/man.rst index 41fc1d75..1f9aad76 100644 --- a/other/types_submitted_for_inclusion/__nfs_server/man.text +++ b/other/types_submitted_for_inclusion/__nfs_server/man.rst @@ -1,13 +1,10 @@ cdist-type__nfs_server(7) ========================= +nfs server + Steven Armstrong -NAME ----- -cdist-type__nfs_server - nfs server - - DESCRIPTION ----------- Install, start, do whatever is necessary to have a working nfs server. @@ -26,14 +23,14 @@ None. EXAMPLES -------- --------------------------------------------------------------------------------- -__nfs_server --------------------------------------------------------------------------------- +.. code-block:: sh + + __nfs_server SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/other/types_submitted_for_inclusion/__rsyncer/man.text b/other/types_submitted_for_inclusion/__rsyncer/man.rst similarity index 72% rename from other/types_submitted_for_inclusion/__rsyncer/man.text rename to other/types_submitted_for_inclusion/__rsyncer/man.rst index 6fab9fd3..a09bfea5 100644 --- a/other/types_submitted_for_inclusion/__rsyncer/man.text +++ b/other/types_submitted_for_inclusion/__rsyncer/man.rst @@ -1,13 +1,10 @@ cdist-type__rsyncer(7) ====================== +Use rsync to copy files. + Daniel Maher -NAME ----- -cdist-type__rsyncer - Use rsync to copy files. - - DESCRIPTION ----------- This type is used to trigger rsync to copy files from the machine running cdist @@ -19,41 +16,41 @@ from the destination which are not present on the source. REQUIRED PARAMETERS ------------------- -source:: +source The full path of the source from which to copy. This is passed directly to rsync. OPTIONAL PARAMETERS ------------------- -destination:: +destination The full path of the destination. This is passed directly to rsync. Default: object_id -delete:: +delete If true, remove files from destination which are not in source. This is effectively the --delete argument of rsync. Default: false -rsyncbin:: +rsyncbin Specify the full path to the rsync binary. Default: `which rsync` EXAMPLES -------- --------------------------------------------------------------------------------- -# Basic example -__rsyncer '/home/foo' --source '/opt/dist/foo' +.. code-block:: sh -# Fancier example -__rsyncer FOO --source '/opt/dist/foo' --destination '/home/foo/' --delete true --------------------------------------------------------------------------------- + # Basic example + __rsyncer '/home/foo' --source '/opt/dist/foo' + + # Fancier example + __rsyncer FOO --source '/opt/dist/foo' --destination '/home/foo/' --delete true SEE ALSO -------- -- cdist-type(7) +- `cdist-type(7) `_ COPYING diff --git a/other/types_submitted_for_inclusion/__run_command/man.rst b/other/types_submitted_for_inclusion/__run_command/man.rst new file mode 100644 index 00000000..f4426043 --- /dev/null +++ b/other/types_submitted_for_inclusion/__run_command/man.rst @@ -0,0 +1,66 @@ +cdist-type__run_command(7) +========================== +Run a command + +Benedikt Koeppel + + +DESCRIPTION +----------- +This cdist type allows you to run a specific command once at installation time. + + +REQUIRED PARAMETERS +------------------- + + +OPTIONAL PARAMETERS +------------------- +command + Command (with arguments) to run. + + If no command is give, then the object_id is executed. + + + +EXAMPLES +-------- + +.. code-block:: sh + + # Run a command + __run_command "/etc/init.d/mysql restart" + # runs `/etc/init.d/mysql restart` (the "object_id") + + # Run the same command: + __run_command restart-mysql --command "/etc/init.d/mysql restart" + # runs `/etc/init.d/mysql restart` (the --command argument) + # additionally, it can easily be referenced (for example in a require="..." + #as __run_command/restart-mysql + + # Run a script: + __run_command install-pear --command "$(cat <<-EOF + /usr/bin/pear install --force Auth + /usr/bin/pear install --force HTML_Template_IT-1.2.1 + /usr/bin/pear install --force MDB2 + /usr/bin/pear install --force MDB2#mysql + /usr/bin/pear config-set preferred_state beta; + /usr/bin/pear install --force --alldeps Spreadsheet_Excel_Writer; + /usr/bin/pear config-set preferred_state stable + /usr/bin/pear install --force HTTP_Request + /usr/bin/pear install --force Mail + /usr/bin/pear install --force Auth_HTTP + /usr/bin/pear install --force XML_RPC + EOF + )" + + +SEE ALSO +-------- +- `cdist-type(7) `_ + + +COPYING +------- +Copyright \(C) 2012 Benedikt Koeppel. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/other/types_submitted_for_inclusion/__run_command/man.text b/other/types_submitted_for_inclusion/__run_command/man.text deleted file mode 100644 index 5ea553c3..00000000 --- a/other/types_submitted_for_inclusion/__run_command/man.text +++ /dev/null @@ -1,70 +0,0 @@ -cdist-type__run_command(7) -========================== -Benedikt Koeppel - - -NAME ----- -cdist-type__run_command - Run a command - - -DESCRIPTION ------------ -This cdist type allows you to run a specific command once at installation time. - - -REQUIRED PARAMETERS -------------------- - - -OPTIONAL PARAMETERS -------------------- -command:: - Command (with arguments) to run. - - If no command is give, then the object_id is executed. - - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# Run a command -__run_command "/etc/init.d/mysql restart" -# runs `/etc/init.d/mysql restart` (the "object_id") - -# Run the same command: -__run_command restart-mysql --command "/etc/init.d/mysql restart" -# runs `/etc/init.d/mysql restart` (the --command argument) -# additionally, it can easily be referenced (for example in a require="..." -#as __run_command/restart-mysql - -# Run a script: -__run_command install-pear --command "$(cat <<-EOF - /usr/bin/pear install --force Auth - /usr/bin/pear install --force HTML_Template_IT-1.2.1 - /usr/bin/pear install --force MDB2 - /usr/bin/pear install --force MDB2#mysql - /usr/bin/pear config-set preferred_state beta; - /usr/bin/pear install --force --alldeps Spreadsheet_Excel_Writer; - /usr/bin/pear config-set preferred_state stable - /usr/bin/pear install --force HTTP_Request - /usr/bin/pear install --force Mail - /usr/bin/pear install --force Auth_HTTP - /usr/bin/pear install --force XML_RPC -EOF -)" - --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2012 Benedikt Koeppel. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). From 69f3759a8956823bdf89bc0c37bbb31635ac0d39 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 23 May 2016 17:24:17 +0200 Subject: [PATCH 0129/1332] Update changelog for option -f. --- docs/changelog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 3a644b6f..e7dc26ed 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Add -f option to read additional hosts from file/stdin (Darko Poljak) + 4.0.0: 2016-05-04 * Core: Fix bug with parallel hosts operation when output path is specifed (Darko Poljak) * Type __package_pip: Add support for running as specified user (useful for pip in venv) (Darko Poljak) @@ -25,7 +28,6 @@ Changelog * Type __consul: Add new consul versions (Nico Schottelius) * Type __apt_ppa: Do not install legacy package python-software-properties (Steven Armstrong) - 3.1.13: 2015-05-16 * Type __block: Fix support for non stdin blocks (Dominique Roux) * Type __consul: Install package unzip (Nico Schottelius) From 1b37b9fbb1a36601731dcb653ecf4834bc77fa3f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 25 May 2016 07:25:21 +0200 Subject: [PATCH 0130/1332] Minor sentence fixes. --- docs/man/man1/cdist.text | 2 +- scripts/cdist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index 4e45ae81..1dc1e87f 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -111,7 +111,7 @@ EXAMPLES --remote-copy /path/to/my/remote/copy \ -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch -# Configure hosts in parallel by reading hosts from file loadbalancers +# Configure hosts read from file loadbalancers % cdist config -f loadbalancers # Display banner diff --git a/scripts/cdist b/scripts/cdist index ccdb5232..6baa28f3 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -85,7 +85,7 @@ def commandline(): parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel']]) parser['config'].add_argument('host', nargs='*', - help='one or more hosts to operate on') + help='host(s) to operate on') parser['config'].add_argument('-c', '--conf-dir', help=('Add configuration directory (can be repeated, ' 'last one wins)'), action='append') From 03928eb23f37413d5fe36e5a1afde3aff29d236a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 25 May 2016 08:06:13 +0200 Subject: [PATCH 0131/1332] Fix man section conf. --- docs/man/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/conf.py b/docs/man/conf.py index 0cf8bc61..7df4ed25 100644 --- a/docs/man/conf.py +++ b/docs/man/conf.py @@ -265,7 +265,7 @@ for mansubdir in ('man1', 'man7'): froot, fext = os.path.splitext(fname) if fext == '.rst': man_page = (os.path.join(mansubdir, froot), froot, '', - [], 7) + [], mansubdir[-1]) man_pages.append(man_page) #man_pages = [ From 3e94ea3d869938adc1aa75d74aa89c09e993338b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 25 May 2016 08:09:18 +0200 Subject: [PATCH 0132/1332] Cleanup. --- docs/man/man7/cdist-reference.rst | 313 ------------------ docs/man/man7/cdist-type__apt_key.rst | 1 - docs/man/man7/cdist-type__apt_key_uri.rst | 1 - .../man/man7/cdist-type__apt_norecommends.rst | 1 - docs/man/man7/cdist-type__apt_ppa.rst | 1 - docs/man/man7/cdist-type__apt_source.rst | 1 - .../man/man7/cdist-type__apt_update_index.rst | 1 - docs/man/man7/cdist-type__block.rst | 1 - docs/man/man7/cdist-type__ccollect_source.rst | 1 - docs/man/man7/cdist-type__cdist.rst | 1 - docs/man/man7/cdist-type__cdistmarker.rst | 1 - docs/man/man7/cdist-type__config_file.rst | 1 - docs/man/man7/cdist-type__consul.rst | 1 - docs/man/man7/cdist-type__consul_agent.rst | 1 - docs/man/man7/cdist-type__consul_check.rst | 1 - docs/man/man7/cdist-type__consul_reload.rst | 1 - docs/man/man7/cdist-type__consul_service.rst | 1 - docs/man/man7/cdist-type__consul_template.rst | 1 - .../cdist-type__consul_template_template.rst | 1 - .../man7/cdist-type__consul_watch_checks.rst | 1 - .../man7/cdist-type__consul_watch_event.rst | 1 - .../man/man7/cdist-type__consul_watch_key.rst | 1 - .../cdist-type__consul_watch_keyprefix.rst | 1 - .../man7/cdist-type__consul_watch_nodes.rst | 1 - .../man7/cdist-type__consul_watch_service.rst | 1 - .../cdist-type__consul_watch_services.rst | 1 - docs/man/man7/cdist-type__cron.rst | 1 - .../cdist-type__debconf_set_selections.rst | 1 - docs/man/man7/cdist-type__directory.rst | 1 - docs/man/man7/cdist-type__dog_vdi.rst | 1 - docs/man/man7/cdist-type__file.rst | 1 - docs/man/man7/cdist-type__firewalld_rule.rst | 1 - docs/man/man7/cdist-type__git.rst | 1 - docs/man/man7/cdist-type__group.rst | 1 - docs/man/man7/cdist-type__hostname.rst | 1 - docs/man/man7/cdist-type__iptables_apply.rst | 1 - docs/man/man7/cdist-type__iptables_rule.rst | 1 - docs/man/man7/cdist-type__issue.rst | 1 - docs/man/man7/cdist-type__jail.rst | 1 - docs/man/man7/cdist-type__key_value.rst | 1 - docs/man/man7/cdist-type__line.rst | 1 - docs/man/man7/cdist-type__link.rst | 1 - docs/man/man7/cdist-type__locale.rst | 1 - docs/man/man7/cdist-type__motd.rst | 1 - docs/man/man7/cdist-type__mount.rst | 1 - docs/man/man7/cdist-type__mysql_database.rst | 1 - docs/man/man7/cdist-type__package.rst | 1 - docs/man/man7/cdist-type__package_apt.rst | 1 - docs/man/man7/cdist-type__package_emerge.rst | 1 - ...dist-type__package_emerge_dependencies.rst | 1 - .../man/man7/cdist-type__package_luarocks.rst | 1 - docs/man/man7/cdist-type__package_opkg.rst | 1 - docs/man/man7/cdist-type__package_pacman.rst | 1 - docs/man/man7/cdist-type__package_pip.rst | 1 - .../man7/cdist-type__package_pkg_freebsd.rst | 1 - .../man7/cdist-type__package_pkg_openbsd.rst | 1 - .../cdist-type__package_pkgng_freebsd.rst | 1 - docs/man/man7/cdist-type__package_rubygem.rst | 1 - .../man7/cdist-type__package_update_index.rst | 1 - .../man7/cdist-type__package_upgrade_all.rst | 1 - docs/man/man7/cdist-type__package_yum.rst | 1 - docs/man/man7/cdist-type__package_zypper.rst | 1 - docs/man/man7/cdist-type__pacman_conf.rst | 1 - .../cdist-type__pacman_conf_integrate.rst | 1 - docs/man/man7/cdist-type__pf_apply.rst | 1 - docs/man/man7/cdist-type__pf_ruleset.rst | 1 - docs/man/man7/cdist-type__postfix.rst | 1 - docs/man/man7/cdist-type__postfix_master.rst | 1 - .../man/man7/cdist-type__postfix_postconf.rst | 1 - docs/man/man7/cdist-type__postfix_postmap.rst | 1 - docs/man/man7/cdist-type__postfix_reload.rst | 1 - .../man7/cdist-type__postgres_database.rst | 1 - docs/man/man7/cdist-type__postgres_role.rst | 1 - docs/man/man7/cdist-type__process.rst | 1 - docs/man/man7/cdist-type__pyvenv.rst | 1 - docs/man/man7/cdist-type__qemu_img.rst | 1 - docs/man/man7/cdist-type__rbenv.rst | 1 - docs/man/man7/cdist-type__rsync.rst | 1 - docs/man/man7/cdist-type__rvm.rst | 1 - docs/man/man7/cdist-type__rvm_gem.rst | 1 - docs/man/man7/cdist-type__rvm_gemset.rst | 1 - docs/man/man7/cdist-type__rvm_ruby.rst | 1 - .../man7/cdist-type__ssh_authorized_key.rst | 1 - .../man7/cdist-type__ssh_authorized_keys.rst | 1 - docs/man/man7/cdist-type__ssh_dot_ssh.rst | 1 - docs/man/man7/cdist-type__staged_file.rst | 1 - docs/man/man7/cdist-type__start_on_boot.rst | 1 - docs/man/man7/cdist-type__timezone.rst | 1 - .../man7/cdist-type__update_alternatives.rst | 1 - docs/man/man7/cdist-type__user.rst | 1 - docs/man/man7/cdist-type__user_groups.rst | 1 - docs/man/man7/cdist-type__yum_repo.rst | 1 - docs/man/man7/cdist-type__zypper_repo.rst | 1 - docs/man/man7/cdist-type__zypper_service.rst | 1 - 94 files changed, 406 deletions(-) delete mode 100644 docs/man/man7/cdist-reference.rst delete mode 120000 docs/man/man7/cdist-type__apt_key.rst delete mode 120000 docs/man/man7/cdist-type__apt_key_uri.rst delete mode 120000 docs/man/man7/cdist-type__apt_norecommends.rst delete mode 120000 docs/man/man7/cdist-type__apt_ppa.rst delete mode 120000 docs/man/man7/cdist-type__apt_source.rst delete mode 120000 docs/man/man7/cdist-type__apt_update_index.rst delete mode 120000 docs/man/man7/cdist-type__block.rst delete mode 120000 docs/man/man7/cdist-type__ccollect_source.rst delete mode 120000 docs/man/man7/cdist-type__cdist.rst delete mode 120000 docs/man/man7/cdist-type__cdistmarker.rst delete mode 120000 docs/man/man7/cdist-type__config_file.rst delete mode 120000 docs/man/man7/cdist-type__consul.rst delete mode 120000 docs/man/man7/cdist-type__consul_agent.rst delete mode 120000 docs/man/man7/cdist-type__consul_check.rst delete mode 120000 docs/man/man7/cdist-type__consul_reload.rst delete mode 120000 docs/man/man7/cdist-type__consul_service.rst delete mode 120000 docs/man/man7/cdist-type__consul_template.rst delete mode 120000 docs/man/man7/cdist-type__consul_template_template.rst delete mode 120000 docs/man/man7/cdist-type__consul_watch_checks.rst delete mode 120000 docs/man/man7/cdist-type__consul_watch_event.rst delete mode 120000 docs/man/man7/cdist-type__consul_watch_key.rst delete mode 120000 docs/man/man7/cdist-type__consul_watch_keyprefix.rst delete mode 120000 docs/man/man7/cdist-type__consul_watch_nodes.rst delete mode 120000 docs/man/man7/cdist-type__consul_watch_service.rst delete mode 120000 docs/man/man7/cdist-type__consul_watch_services.rst delete mode 120000 docs/man/man7/cdist-type__cron.rst delete mode 120000 docs/man/man7/cdist-type__debconf_set_selections.rst delete mode 120000 docs/man/man7/cdist-type__directory.rst delete mode 120000 docs/man/man7/cdist-type__dog_vdi.rst delete mode 120000 docs/man/man7/cdist-type__file.rst delete mode 120000 docs/man/man7/cdist-type__firewalld_rule.rst delete mode 120000 docs/man/man7/cdist-type__git.rst delete mode 120000 docs/man/man7/cdist-type__group.rst delete mode 120000 docs/man/man7/cdist-type__hostname.rst delete mode 120000 docs/man/man7/cdist-type__iptables_apply.rst delete mode 120000 docs/man/man7/cdist-type__iptables_rule.rst delete mode 120000 docs/man/man7/cdist-type__issue.rst delete mode 120000 docs/man/man7/cdist-type__jail.rst delete mode 120000 docs/man/man7/cdist-type__key_value.rst delete mode 120000 docs/man/man7/cdist-type__line.rst delete mode 120000 docs/man/man7/cdist-type__link.rst delete mode 120000 docs/man/man7/cdist-type__locale.rst delete mode 120000 docs/man/man7/cdist-type__motd.rst delete mode 120000 docs/man/man7/cdist-type__mount.rst delete mode 120000 docs/man/man7/cdist-type__mysql_database.rst delete mode 120000 docs/man/man7/cdist-type__package.rst delete mode 120000 docs/man/man7/cdist-type__package_apt.rst delete mode 120000 docs/man/man7/cdist-type__package_emerge.rst delete mode 120000 docs/man/man7/cdist-type__package_emerge_dependencies.rst delete mode 120000 docs/man/man7/cdist-type__package_luarocks.rst delete mode 120000 docs/man/man7/cdist-type__package_opkg.rst delete mode 120000 docs/man/man7/cdist-type__package_pacman.rst delete mode 120000 docs/man/man7/cdist-type__package_pip.rst delete mode 120000 docs/man/man7/cdist-type__package_pkg_freebsd.rst delete mode 120000 docs/man/man7/cdist-type__package_pkg_openbsd.rst delete mode 120000 docs/man/man7/cdist-type__package_pkgng_freebsd.rst delete mode 120000 docs/man/man7/cdist-type__package_rubygem.rst delete mode 120000 docs/man/man7/cdist-type__package_update_index.rst delete mode 120000 docs/man/man7/cdist-type__package_upgrade_all.rst delete mode 120000 docs/man/man7/cdist-type__package_yum.rst delete mode 120000 docs/man/man7/cdist-type__package_zypper.rst delete mode 120000 docs/man/man7/cdist-type__pacman_conf.rst delete mode 120000 docs/man/man7/cdist-type__pacman_conf_integrate.rst delete mode 120000 docs/man/man7/cdist-type__pf_apply.rst delete mode 120000 docs/man/man7/cdist-type__pf_ruleset.rst delete mode 120000 docs/man/man7/cdist-type__postfix.rst delete mode 120000 docs/man/man7/cdist-type__postfix_master.rst delete mode 120000 docs/man/man7/cdist-type__postfix_postconf.rst delete mode 120000 docs/man/man7/cdist-type__postfix_postmap.rst delete mode 120000 docs/man/man7/cdist-type__postfix_reload.rst delete mode 120000 docs/man/man7/cdist-type__postgres_database.rst delete mode 120000 docs/man/man7/cdist-type__postgres_role.rst delete mode 120000 docs/man/man7/cdist-type__process.rst delete mode 120000 docs/man/man7/cdist-type__pyvenv.rst delete mode 120000 docs/man/man7/cdist-type__qemu_img.rst delete mode 120000 docs/man/man7/cdist-type__rbenv.rst delete mode 120000 docs/man/man7/cdist-type__rsync.rst delete mode 120000 docs/man/man7/cdist-type__rvm.rst delete mode 120000 docs/man/man7/cdist-type__rvm_gem.rst delete mode 120000 docs/man/man7/cdist-type__rvm_gemset.rst delete mode 120000 docs/man/man7/cdist-type__rvm_ruby.rst delete mode 120000 docs/man/man7/cdist-type__ssh_authorized_key.rst delete mode 120000 docs/man/man7/cdist-type__ssh_authorized_keys.rst delete mode 120000 docs/man/man7/cdist-type__ssh_dot_ssh.rst delete mode 120000 docs/man/man7/cdist-type__staged_file.rst delete mode 120000 docs/man/man7/cdist-type__start_on_boot.rst delete mode 120000 docs/man/man7/cdist-type__timezone.rst delete mode 120000 docs/man/man7/cdist-type__update_alternatives.rst delete mode 120000 docs/man/man7/cdist-type__user.rst delete mode 120000 docs/man/man7/cdist-type__user_groups.rst delete mode 120000 docs/man/man7/cdist-type__yum_repo.rst delete mode 120000 docs/man/man7/cdist-type__zypper_repo.rst delete mode 120000 docs/man/man7/cdist-type__zypper_service.rst diff --git a/docs/man/man7/cdist-reference.rst b/docs/man/man7/cdist-reference.rst deleted file mode 100644 index bef0e452..00000000 --- a/docs/man/man7/cdist-reference.rst +++ /dev/null @@ -1,313 +0,0 @@ -cdist-reference(7) -================== -Variable, path and type reference for cdist - -Nico Schottelius - - -EXPLORERS ---------- -The following global explorers are available: - -- cpu_cores -- cpu_sockets -- hostname -- init -- interfaces -- lsb_codename -- lsb_description -- lsb_id -- lsb_release -- machine -- machine_type -- memory -- os -- os_version -- runlevel - -PATHS ------ -$HOME/.cdist - The standard cdist configuration directory relative to your home directory - This is usually the place you want to store your site specific configuration - -cdist/conf/ - The distribution configuration directory - This contains types and explorers to be used - -confdir - Cdist will use all available configuration directories and create - a temporary confdir containing links to the real configuration directories. - This way it is possible to merge configuration directories. - By default it consists of everything in $HOME/.cdist and cdist/conf/. - For more details see cdist(1) - -confdir/manifest/init - This is the central entry point. - It is an executable (+x bit set) shell script that can use - values from the explorers to decide which configuration to create - for the specified target host. - Its intent is to used to define mapping from configurations to hosts. - -confdir/manifest/* - All other files in this directory are not directly used by cdist, but you - can separate configuration mappings, if you have a lot of code in the - conf/manifest/init file. This may also be helpful to have different admins - maintain different groups of hosts. - -confdir/explorer/ - Contains explorers to be run on the target hosts, see cdist-explorer(7). - -confdir/type/ - Contains all available types, which are used to provide - some kind of functionality. See cdist-type(7). - -confdir/type// - Home of the type . - This directory is referenced by the variable __type (see below). - -confdir/type//man.rst - Manpage in reStructuredText format (required for inclusion into upstream) - -confdir/type//manifest - Used to generate additional objects from a type. - -confdir/type//gencode-local - Used to generate code to be executed on the source host - -confdir/type//gencode-remote - Used to generate code to be executed on the target host - -confdir/type//parameter/required - Parameters required by type, \n separated list. - -confdir/type//parameter/optional - Parameters optionally accepted by type, \n separated list. - -confdir/type//parameter/default/* - Default values for optional parameters. - Assuming an optional parameter name of 'foo', it's default value would - be read from the file confdir/type//parameter/default/foo. - -confdir/type//parameter/boolean - Boolean parameters accepted by type, \n separated list. - -confdir/type//explorer - Location of the type specific explorers. - This directory is referenced by the variable __type_explorer (see below). - See cdist-explorer(7). - -confdir/type//files - This directory is reserved for user data and will not be used - by cdist at any time. It can be used for storing supplementary - files (like scripts to act as a template or configuration files). - -out/ - This directory contains output of cdist and is usually located - in a temporary directory and thus will be removed after the run. - This directory is referenced by the variable __global (see below). - -out/explorer - Output of general explorers. - -out/object - Objects created for the host. - -out/object/ - Contains all object specific information. - This directory is referenced by the variable __object (see below). - -out/object//explorers - Output of type specific explorers, per object. - -TYPES ------ -The following types are available: - -- \__apt_key (`cdist-type__apt_key(7) `_) -- \__apt_key_uri (`cdist-type__apt_key_uri(7) `_) -- \__apt_norecommends (`cdist-type__apt_norecommends(7) `_) -- \__apt_ppa (`cdist-type__apt_ppa(7) `_) -- \__apt_source (`cdist-type__apt_source(7) `_) -- \__apt_update_index (`cdist-type__apt_update_index(7) `_) -- \__block (`cdist-type__block(7) `_) -- \__ccollect_source (`cdist-type__ccollect_source(7) `_) -- \__cdist (`cdist-type__cdist(7) `_) -- \__cdistmarker (`cdist-type__cdistmarker(7) `_) -- \__config_file (`cdist-type__config_file(7) `_) -- \__consul (`cdist-type__consul(7) `_) -- \__consul_agent (`cdist-type__consul_agent(7) `_) -- \__consul_check (`cdist-type__consul_check(7) `_) -- \__consul_reload (`cdist-type__consul_reload(7) `_) -- \__consul_service (`cdist-type__consul_service(7) `_) -- \__consul_template (`cdist-type__consul_template(7) `_) -- \__consul_template_template (`cdist-type__consul_template_template(7) `_) -- \__consul_watch_checks (`cdist-type__consul_watch_checks(7) `_) -- \__consul_watch_event (`cdist-type__consul_watch_event(7) `_) -- \__consul_watch_key (`cdist-type__consul_watch_key(7) `_) -- \__consul_watch_keyprefix (`cdist-type__consul_watch_keyprefix(7) `_) -- \__consul_watch_nodes (`cdist-type__consul_watch_nodes(7) `_) -- \__consul_watch_service (`cdist-type__consul_watch_service(7) `_) -- \__consul_watch_services (`cdist-type__consul_watch_services(7) `_) -- \__cron (`cdist-type__cron(7) `_) -- \__debconf_set_selections (`cdist-type__debconf_set_selections(7) `_) -- \__directory (`cdist-type__directory(7) `_) -- \__dog_vdi (`cdist-type__dog_vdi(7) `_) -- \__file (`cdist-type__file(7) `_) -- \__firewalld_rule (`cdist-type__firewalld_rule(7) `_) -- \__git (`cdist-type__git(7) `_) -- \__group (`cdist-type__group(7) `_) -- \__hostname (`cdist-type__hostname(7) `_) -- \__iptables_apply (`cdist-type__iptables_apply(7) `_) -- \__iptables_rule (`cdist-type__iptables_rule(7) `_) -- \__issue (`cdist-type__issue(7) `_) -- \__jail (`cdist-type__jail(7) `_) -- \__key_value (`cdist-type__key_value(7) `_) -- \__line (`cdist-type__line(7) `_) -- \__link (`cdist-type__link(7) `_) -- \__locale (`cdist-type__locale(7) `_) -- \__motd (`cdist-type__motd(7) `_) -- \__mount (`cdist-type__mount(7) `_) -- \__mysql_database (`cdist-type__mysql_database(7) `_) -- \__package (`cdist-type__package(7) `_) -- \__package_apt (`cdist-type__package_apt(7) `_) -- \__package_emerge (`cdist-type__package_emerge(7) `_) -- \__package_emerge_dependencies (`cdist-type__package_emerge_dependencies(7) `_) -- \__package_luarocks (`cdist-type__package_luarocks(7) `_) -- \__package_opkg (`cdist-type__package_opkg(7) `_) -- \__package_pacman (`cdist-type__package_pacman(7) `_) -- \__package_pip (`cdist-type__package_pip(7) `_) -- \__package_pkg_freebsd (`cdist-type__package_pkg_freebsd(7) `_) -- \__package_pkg_openbsd (`cdist-type__package_pkg_openbsd(7) `_) -- \__package_pkgng_freebsd (`cdist-type__package_pkgng_freebsd(7) `_) -- \__package_rubygem (`cdist-type__package_rubygem(7) `_) -- \__package_update_index (`cdist-type__package_update_index(7) `_) -- \__package_upgrade_all (`cdist-type__package_upgrade_all(7) `_) -- \__package_yum (`cdist-type__package_yum(7) `_) -- \__package_zypper (`cdist-type__package_zypper(7) `_) -- \__pacman_conf (`cdist-type__pacman_conf(7) `_) -- \__pacman_conf_integrate (`cdist-type__pacman_conf_integrate(7) `_) -- \__pf_apply (`cdist-type__pf_apply(7) `_) -- \__pf_ruleset (`cdist-type__pf_ruleset(7) `_) -- \__postfix (`cdist-type__postfix(7) `_) -- \__postfix_master (`cdist-type__postfix_master(7) `_) -- \__postfix_postconf (`cdist-type__postfix_postconf(7) `_) -- \__postfix_postmap (`cdist-type__postfix_postmap(7) `_) -- \__postfix_reload (`cdist-type__postfix_reload(7) `_) -- \__postgres_database (`cdist-type__postgres_database(7) `_) -- \__postgres_role (`cdist-type__postgres_role(7) `_) -- \__process (`cdist-type__process(7) `_) -- \__pyvenv (`cdist-type__pyvenv(7) `_) -- \__qemu_img (`cdist-type__qemu_img(7) `_) -- \__rbenv (`cdist-type__rbenv(7) `_) -- \__rsync (`cdist-type__rsync(7) `_) -- \__rvm (`cdist-type__rvm(7) `_) -- \__rvm_gem (`cdist-type__rvm_gem(7) `_) -- \__rvm_gemset (`cdist-type__rvm_gemset(7) `_) -- \__rvm_ruby (`cdist-type__rvm_ruby(7) `_) -- \__ssh_authorized_key (`cdist-type__ssh_authorized_key(7) `_) -- \__ssh_authorized_keys (`cdist-type__ssh_authorized_keys(7) `_) -- \__ssh_dot_ssh (`cdist-type__ssh_dot_ssh(7) `_) -- \__staged_file (`cdist-type__staged_file(7) `_) -- \__start_on_boot (`cdist-type__start_on_boot(7) `_) -- \__timezone (`cdist-type__timezone(7) `_) -- \__update_alternatives (`cdist-type__update_alternatives(7) `_) -- \__user (`cdist-type__user(7) `_) -- \__user_groups (`cdist-type__user_groups(7) `_) -- \__yum_repo (`cdist-type__yum_repo(7) `_) -- \__zypper_repo (`cdist-type__zypper_repo(7) `_) -- \__zypper_service (`cdist-type__zypper_service(7) `_) - - -OBJECTS -------- -For object to object communication and tests, the following paths are -usable within a object directory: - -files - This directory is reserved for user data and will not be used - by cdist at any time. It can be used freely by the type - (for instance to store template results). -changed - This empty file exists in an object directory, if the object has - code to be executed (either remote or local) -stdin - This file exists and contains data, if data was provided on stdin - when the type was called. - - -ENVIRONMENT VARIABLES (FOR READING) ------------------------------------ -The following environment variables are exported by cdist: - -__explorer - Directory that contains all global explorers. - Available for: initial manifest, explorer, type explorer, shell -__manifest - Directory that contains the initial manifest. - Available for: initial manifest, type manifest, shell -__global - Directory that contains generic output like explorer. - Available for: initial manifest, type manifest, type gencode, shell -__messages_in - File to read messages from. - Available for: initial manifest, type manifest, type gencode -__messages_out - File to write messages. - Available for: initial manifest, type manifest, type gencode -__object - Directory that contains the current object. - Available for: type manifest, type explorer, type gencode and code scripts -__object_id - The type unique object id. - Available for: type manifest, type explorer, type gencode and code scripts - Note: The leading and the trailing "/" will always be stripped (caused by - the filesystem database and ensured by the core). - Note: Double slashes ("//") will not be fixed and result in an error. -__object_name - The full qualified name of the current object. - Available for: type manifest, type explorer, type gencode -__target_host - The host we are deploying to. - Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell -__type - Path to the current type. - Available for: type manifest, type gencode -__type_explorer - Directory that contains the type explorers. - Available for: type explorer - -ENVIRONMENT VARIABLES (FOR WRITING) ------------------------------------ -The following environment variables influence the behaviour of cdist: - -require - Setup dependencies between objects (see cdist-manifest(7)) - -CDIST_LOCAL_SHELL - Use this shell locally instead of /bin/sh to execute scripts - -CDIST_REMOTE_SHELL - Use this shell remotely instead of /bin/sh to execute scripts - -CDIST_OVERRIDE - Allow overwriting type parameters (see cdist-manifest(7)) - -CDIST_ORDER_DEPENDENCY - Create dependencies based on the execution order (see cdist-manifest(7)) - -CDIST_REMOTE_EXEC - Use this command for remote execution (should behave like ssh) - -CDIST_REMOTE_COPY - Use this command for remote copy (should behave like scp) - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ - - -COPYING -------- -Copyright \(C) 2011-2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-type__apt_key.rst b/docs/man/man7/cdist-type__apt_key.rst deleted file mode 120000 index 12d532ee..00000000 --- a/docs/man/man7/cdist-type__apt_key.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__apt_key/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_key_uri.rst b/docs/man/man7/cdist-type__apt_key_uri.rst deleted file mode 120000 index e90fda00..00000000 --- a/docs/man/man7/cdist-type__apt_key_uri.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__apt_key_uri/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_norecommends.rst b/docs/man/man7/cdist-type__apt_norecommends.rst deleted file mode 120000 index 2ce4bdea..00000000 --- a/docs/man/man7/cdist-type__apt_norecommends.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__apt_norecommends/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_ppa.rst b/docs/man/man7/cdist-type__apt_ppa.rst deleted file mode 120000 index efdc1de2..00000000 --- a/docs/man/man7/cdist-type__apt_ppa.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__apt_ppa/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_source.rst b/docs/man/man7/cdist-type__apt_source.rst deleted file mode 120000 index 2d2c77b7..00000000 --- a/docs/man/man7/cdist-type__apt_source.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__apt_source/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__apt_update_index.rst b/docs/man/man7/cdist-type__apt_update_index.rst deleted file mode 120000 index f2ee88e7..00000000 --- a/docs/man/man7/cdist-type__apt_update_index.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__apt_update_index/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__block.rst b/docs/man/man7/cdist-type__block.rst deleted file mode 120000 index 74d8e18f..00000000 --- a/docs/man/man7/cdist-type__block.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__block/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__ccollect_source.rst b/docs/man/man7/cdist-type__ccollect_source.rst deleted file mode 120000 index 8398eb0f..00000000 --- a/docs/man/man7/cdist-type__ccollect_source.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__ccollect_source/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__cdist.rst b/docs/man/man7/cdist-type__cdist.rst deleted file mode 120000 index 483afed8..00000000 --- a/docs/man/man7/cdist-type__cdist.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__cdist/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__cdistmarker.rst b/docs/man/man7/cdist-type__cdistmarker.rst deleted file mode 120000 index 3b4db6a6..00000000 --- a/docs/man/man7/cdist-type__cdistmarker.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__cdistmarker/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__config_file.rst b/docs/man/man7/cdist-type__config_file.rst deleted file mode 120000 index 714be1a6..00000000 --- a/docs/man/man7/cdist-type__config_file.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__config_file/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul.rst b/docs/man/man7/cdist-type__consul.rst deleted file mode 120000 index 5548772f..00000000 --- a/docs/man/man7/cdist-type__consul.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_agent.rst b/docs/man/man7/cdist-type__consul_agent.rst deleted file mode 120000 index 89101b6e..00000000 --- a/docs/man/man7/cdist-type__consul_agent.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_agent/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_check.rst b/docs/man/man7/cdist-type__consul_check.rst deleted file mode 120000 index 767cfc78..00000000 --- a/docs/man/man7/cdist-type__consul_check.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_check/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_reload.rst b/docs/man/man7/cdist-type__consul_reload.rst deleted file mode 120000 index 9344d259..00000000 --- a/docs/man/man7/cdist-type__consul_reload.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_reload/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_service.rst b/docs/man/man7/cdist-type__consul_service.rst deleted file mode 120000 index 697b6de7..00000000 --- a/docs/man/man7/cdist-type__consul_service.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_service/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_template.rst b/docs/man/man7/cdist-type__consul_template.rst deleted file mode 120000 index 73cb7f66..00000000 --- a/docs/man/man7/cdist-type__consul_template.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_template/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_template_template.rst b/docs/man/man7/cdist-type__consul_template_template.rst deleted file mode 120000 index ea2fa00e..00000000 --- a/docs/man/man7/cdist-type__consul_template_template.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_template_template/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_checks.rst b/docs/man/man7/cdist-type__consul_watch_checks.rst deleted file mode 120000 index 241f2c86..00000000 --- a/docs/man/man7/cdist-type__consul_watch_checks.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_watch_checks/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_event.rst b/docs/man/man7/cdist-type__consul_watch_event.rst deleted file mode 120000 index 710f69bb..00000000 --- a/docs/man/man7/cdist-type__consul_watch_event.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_watch_event/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_key.rst b/docs/man/man7/cdist-type__consul_watch_key.rst deleted file mode 120000 index d3987862..00000000 --- a/docs/man/man7/cdist-type__consul_watch_key.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_watch_key/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_keyprefix.rst b/docs/man/man7/cdist-type__consul_watch_keyprefix.rst deleted file mode 120000 index f5a58339..00000000 --- a/docs/man/man7/cdist-type__consul_watch_keyprefix.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_watch_keyprefix/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_nodes.rst b/docs/man/man7/cdist-type__consul_watch_nodes.rst deleted file mode 120000 index 20b29324..00000000 --- a/docs/man/man7/cdist-type__consul_watch_nodes.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_watch_nodes/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_service.rst b/docs/man/man7/cdist-type__consul_watch_service.rst deleted file mode 120000 index 0965c7ca..00000000 --- a/docs/man/man7/cdist-type__consul_watch_service.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_watch_service/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__consul_watch_services.rst b/docs/man/man7/cdist-type__consul_watch_services.rst deleted file mode 120000 index 06610a8c..00000000 --- a/docs/man/man7/cdist-type__consul_watch_services.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__consul_watch_services/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__cron.rst b/docs/man/man7/cdist-type__cron.rst deleted file mode 120000 index 783ef87d..00000000 --- a/docs/man/man7/cdist-type__cron.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__cron/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__debconf_set_selections.rst b/docs/man/man7/cdist-type__debconf_set_selections.rst deleted file mode 120000 index 88c233ae..00000000 --- a/docs/man/man7/cdist-type__debconf_set_selections.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__debconf_set_selections/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__directory.rst b/docs/man/man7/cdist-type__directory.rst deleted file mode 120000 index 8c25832f..00000000 --- a/docs/man/man7/cdist-type__directory.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__directory/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__dog_vdi.rst b/docs/man/man7/cdist-type__dog_vdi.rst deleted file mode 120000 index 4ffbb2db..00000000 --- a/docs/man/man7/cdist-type__dog_vdi.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__dog_vdi/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__file.rst b/docs/man/man7/cdist-type__file.rst deleted file mode 120000 index 60aa8b88..00000000 --- a/docs/man/man7/cdist-type__file.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__file/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__firewalld_rule.rst b/docs/man/man7/cdist-type__firewalld_rule.rst deleted file mode 120000 index 756b8d20..00000000 --- a/docs/man/man7/cdist-type__firewalld_rule.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__firewalld_rule/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__git.rst b/docs/man/man7/cdist-type__git.rst deleted file mode 120000 index 14057be3..00000000 --- a/docs/man/man7/cdist-type__git.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__git/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__group.rst b/docs/man/man7/cdist-type__group.rst deleted file mode 120000 index a35a5779..00000000 --- a/docs/man/man7/cdist-type__group.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__group/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__hostname.rst b/docs/man/man7/cdist-type__hostname.rst deleted file mode 120000 index 46eaec8b..00000000 --- a/docs/man/man7/cdist-type__hostname.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__hostname/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__iptables_apply.rst b/docs/man/man7/cdist-type__iptables_apply.rst deleted file mode 120000 index cc4c25d7..00000000 --- a/docs/man/man7/cdist-type__iptables_apply.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__iptables_apply/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__iptables_rule.rst b/docs/man/man7/cdist-type__iptables_rule.rst deleted file mode 120000 index 4e5c50f4..00000000 --- a/docs/man/man7/cdist-type__iptables_rule.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__iptables_rule/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__issue.rst b/docs/man/man7/cdist-type__issue.rst deleted file mode 120000 index 9dad6d0d..00000000 --- a/docs/man/man7/cdist-type__issue.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__issue/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__jail.rst b/docs/man/man7/cdist-type__jail.rst deleted file mode 120000 index 75ad8a18..00000000 --- a/docs/man/man7/cdist-type__jail.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__jail/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__key_value.rst b/docs/man/man7/cdist-type__key_value.rst deleted file mode 120000 index 0dd8b882..00000000 --- a/docs/man/man7/cdist-type__key_value.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__key_value/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__line.rst b/docs/man/man7/cdist-type__line.rst deleted file mode 120000 index 3d6b98d5..00000000 --- a/docs/man/man7/cdist-type__line.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__line/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__link.rst b/docs/man/man7/cdist-type__link.rst deleted file mode 120000 index ecb21b4a..00000000 --- a/docs/man/man7/cdist-type__link.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__link/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__locale.rst b/docs/man/man7/cdist-type__locale.rst deleted file mode 120000 index b1506d28..00000000 --- a/docs/man/man7/cdist-type__locale.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__locale/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__motd.rst b/docs/man/man7/cdist-type__motd.rst deleted file mode 120000 index 300ad9bd..00000000 --- a/docs/man/man7/cdist-type__motd.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__motd/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__mount.rst b/docs/man/man7/cdist-type__mount.rst deleted file mode 120000 index e2ee3a56..00000000 --- a/docs/man/man7/cdist-type__mount.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__mount/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__mysql_database.rst b/docs/man/man7/cdist-type__mysql_database.rst deleted file mode 120000 index 3d0ebe5f..00000000 --- a/docs/man/man7/cdist-type__mysql_database.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__mysql_database/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package.rst b/docs/man/man7/cdist-type__package.rst deleted file mode 120000 index da9a827a..00000000 --- a/docs/man/man7/cdist-type__package.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_apt.rst b/docs/man/man7/cdist-type__package_apt.rst deleted file mode 120000 index c1c21110..00000000 --- a/docs/man/man7/cdist-type__package_apt.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_apt/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_emerge.rst b/docs/man/man7/cdist-type__package_emerge.rst deleted file mode 120000 index 33312455..00000000 --- a/docs/man/man7/cdist-type__package_emerge.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_emerge/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_emerge_dependencies.rst b/docs/man/man7/cdist-type__package_emerge_dependencies.rst deleted file mode 120000 index 785ccd97..00000000 --- a/docs/man/man7/cdist-type__package_emerge_dependencies.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_emerge_dependencies/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_luarocks.rst b/docs/man/man7/cdist-type__package_luarocks.rst deleted file mode 120000 index e87cc0ee..00000000 --- a/docs/man/man7/cdist-type__package_luarocks.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_luarocks/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_opkg.rst b/docs/man/man7/cdist-type__package_opkg.rst deleted file mode 120000 index 0ea6199b..00000000 --- a/docs/man/man7/cdist-type__package_opkg.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_opkg/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pacman.rst b/docs/man/man7/cdist-type__package_pacman.rst deleted file mode 120000 index 30d0efd1..00000000 --- a/docs/man/man7/cdist-type__package_pacman.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_pacman/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pip.rst b/docs/man/man7/cdist-type__package_pip.rst deleted file mode 120000 index 1d8202ff..00000000 --- a/docs/man/man7/cdist-type__package_pip.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_pip/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pkg_freebsd.rst b/docs/man/man7/cdist-type__package_pkg_freebsd.rst deleted file mode 120000 index 2fcbb36b..00000000 --- a/docs/man/man7/cdist-type__package_pkg_freebsd.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_pkg_freebsd/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pkg_openbsd.rst b/docs/man/man7/cdist-type__package_pkg_openbsd.rst deleted file mode 120000 index 01676166..00000000 --- a/docs/man/man7/cdist-type__package_pkg_openbsd.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_pkg_openbsd/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_pkgng_freebsd.rst b/docs/man/man7/cdist-type__package_pkgng_freebsd.rst deleted file mode 120000 index 2cac19eb..00000000 --- a/docs/man/man7/cdist-type__package_pkgng_freebsd.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_pkgng_freebsd/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_rubygem.rst b/docs/man/man7/cdist-type__package_rubygem.rst deleted file mode 120000 index e9b394fd..00000000 --- a/docs/man/man7/cdist-type__package_rubygem.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_rubygem/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_update_index.rst b/docs/man/man7/cdist-type__package_update_index.rst deleted file mode 120000 index 1d4175a9..00000000 --- a/docs/man/man7/cdist-type__package_update_index.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_update_index/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_upgrade_all.rst b/docs/man/man7/cdist-type__package_upgrade_all.rst deleted file mode 120000 index 7fb535e2..00000000 --- a/docs/man/man7/cdist-type__package_upgrade_all.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_upgrade_all/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_yum.rst b/docs/man/man7/cdist-type__package_yum.rst deleted file mode 120000 index eebce5b1..00000000 --- a/docs/man/man7/cdist-type__package_yum.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_yum/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__package_zypper.rst b/docs/man/man7/cdist-type__package_zypper.rst deleted file mode 120000 index b35d0f25..00000000 --- a/docs/man/man7/cdist-type__package_zypper.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__package_zypper/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pacman_conf.rst b/docs/man/man7/cdist-type__pacman_conf.rst deleted file mode 120000 index 99901486..00000000 --- a/docs/man/man7/cdist-type__pacman_conf.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__pacman_conf/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pacman_conf_integrate.rst b/docs/man/man7/cdist-type__pacman_conf_integrate.rst deleted file mode 120000 index 298576dc..00000000 --- a/docs/man/man7/cdist-type__pacman_conf_integrate.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__pacman_conf_integrate/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pf_apply.rst b/docs/man/man7/cdist-type__pf_apply.rst deleted file mode 120000 index 6897ffad..00000000 --- a/docs/man/man7/cdist-type__pf_apply.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__pf_apply/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pf_ruleset.rst b/docs/man/man7/cdist-type__pf_ruleset.rst deleted file mode 120000 index 6f484a26..00000000 --- a/docs/man/man7/cdist-type__pf_ruleset.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__pf_ruleset/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix.rst b/docs/man/man7/cdist-type__postfix.rst deleted file mode 120000 index 43001302..00000000 --- a/docs/man/man7/cdist-type__postfix.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__postfix/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix_master.rst b/docs/man/man7/cdist-type__postfix_master.rst deleted file mode 120000 index 7e35f771..00000000 --- a/docs/man/man7/cdist-type__postfix_master.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__postfix_master/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix_postconf.rst b/docs/man/man7/cdist-type__postfix_postconf.rst deleted file mode 120000 index 2e66b0fc..00000000 --- a/docs/man/man7/cdist-type__postfix_postconf.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__postfix_postconf/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix_postmap.rst b/docs/man/man7/cdist-type__postfix_postmap.rst deleted file mode 120000 index 5fab5328..00000000 --- a/docs/man/man7/cdist-type__postfix_postmap.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__postfix_postmap/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postfix_reload.rst b/docs/man/man7/cdist-type__postfix_reload.rst deleted file mode 120000 index b60fc927..00000000 --- a/docs/man/man7/cdist-type__postfix_reload.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__postfix_reload/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postgres_database.rst b/docs/man/man7/cdist-type__postgres_database.rst deleted file mode 120000 index 22697ebb..00000000 --- a/docs/man/man7/cdist-type__postgres_database.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__postgres_database/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__postgres_role.rst b/docs/man/man7/cdist-type__postgres_role.rst deleted file mode 120000 index ffd8cfc2..00000000 --- a/docs/man/man7/cdist-type__postgres_role.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__postgres_role/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__process.rst b/docs/man/man7/cdist-type__process.rst deleted file mode 120000 index 6385603a..00000000 --- a/docs/man/man7/cdist-type__process.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__process/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__pyvenv.rst b/docs/man/man7/cdist-type__pyvenv.rst deleted file mode 120000 index b7fdf05e..00000000 --- a/docs/man/man7/cdist-type__pyvenv.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__pyvenv/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__qemu_img.rst b/docs/man/man7/cdist-type__qemu_img.rst deleted file mode 120000 index 88797991..00000000 --- a/docs/man/man7/cdist-type__qemu_img.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__qemu_img/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rbenv.rst b/docs/man/man7/cdist-type__rbenv.rst deleted file mode 120000 index 6f990abf..00000000 --- a/docs/man/man7/cdist-type__rbenv.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__rbenv/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rsync.rst b/docs/man/man7/cdist-type__rsync.rst deleted file mode 120000 index c581bd7b..00000000 --- a/docs/man/man7/cdist-type__rsync.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__rsync/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rvm.rst b/docs/man/man7/cdist-type__rvm.rst deleted file mode 120000 index ad7c1fde..00000000 --- a/docs/man/man7/cdist-type__rvm.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__rvm/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rvm_gem.rst b/docs/man/man7/cdist-type__rvm_gem.rst deleted file mode 120000 index fd1c83c1..00000000 --- a/docs/man/man7/cdist-type__rvm_gem.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__rvm_gem/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rvm_gemset.rst b/docs/man/man7/cdist-type__rvm_gemset.rst deleted file mode 120000 index 49da138a..00000000 --- a/docs/man/man7/cdist-type__rvm_gemset.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__rvm_gemset/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__rvm_ruby.rst b/docs/man/man7/cdist-type__rvm_ruby.rst deleted file mode 120000 index 48fec75d..00000000 --- a/docs/man/man7/cdist-type__rvm_ruby.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__rvm_ruby/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__ssh_authorized_key.rst b/docs/man/man7/cdist-type__ssh_authorized_key.rst deleted file mode 120000 index b82695cb..00000000 --- a/docs/man/man7/cdist-type__ssh_authorized_key.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__ssh_authorized_key/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__ssh_authorized_keys.rst b/docs/man/man7/cdist-type__ssh_authorized_keys.rst deleted file mode 120000 index 71794a71..00000000 --- a/docs/man/man7/cdist-type__ssh_authorized_keys.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__ssh_authorized_keys/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__ssh_dot_ssh.rst b/docs/man/man7/cdist-type__ssh_dot_ssh.rst deleted file mode 120000 index e88fc415..00000000 --- a/docs/man/man7/cdist-type__ssh_dot_ssh.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__ssh_dot_ssh/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__staged_file.rst b/docs/man/man7/cdist-type__staged_file.rst deleted file mode 120000 index 17e94c67..00000000 --- a/docs/man/man7/cdist-type__staged_file.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__staged_file/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__start_on_boot.rst b/docs/man/man7/cdist-type__start_on_boot.rst deleted file mode 120000 index f0223931..00000000 --- a/docs/man/man7/cdist-type__start_on_boot.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__start_on_boot/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__timezone.rst b/docs/man/man7/cdist-type__timezone.rst deleted file mode 120000 index fd6db767..00000000 --- a/docs/man/man7/cdist-type__timezone.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__timezone/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__update_alternatives.rst b/docs/man/man7/cdist-type__update_alternatives.rst deleted file mode 120000 index 6337c09d..00000000 --- a/docs/man/man7/cdist-type__update_alternatives.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__update_alternatives/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__user.rst b/docs/man/man7/cdist-type__user.rst deleted file mode 120000 index feea364d..00000000 --- a/docs/man/man7/cdist-type__user.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__user/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__user_groups.rst b/docs/man/man7/cdist-type__user_groups.rst deleted file mode 120000 index 92de8259..00000000 --- a/docs/man/man7/cdist-type__user_groups.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__user_groups/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__yum_repo.rst b/docs/man/man7/cdist-type__yum_repo.rst deleted file mode 120000 index 213fc81e..00000000 --- a/docs/man/man7/cdist-type__yum_repo.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__yum_repo/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__zypper_repo.rst b/docs/man/man7/cdist-type__zypper_repo.rst deleted file mode 120000 index 8e6e7d14..00000000 --- a/docs/man/man7/cdist-type__zypper_repo.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__zypper_repo/man.rst \ No newline at end of file diff --git a/docs/man/man7/cdist-type__zypper_service.rst b/docs/man/man7/cdist-type__zypper_service.rst deleted file mode 120000 index 7b238e8f..00000000 --- a/docs/man/man7/cdist-type__zypper_service.rst +++ /dev/null @@ -1 +0,0 @@ -../../../cdist/conf/type/__zypper_service/man.rst \ No newline at end of file From 871d323b3dfced3a9c432152fedf86c2e0313f3c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 25 May 2016 10:52:53 +0200 Subject: [PATCH 0133/1332] Update .gitignore: test->rst. --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9c3594f7..2a193c2a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,8 +8,8 @@ docs/man/man7/*.7 docs/man/man*/*.html docs/man/man*/*.xml docs/man/man*/docbook-xsl.css -docs/man/man7/cdist-type__*.text -docs/man/man7/cdist-reference.text +docs/man/man7/cdist-type__*.rst +docs/man/man7/cdist-reference.rst # Ignore cdist cache for version control /cache/ From dbcdc8a8ba9696412bf2a8fc7702fe515177f0bd Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 25 May 2016 14:39:40 +0200 Subject: [PATCH 0134/1332] use pool.sks-keyservers.net instead of subkeys.pgp.net Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_key/parameter/default/keyserver | 2 +- docs/changelog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_key/parameter/default/keyserver b/cdist/conf/type/__apt_key/parameter/default/keyserver index f851282c..0d189916 100644 --- a/cdist/conf/type/__apt_key/parameter/default/keyserver +++ b/cdist/conf/type/__apt_key/parameter/default/keyserver @@ -1 +1 @@ -subkeys.pgp.net +pool.sks-keyservers.net diff --git a/docs/changelog b/docs/changelog index a63c05d7..a22eba62 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Documentation: Migrate to reStructuredText format and sphinx (Darko Poljak) * Core: Add -f option to read additional hosts from file/stdin (Darko Poljak) + * Type __apt_key: Use pool.sks-keyservers.net as keyserver (Steven Armstrong) 4.0.0: 2016-05-04 * Core: Fix bug with parallel hosts operation when output path is specifed (Darko Poljak) From 8818d2fece0a0aef6ec26e49a9ff9c586b33b8be Mon Sep 17 00:00:00 2001 From: Chris Lamb Date: Thu, 26 May 2016 18:48:29 +0100 Subject: [PATCH 0135/1332] Ensure build of reference documentation is reproducible. Signed-off-by: Chris Lamb --- docs/man/cdist-reference.rst.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/man/cdist-reference.rst.sh b/docs/man/cdist-reference.rst.sh index ae73169e..132d37b4 100755 --- a/docs/man/cdist-reference.rst.sh +++ b/docs/man/cdist-reference.rst.sh @@ -49,7 +49,7 @@ The following global explorers are available: eof ( cd ../../cdist/conf/explorer - for explorer in *; do + for explorer in $(ls * | LC_ALL=C sort); do echo "- $explorer" done ) @@ -157,7 +157,7 @@ The following types are available: eof -for type in man7/cdist-type__*.rst; do +for type in $(ls man7/cdist-type__*.rst | LC_ALL=C sort); do no_dir="${type#man7/}"; no_type="${no_dir#cdist-type}"; name="${no_type%.rst}"; From ab74da9c294c1cfc302f2e0bd920b365aa3e5a04 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 27 May 2016 07:26:42 +0200 Subject: [PATCH 0136/1332] Prepare for new release. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index a22eba62..dada1d90 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.1.0: 2016-05-27 * Documentation: Migrate to reStructuredText format and sphinx (Darko Poljak) * Core: Add -f option to read additional hosts from file/stdin (Darko Poljak) * Type __apt_key: Use pool.sks-keyservers.net as keyserver (Steven Armstrong) From 2f68e21a96a5a09fd6b99512cdf73b2e00b5458c Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Sun, 5 Jun 2016 21:57:21 -0400 Subject: [PATCH 0137/1332] Add support for FreeBSD 10.x jails Separate __jail type into distinct __jail_freebsd9 and __jail_freebsd10 types --- cdist/conf/type/__jail/manifest | 13 + .../explorer/basepresent | 0 .../explorer/present | 0 .../explorer/status | 0 .../conf/type/__jail_freebsd10/gencode-local | 52 +++ .../conf/type/__jail_freebsd10/gencode-remote | 362 ++++++++++++++++++ cdist/conf/type/__jail_freebsd10/man.text | 119 ++++++ .../type/__jail_freebsd10/parameter/boolean | 3 + .../parameter/default/devfs-ruleset | 1 + .../parameter/default/jailbase | 1 + .../parameter/default/jaildir | 1 + .../__jail_freebsd10/parameter/default/state | 1 + .../type/__jail_freebsd10/parameter/optional | 8 + .../type/__jail_freebsd9/explorer/basepresent | 54 +++ .../type/__jail_freebsd9/explorer/present | 43 +++ .../conf/type/__jail_freebsd9/explorer/status | 52 +++ .../{__jail => __jail_freebsd9}/gencode-local | 0 .../gencode-remote | 7 +- cdist/conf/type/__jail_freebsd9/man.text | 120 ++++++ .../type/__jail_freebsd9/parameter/boolean | 3 + .../parameter/default/devfs-ruleset | 1 + .../parameter/default/jailbase | 1 + .../__jail_freebsd9/parameter/default/jaildir | 1 + .../__jail_freebsd9/parameter/default/state | 1 + .../type/__jail_freebsd9/parameter/optional | 8 + cdist/conf/type/__package/parameter/boolean | 1 + cdist/conf/type/__package/parameter/optional | 1 + 27 files changed, 851 insertions(+), 3 deletions(-) rename cdist/conf/type/{__jail => __jail_freebsd10}/explorer/basepresent (100%) rename cdist/conf/type/{__jail => __jail_freebsd10}/explorer/present (100%) rename cdist/conf/type/{__jail => __jail_freebsd10}/explorer/status (100%) create mode 100755 cdist/conf/type/__jail_freebsd10/gencode-local create mode 100755 cdist/conf/type/__jail_freebsd10/gencode-remote create mode 100644 cdist/conf/type/__jail_freebsd10/man.text create mode 100644 cdist/conf/type/__jail_freebsd10/parameter/boolean create mode 100644 cdist/conf/type/__jail_freebsd10/parameter/default/devfs-ruleset create mode 100644 cdist/conf/type/__jail_freebsd10/parameter/default/jailbase create mode 100644 cdist/conf/type/__jail_freebsd10/parameter/default/jaildir create mode 100644 cdist/conf/type/__jail_freebsd10/parameter/default/state create mode 100644 cdist/conf/type/__jail_freebsd10/parameter/optional create mode 100755 cdist/conf/type/__jail_freebsd9/explorer/basepresent create mode 100755 cdist/conf/type/__jail_freebsd9/explorer/present create mode 100755 cdist/conf/type/__jail_freebsd9/explorer/status rename cdist/conf/type/{__jail => __jail_freebsd9}/gencode-local (100%) rename cdist/conf/type/{__jail => __jail_freebsd9}/gencode-remote (98%) create mode 100644 cdist/conf/type/__jail_freebsd9/man.text create mode 100644 cdist/conf/type/__jail_freebsd9/parameter/boolean create mode 100644 cdist/conf/type/__jail_freebsd9/parameter/default/devfs-ruleset create mode 100644 cdist/conf/type/__jail_freebsd9/parameter/default/jailbase create mode 100644 cdist/conf/type/__jail_freebsd9/parameter/default/jaildir create mode 100644 cdist/conf/type/__jail_freebsd9/parameter/default/state create mode 100644 cdist/conf/type/__jail_freebsd9/parameter/optional create mode 100644 cdist/conf/type/__package/parameter/boolean diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index 2d29e263..6df52c59 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -37,6 +37,19 @@ jaildir="$(cat "$__object/parameter/jaildir")" __directory ${jaildir} --parents +set -- "$@" "$__object_id" "--state" "$state" +cd "$__object/parameter" +for property in $(ls .); do + set -- "$@" "--$property" "$(cat "$property")" +done + +ver="$(cat "$__global/explorer/os_version")" +if [ -n "$(echo "$ver" | grep '^10\.' )" ]; then # Version is 10.x + __jail_freebsd10 "$@" +else + __jail_freebsd9 "$@" +fi + # Debug #set +x diff --git a/cdist/conf/type/__jail/explorer/basepresent b/cdist/conf/type/__jail_freebsd10/explorer/basepresent similarity index 100% rename from cdist/conf/type/__jail/explorer/basepresent rename to cdist/conf/type/__jail_freebsd10/explorer/basepresent diff --git a/cdist/conf/type/__jail/explorer/present b/cdist/conf/type/__jail_freebsd10/explorer/present similarity index 100% rename from cdist/conf/type/__jail/explorer/present rename to cdist/conf/type/__jail_freebsd10/explorer/present diff --git a/cdist/conf/type/__jail/explorer/status b/cdist/conf/type/__jail_freebsd10/explorer/status similarity index 100% rename from cdist/conf/type/__jail/explorer/status rename to cdist/conf/type/__jail_freebsd10/explorer/status diff --git a/cdist/conf/type/__jail_freebsd10/gencode-local b/cdist/conf/type/__jail_freebsd10/gencode-local new file mode 100755 index 00000000..a88e8ae4 --- /dev/null +++ b/cdist/conf/type/__jail_freebsd10/gencode-local @@ -0,0 +1,52 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.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 . +# +# +# The __jail type creates, configures, and deletes FreeBSD jails for use as +# virtual machines. +# + +# Debug +exec >&2 +set -x + +jaildir="$(cat "$__object/parameter/jaildir")" + +jailbase="$(cat "$__object/parameter/jailbase")" + +state="$(cat "$__object/parameter/state")" + +if [ "$state" = "present" ] && [ -z "$jailbase" ]; then + exec >&2 + echo "jailbase is a REQUIRED parameter when state=present!" + exit 1 +fi + +remotebase="${jaildir}/jailbase.tgz" +basepresent="$(cat "$__object/explorer/basepresent")" + +if [ "$state" = "present" ]; then + if [ "$basepresent" = "NONE" ]; then + echo "$__remote_copy" "${jailbase}" "$__target_host:${remotebase}" + fi # basepresent=NONE +fi # state=present + +# Debug +set +x + diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote new file mode 100755 index 00000000..ae68616d --- /dev/null +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -0,0 +1,362 @@ +#!/bin/sh +# +# 2012,2014,2016 Jake Guffey (jake.guffey at jointheirstm.org) +# +# 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 . +# +# +# The __jail_freebsd10 type creates, configures, and deletes FreeBSD +# jails for use as virtual machines on FreeBSD 10.x. +# + +# Debug +#exec >&2 +#set -x + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +state="$(cat "$__object/parameter/state")" + +started="true" +# If the user wants the jail gone, it implies it shouldn't be started. +[ -f "$__object/parameter/stopped" -o "$state" = "absent" ] && started="false" + +if [ -f "$__object/parameter/ip" ]; then + ip="$(cat "$__object/parameter/ip")" +else +# IP is an optional param when $state=absent, but +# when $state=present, it's required. Enforce this. + if [ "$state" = "present" ]; then + exec >&2 + echo "If --state is 'present,' --ip must be given\!" + exit 1 + fi +fi + +if [ -f "$__object/parameter/hostname" ]; then + hostname="$(cat "$__object/parameter/hostname")" +else + hostname="$name" +fi + +if [ -f "$__object/parameter/devfs-disable" ]; then + devfsenable="false" +else + devfsenable="true" +fi + +devfsruleset="$(cat "$__object/parameter/devfs-ruleset")" + +# devfs_ruleset being defined without devfs_enable being true +# is pointless. Treat this as an error. +if [ -n "$devfsruleset" -a "$devfsenable" = "false" ]; then + exec >&2 + echo "Can't have --devfs-ruleset defined with --devfs-disable" + exit 1 +fi + +if [ -f "$__object/parameter/onboot" ]; then + onboot="true" +fi + +jaildir="$(cat "$__object/parameter/jaildir")" + +present="$(cat "$__object/explorer/present")" +#present="$(cat "$__type/explorer/present")" +status="$(cat "$__object/explorer/status")" + +# Handle ip="addr, addr" format +if [ $(expr "${ip}" : ".*, .*") -gt "0" ]; then + SAVE_IFS="$IFS" + IFS=", " + for cur_ip in ${ip}; do + # Just get the last IP address for SSH to listen on + mgmt_ip=$(echo "${ip}" | cut '-d ' -f1) # In case using "ip netmask" format rather than CIDR + done + IFS="$SAVE_IFS" +else + mgmt_ip=$(echo "${ip}" | cut '-d ' -f1) # In case using "ip netmask" format rather than CIDR +fi + +stopJail() { +# Check $status before issuing command + if [ "$status" = "STARTED" ]; then + echo "/etc/rc.d/jail stop ${name}" + echo "stop" >> "$__messages_out" + fi +} + +startJail() { +# Check $status before issuing command + if [ "$status" = "NOTSTART" ]; then + echo "/etc/rc.d/jail start ${name}" + echo "start" >> "$__messages_out" + fi +} + +deleteJail() { +# Unmount the jail's mountpoints if necessary + cat <=1 rw mount is mounted still + for DIR in "${output}"; do + umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print $3}')" + done + fi + output="\$(mount | grep "\/${name} (")" || true + if [ -n "\${output}" ]; then # ro mount is mounted still + umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print $3}')" + fi +EOF +# Remove the jail's rw mountpoints + echo "rm -rf \"${jaildir}/rw/${name}\"" +# Remove the jail directory + echo "rm -rf \"${jaildir}/${name}\"" +# Remove the jail's fstab + echo "rm -f \"/etc/fstab.${name}\"" +# Remove jail entry from jail.conf + cat <> "$__messages_out" +} + +createJail() { +# Create the jail directory +cat <> "$__messages_out" + +# Create the ro+rw mountpoint entries in fstab +cat </etc/fstab.${name} <>/etc/rc.conf + elif [ ! "\$(echo \$jail_enable | tr '[a-z]' '[A-Z]' | tr -d '"')" = "YES" ]; then # jail_enable="NO" + sed -i '.bak' 's/^jail_enable=.*$/jail_enable="YES"/g' /etc/rc.conf # fix this -^ + rm -f /etc/rc.conf.bak + fi + + jailfile=/etc/jail.conf + jailheader="${name} {" + + jaildata="path=\"${jaildir}/${name}\";" + + if [ "$devfsenable" = "true" ]; then + jaildata="\$jaildata + mount.devfs;" + else + jaildata="\$jaildata + mount.nodevfs;" + fi + + jaildata="\$jaildata + host.hostname=\"${hostname}\"; + ip4.addr=\"${ip}\"; + exec.start=\"/bin/sh /etc/rc\"; + exec.stop=\"/bin/sh /etc/rc.shutdown\"; + exec.consolelog=\"/var/log/jail_${name}_console.log\"; + mount.fstab=\"/etc/fstab.${name}\"; + allow.mount; + exec.clean; + allow.set_hostname=0; + allow.sysvipc=0; + allow.raw_sockets=0;" + + jailtrailer="}" + + if [ "$devfsenable" = "true" ] && [ "${devfsruleset}" = "jailrules" ]; then # The default ruleset is to be used + if [ ! -f /etc/devfs.rules ]; then + touch /etc/devfs.rules + fi + if [ -z "\$(grep '\[jailrules=' /etc/devfs.rules)" ]; then # The default ruleset doesn't exist + # Get the highest-numbered ruleset + highest="\$(sed -n 's/\[.*=\([0-9]*\)\]/\1/pg' /etc/devfs.rules | sort -u | tail -n 1)" || true + # increment by 1 + [ -z "\$highest" ] && highest=10 + let num="\${highest}+1" 2>&1 >/dev/null # Close the FD==fail... + # add default ruleset + cat >>/etc/devfs.rules <>\"\$jailfile\"" + +# Add $name to jail_list if $onboot=yes +if [ "$onboot" = "yes" ]; then + + # first check to see whether jail_enable="YES" exists in rc.conf or not and add it + # if necessary + + cat <> "$__messages_out" +fi + +# Add the normal entries into the jail's rc.conf +cat <"${jaildir}/rw/${name}/etc/rc.conf" +echo sshd_enable=\"YES\" >>"${jaildir}/rw/${name}/etc/rc.conf" +echo sendmail_enable=\"NONE\" >>"${jaildir}/rw/${name}/etc/rc.conf" +echo syslogd_enable=\"YES\" >>"${jaildir}/rw/${name}/etc/rc.conf" +echo syslogd_flags=\"-ss\" >>"${jaildir}/rw/${name}/etc/rc.conf" + +EOF +# Configure SSHd's listening address +cat < + + +NAME +---- +cdist-type__jail_freebsd_10 - Manage FreeBSD jails + + +DESCRIPTION +----------- +This type is used on FreeBSD 10.x to manage jails. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "present" or "absent", defaults to "present". + +jailbase:: + The location of the .tgz archive containing the base fs for your jails. + + +OPTIONAL PARAMETERS +------------------- +name:: + The name of the jail. Default is to use the object_id as the jail name. + +ip:: + The ifconfig style IP/netmask combination to use for the jail guest. If + the state parameter is "present," this parameter is required. + +hostname:: + The FQDN to use for the jail guest. Defaults to the name parameter. + +interface:: + The name of the physical interface on the jail server to bind the jail to. + Defaults to the first interface found in the output of ifconfig -l. + +devfs-ruleset:: + The name of the devfs ruleset to associate with the jail. Defaults to + "jailrules." This ruleset must be copied to the server via another type. + To use this option, devfs-enable must be "true." + +jaildir:: + The location on the remote server to use for hosting jail filesystems. + Defaults to /usr/jail. + +BOOLEAN PARAMETERS +------------------ +stopped:: + Do not start the jail + +devfs-disable:: + Whether to disallow devfs mounting within the jail + +onboot:: + Whether to add the jail to rc.conf's jail_list variable. + + +CAVEATS +------- +This type does not currently support modification of jail options. If, for +example a jail needs to have its IP address or netmask changed, the jail must +be removed then re-added with the correct IP address/netmask or the appropriate +modifications to jail.conf need to be made through alternate means. + +MESSAGES +-------- +start:: + The jail was started +stop:: + The jail was stopped +create: + The jail was created +delete:: + The jail was deleted +onboot:: + The jail was configured to start on boot + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Create a jail called www +__jail_freebsd_10 www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz + +# Remove the jail called www +__jail_freebsd_10 www --state absent --jailbase /my/jail/base.tgz + +# The jail www should not be started +__jail_freebsd_10 www --state present --stopped \ + --ip "192.168.1.2 netmask 255.255.255.0" \ + --jailbase /my/jail/base.tgz + +# Use the name variable explicitly +__jail_freebsd_10 thisjail --state present --name www \ + --ip "192.168.1.2" \ + --jailbase /my/jail/base.tgz + +# Go nuts +__jail_freebsd_10 lotsofoptions --state present --name testjail \ + --ip "192.168.1.100 netmask 255.255.255.0" \ + --hostname "testjail.example.com" --interface "em0" \ + --onboot --jailbase /my/jail/base.tgz --jaildir /jails +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__jail(7) + + +COPYING +------- +Copyright \(C) 2012-2016 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__jail_freebsd10/parameter/boolean b/cdist/conf/type/__jail_freebsd10/parameter/boolean new file mode 100644 index 00000000..39144f6f --- /dev/null +++ b/cdist/conf/type/__jail_freebsd10/parameter/boolean @@ -0,0 +1,3 @@ +onboot +stopped +devfs-disable diff --git a/cdist/conf/type/__jail_freebsd10/parameter/default/devfs-ruleset b/cdist/conf/type/__jail_freebsd10/parameter/default/devfs-ruleset new file mode 100644 index 00000000..f602aa0a --- /dev/null +++ b/cdist/conf/type/__jail_freebsd10/parameter/default/devfs-ruleset @@ -0,0 +1 @@ +jailrules diff --git a/cdist/conf/type/__jail_freebsd10/parameter/default/jailbase b/cdist/conf/type/__jail_freebsd10/parameter/default/jailbase new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__jail_freebsd10/parameter/default/jailbase @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__jail_freebsd10/parameter/default/jaildir b/cdist/conf/type/__jail_freebsd10/parameter/default/jaildir new file mode 100644 index 00000000..ec7d86c6 --- /dev/null +++ b/cdist/conf/type/__jail_freebsd10/parameter/default/jaildir @@ -0,0 +1 @@ +/usr/jail diff --git a/cdist/conf/type/__jail_freebsd10/parameter/default/state b/cdist/conf/type/__jail_freebsd10/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__jail_freebsd10/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__jail_freebsd10/parameter/optional b/cdist/conf/type/__jail_freebsd10/parameter/optional new file mode 100644 index 00000000..b36f0fa5 --- /dev/null +++ b/cdist/conf/type/__jail_freebsd10/parameter/optional @@ -0,0 +1,8 @@ +name +ip +hostname +interface +devfs-ruleset +jaildir +jailbase +state diff --git a/cdist/conf/type/__jail_freebsd9/explorer/basepresent b/cdist/conf/type/__jail_freebsd9/explorer/basepresent new file mode 100755 index 00000000..034128d5 --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/explorer/basepresent @@ -0,0 +1,54 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.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 . +# +# +# See if the jailbase.tgz or $jaildir/base dir exists +# + +# Debug +#exec >&2 +#set -x + +if [ -f "$__object/parameter/jaildir" ]; then + jaildir="$(cat "$__object/parameter/jaildir")" +else + jaildir="/usr/jail" +fi + +name="base:jailbase.tgz" +out="" + +save_IFS="$IFS" +IFS=":" +for cur in $name; do + if [ -e "${jaildir}/$cur" ]; then + out="${out}:${cur}" + fi +done +IFS="$save_IFS" + +if [ -z "$out" ]; then + echo "NONE" +else + echo "${out}" +fi + +# Debug +#set +x + diff --git a/cdist/conf/type/__jail_freebsd9/explorer/present b/cdist/conf/type/__jail_freebsd9/explorer/present new file mode 100755 index 00000000..ddfb805c --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/explorer/present @@ -0,0 +1,43 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.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 . +# +# +# See if the requested jail exists +# + +# Debug +#exec >&2 +#set -x + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name=$__object_id +fi + +if [ -f "$__object/parameter/jaildir" ]; then + jaildir="$(cat "$__object/parameter/jaildir")" +else + jaildir="/usr/jail" +fi + +[ -d "${jaildir}/$name" ] && echo "EXISTS" || echo "NOTEXIST" + +#set +x + diff --git a/cdist/conf/type/__jail_freebsd9/explorer/status b/cdist/conf/type/__jail_freebsd9/explorer/status new file mode 100755 index 00000000..1ceba212 --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/explorer/status @@ -0,0 +1,52 @@ +#!/bin/sh +# +# 2012 Jake Guffey (jake.guffey at eprotex.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 . +# +# +# See if the requested jail is started +# + +# Debug +#exec >&2 +#set -x + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +if [ -f "$__object/parameter/jaildir" ]; then + jaildir="$(cat "$__object/parameter/jaildir")" +else + jaildir="/usr/jail" +fi +# backslash-escaped $jaildir +sjaildir="$(echo ${jaildir} | sed 's#/#\\/#g')" + +jls_output="$(jls | grep "[ ]${sjaildir}\/${name}\$")" || true + +if [ -n "${jls_output}" ]; then + echo "STARTED" +else + echo "NOTSTART" +fi + +# Debug +#set +x + diff --git a/cdist/conf/type/__jail/gencode-local b/cdist/conf/type/__jail_freebsd9/gencode-local similarity index 100% rename from cdist/conf/type/__jail/gencode-local rename to cdist/conf/type/__jail_freebsd9/gencode-local diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote similarity index 98% rename from cdist/conf/type/__jail/gencode-remote rename to cdist/conf/type/__jail_freebsd9/gencode-remote index c88f3361..6a4c64de 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012,2014 Jake Guffey (jake.guffey at eprotex.com) +# 2012,2014,2016 Jake Guffey (jake.guffey at jointheirstm.org) # # This file is part of cdist. # @@ -18,8 +18,8 @@ # along with cdist. If not, see . # # -# The __jail type creates, configures, and deletes FreeBSD jails for use as -# virtual machines. +# The __jail_freebsd9 type creates, configures, and deletes FreeBSD jails +# for use as virtual machines on FreeBSD 9.x and before. # # Debug @@ -354,3 +354,4 @@ else # The jail does not currently exist exit 0 fi fi + diff --git a/cdist/conf/type/__jail_freebsd9/man.text b/cdist/conf/type/__jail_freebsd9/man.text new file mode 100644 index 00000000..c51f326d --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/man.text @@ -0,0 +1,120 @@ +cdist-type__jail_freebsd9(7) +============================ +Jake Guffey + + +NAME +---- +cdist-type__jail_freebsd9 - Manage FreeBSD jails + + +DESCRIPTION +----------- +This type is used on FreeBSD 9.x and before to manage jails. + + +REQUIRED PARAMETERS +------------------- +state:: + Either "present" or "absent", defaults to "present". + +jailbase:: + The location of the .tgz archive containing the base fs for your jails. + + +OPTIONAL PARAMETERS +------------------- +name:: + The name of the jail. Default is to use the object_id as the jail name. + +ip:: + The ifconfig style IP/netmask combination to use for the jail guest. If + the state parameter is "present," this parameter is required. + +hostname:: + The FQDN to use for the jail guest. Defaults to the name parameter. + +interface:: + The name of the physical interface on the jail server to bind the jail to. + Defaults to the first interface found in the output of ifconfig -l. + +devfs-ruleset:: + The name of the devfs ruleset to associate with the jail. Defaults to + "jailrules." This ruleset must be copied to the server via another type. + To use this option, devfs-enable must be "true." + +jaildir:: + The location on the remote server to use for hosting jail filesystems. + Defaults to /usr/jail. + +BOOLEAN PARAMETERS +------------------ +stopped:: + Do not start the jail + +devfs-disable:: + Whether to disallow devfs mounting within the jail + +onboot:: + Whether to add the jail to rc.conf's jail_list variable. + + +CAVEATS +------- +This type does not currently support modification of jail options. If, for +example a jail needs to have its IP address or netmask changed, the jail must +be removed then re-added with the correct IP address/netmask or the appropriate +line (jail__ip="...") modified within rc.conf through some alternate +means. + +MESSAGES +-------- +start:: + The jail was started +stop:: + The jail was stopped +create: + The jail was created +delete:: + The jail was deleted +onboot:: + The jail was configured to start on boot + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Create a jail called www +__jail_freebsd9 www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz + +# Remove the jail called www +__jail_freebsd9 www --state absent --jailbase /my/jail/base.tgz + +# The jail www should not be started +__jail_freebsd9 www --state present --stopped \ + --ip "192.168.1.2 netmask 255.255.255.0" \ + --jailbase /my/jail/base.tgz + +# Use the name variable explicitly +__jail_freebsd9 thisjail --state present --name www \ + --ip "192.168.1.2" \ + --jailbase /my/jail/base.tgz + +# Go nuts +__jail_freebsd9 lotsofoptions --state present --name testjail \ + --ip "192.168.1.100 netmask 255.255.255.0" \ + --hostname "testjail.example.com" --interface "em0" \ + --onboot --jailbase /my/jail/base.tgz --jaildir /jails +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__jail + + +COPYING +------- +Copyright \(C) 2012-2016 Jake Guffey. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__jail_freebsd9/parameter/boolean b/cdist/conf/type/__jail_freebsd9/parameter/boolean new file mode 100644 index 00000000..39144f6f --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/parameter/boolean @@ -0,0 +1,3 @@ +onboot +stopped +devfs-disable diff --git a/cdist/conf/type/__jail_freebsd9/parameter/default/devfs-ruleset b/cdist/conf/type/__jail_freebsd9/parameter/default/devfs-ruleset new file mode 100644 index 00000000..f602aa0a --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/parameter/default/devfs-ruleset @@ -0,0 +1 @@ +jailrules diff --git a/cdist/conf/type/__jail_freebsd9/parameter/default/jailbase b/cdist/conf/type/__jail_freebsd9/parameter/default/jailbase new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/parameter/default/jailbase @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__jail_freebsd9/parameter/default/jaildir b/cdist/conf/type/__jail_freebsd9/parameter/default/jaildir new file mode 100644 index 00000000..ec7d86c6 --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/parameter/default/jaildir @@ -0,0 +1 @@ +/usr/jail diff --git a/cdist/conf/type/__jail_freebsd9/parameter/default/state b/cdist/conf/type/__jail_freebsd9/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__jail_freebsd9/parameter/optional b/cdist/conf/type/__jail_freebsd9/parameter/optional new file mode 100644 index 00000000..b36f0fa5 --- /dev/null +++ b/cdist/conf/type/__jail_freebsd9/parameter/optional @@ -0,0 +1,8 @@ +name +ip +hostname +interface +devfs-ruleset +jaildir +jailbase +state diff --git a/cdist/conf/type/__package/parameter/boolean b/cdist/conf/type/__package/parameter/boolean new file mode 100644 index 00000000..effcb218 --- /dev/null +++ b/cdist/conf/type/__package/parameter/boolean @@ -0,0 +1 @@ +upgrade diff --git a/cdist/conf/type/__package/parameter/optional b/cdist/conf/type/__package/parameter/optional index d674f32e..bb3f5154 100644 --- a/cdist/conf/type/__package/parameter/optional +++ b/cdist/conf/type/__package/parameter/optional @@ -4,3 +4,4 @@ type pkgsite state ptype +repo From bcd4e5f29b96f4e9e486533fc5b645680a6cc46d Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Sun, 5 Jun 2016 21:57:56 -0400 Subject: [PATCH 0138/1332] Removed debugging from __jail_freebsd10/gencode-local --- cdist/conf/type/__jail_freebsd10/gencode-local | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__jail_freebsd10/gencode-local b/cdist/conf/type/__jail_freebsd10/gencode-local index a88e8ae4..d4b89730 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-local +++ b/cdist/conf/type/__jail_freebsd10/gencode-local @@ -23,8 +23,8 @@ # # Debug -exec >&2 -set -x +#exec >&2 +#set -x jaildir="$(cat "$__object/parameter/jaildir")" @@ -48,5 +48,5 @@ if [ "$state" = "present" ]; then fi # state=present # Debug -set +x +#set +x From bcd5e9827b2d887e31b1e2a12b1b8b40b077ee15 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Sun, 5 Jun 2016 22:16:42 -0400 Subject: [PATCH 0139/1332] Fix man pages Migrate (re-migrate) from text -> rst and update docs to reflect new developments --- cdist/conf/type/__jail/man.rst | 6 +- .../__jail_freebsd10/{man.text => man.rst} | 84 +++++++++---------- .../__jail_freebsd9/{man.text => man.rst} | 80 +++++++++--------- 3 files changed, 81 insertions(+), 89 deletions(-) rename cdist/conf/type/__jail_freebsd10/{man.text => man.rst} (59%) rename cdist/conf/type/__jail_freebsd9/{man.text => man.rst} (60%) diff --git a/cdist/conf/type/__jail/man.rst b/cdist/conf/type/__jail/man.rst index 38ec4f96..826dce21 100644 --- a/cdist/conf/type/__jail/man.rst +++ b/cdist/conf/type/__jail/man.rst @@ -2,12 +2,12 @@ cdist-type__jail(7) =================== Manage FreeBSD jails -Jake Guffey +Jake Guffey DESCRIPTION ----------- -This type is used on FreeBSD to manage jails. +This type is used on FreeBSD to manage jails by calling the appropriate per-version subtype. REQUIRED PARAMETERS @@ -112,5 +112,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2012 Jake Guffey. Free use of this software is +Copyright \(C) 2012,2016 Jake Guffey. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__jail_freebsd10/man.text b/cdist/conf/type/__jail_freebsd10/man.rst similarity index 59% rename from cdist/conf/type/__jail_freebsd10/man.text rename to cdist/conf/type/__jail_freebsd10/man.rst index b5df9d5d..7e167549 100644 --- a/cdist/conf/type/__jail_freebsd10/man.text +++ b/cdist/conf/type/__jail_freebsd10/man.rst @@ -1,61 +1,58 @@ -cdist-type__jail_freebsd_10(7) -============================== +cdist-type__jail_freebsd10(7) +============================= +Manage FreeBSD jails + Jake Guffey -NAME ----- -cdist-type__jail_freebsd_10 - Manage FreeBSD jails - - DESCRIPTION ----------- -This type is used on FreeBSD 10.x to manage jails. +This type is used on FreeBSD >= 10.0 to manage jails. REQUIRED PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present". -jailbase:: +jailbase The location of the .tgz archive containing the base fs for your jails. OPTIONAL PARAMETERS ------------------- -name:: +name The name of the jail. Default is to use the object_id as the jail name. -ip:: +ip The ifconfig style IP/netmask combination to use for the jail guest. If the state parameter is "present," this parameter is required. -hostname:: +hostname The FQDN to use for the jail guest. Defaults to the name parameter. -interface:: +interface The name of the physical interface on the jail server to bind the jail to. Defaults to the first interface found in the output of ifconfig -l. -devfs-ruleset:: +devfs-ruleset The name of the devfs ruleset to associate with the jail. Defaults to "jailrules." This ruleset must be copied to the server via another type. To use this option, devfs-enable must be "true." -jaildir:: +jaildir The location on the remote server to use for hosting jail filesystems. Defaults to /usr/jail. BOOLEAN PARAMETERS ------------------ -stopped:: +stopped Do not start the jail -devfs-disable:: +devfs-disable Whether to disallow devfs mounting within the jail -onboot:: +onboot Whether to add the jail to rc.conf's jail_list variable. @@ -68,49 +65,48 @@ modifications to jail.conf need to be made through alternate means. MESSAGES -------- -start:: +start The jail was started -stop:: +stop The jail was stopped create: The jail was created -delete:: +delete The jail was deleted -onboot:: +onboot The jail was configured to start on boot EXAMPLES -------- --------------------------------------------------------------------------------- -# Create a jail called www -__jail_freebsd_10 www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz +.. code-block:: sh -# Remove the jail called www -__jail_freebsd_10 www --state absent --jailbase /my/jail/base.tgz + # Create a jail called www + __jail_freebsd10 www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz -# The jail www should not be started -__jail_freebsd_10 www --state present --stopped \ - --ip "192.168.1.2 netmask 255.255.255.0" \ - --jailbase /my/jail/base.tgz + # Remove the jail called www + __jail_freebsd10 www --state absent --jailbase /my/jail/base.tgz -# Use the name variable explicitly -__jail_freebsd_10 thisjail --state present --name www \ - --ip "192.168.1.2" \ - --jailbase /my/jail/base.tgz + # The jail www should not be started + __jail_freebsd10 www --state present --stopped \ + --ip "192.168.1.2 netmask 255.255.255.0" \ + --jailbase /my/jail/base.tgz -# Go nuts -__jail_freebsd_10 lotsofoptions --state present --name testjail \ - --ip "192.168.1.100 netmask 255.255.255.0" \ - --hostname "testjail.example.com" --interface "em0" \ - --onboot --jailbase /my/jail/base.tgz --jaildir /jails --------------------------------------------------------------------------------- + # Use the name variable explicitly + __jail_freebsd10 thisjail --state present --name www \ + --ip "192.168.1.2" \ + --jailbase /my/jail/base.tgz + + # Go nuts + __jail_freebsd10 lotsofoptions --state present --name testjail \ + --ip "192.168.1.100 netmask 255.255.255.0" \ + --hostname "testjail.example.com" --interface "em0" \ + --onboot --jailbase /my/jail/base.tgz --jaildir /jails SEE ALSO -------- -- cdist-type(7) -- cdist-type__jail(7) +- `cdist-type(7) `_ COPYING diff --git a/cdist/conf/type/__jail_freebsd9/man.text b/cdist/conf/type/__jail_freebsd9/man.rst similarity index 60% rename from cdist/conf/type/__jail_freebsd9/man.text rename to cdist/conf/type/__jail_freebsd9/man.rst index c51f326d..1fe20186 100644 --- a/cdist/conf/type/__jail_freebsd9/man.text +++ b/cdist/conf/type/__jail_freebsd9/man.rst @@ -1,61 +1,58 @@ cdist-type__jail_freebsd9(7) ============================ -Jake Guffey +Manage FreeBSD jails - -NAME ----- -cdist-type__jail_freebsd9 - Manage FreeBSD jails +Jake Guffey DESCRIPTION ----------- -This type is used on FreeBSD 9.x and before to manage jails. +This type is used on FreeBSD <= 9.x to manage jails. REQUIRED PARAMETERS ------------------- -state:: +state Either "present" or "absent", defaults to "present". -jailbase:: +jailbase The location of the .tgz archive containing the base fs for your jails. OPTIONAL PARAMETERS ------------------- -name:: +name The name of the jail. Default is to use the object_id as the jail name. -ip:: +ip The ifconfig style IP/netmask combination to use for the jail guest. If the state parameter is "present," this parameter is required. -hostname:: +hostname The FQDN to use for the jail guest. Defaults to the name parameter. -interface:: +interface The name of the physical interface on the jail server to bind the jail to. Defaults to the first interface found in the output of ifconfig -l. -devfs-ruleset:: +devfs-ruleset The name of the devfs ruleset to associate with the jail. Defaults to "jailrules." This ruleset must be copied to the server via another type. To use this option, devfs-enable must be "true." -jaildir:: +jaildir The location on the remote server to use for hosting jail filesystems. Defaults to /usr/jail. BOOLEAN PARAMETERS ------------------ -stopped:: +stopped Do not start the jail -devfs-disable:: +devfs-disable Whether to disallow devfs mounting within the jail -onboot:: +onboot Whether to add the jail to rc.conf's jail_list variable. @@ -69,49 +66,48 @@ means. MESSAGES -------- -start:: +start The jail was started -stop:: +stop The jail was stopped create: The jail was created -delete:: +delete The jail was deleted -onboot:: +onboot The jail was configured to start on boot EXAMPLES -------- --------------------------------------------------------------------------------- -# Create a jail called www -__jail_freebsd9 www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz +.. code-block:: sh -# Remove the jail called www -__jail_freebsd9 www --state absent --jailbase /my/jail/base.tgz + # Create a jail called www + __jail_freebsd9 www --state present --ip "192.168.1.2" --jailbase /my/jail/base.tgz -# The jail www should not be started -__jail_freebsd9 www --state present --stopped \ - --ip "192.168.1.2 netmask 255.255.255.0" \ - --jailbase /my/jail/base.tgz + # Remove the jail called www + __jail_freebsd9 www --state absent --jailbase /my/jail/base.tgz -# Use the name variable explicitly -__jail_freebsd9 thisjail --state present --name www \ - --ip "192.168.1.2" \ - --jailbase /my/jail/base.tgz + # The jail www should not be started + __jail_freebsd9 www --state present --stopped \ + --ip "192.168.1.2 netmask 255.255.255.0" \ + --jailbase /my/jail/base.tgz -# Go nuts -__jail_freebsd9 lotsofoptions --state present --name testjail \ - --ip "192.168.1.100 netmask 255.255.255.0" \ - --hostname "testjail.example.com" --interface "em0" \ - --onboot --jailbase /my/jail/base.tgz --jaildir /jails --------------------------------------------------------------------------------- + # Use the name variable explicitly + __jail_freebsd9 thisjail --state present --name www \ + --ip "192.168.1.2" \ + --jailbase /my/jail/base.tgz + + # Go nuts + __jail_freebsd9 lotsofoptions --state present --name testjail \ + --ip "192.168.1.100 netmask 255.255.255.0" \ + --hostname "testjail.example.com" --interface "em0" \ + --onboot --jailbase /my/jail/base.tgz --jaildir /jails SEE ALSO -------- -- cdist-type(7) -- cdist-type__jail +- `cdist-type(7) `_ COPYING From d2e5fa7167c981e6a3bdd66eb123732581a41da5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 6 Jun 2016 18:39:24 +0200 Subject: [PATCH 0140/1332] Add some thoughts about improving speed --- docs/2016-06-06.org | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/2016-06-06.org diff --git a/docs/2016-06-06.org b/docs/2016-06-06.org new file mode 100644 index 00000000..8e3624a8 --- /dev/null +++ b/docs/2016-06-06.org @@ -0,0 +1,7 @@ +* Enhance cdist speed +** Start separate server with own option +** Reconfigure normal sshd with appropriate options +** Start various own daemons +** Use custom multiplexing protocol +** Support native Python code +*** Use manifest.py instead of manifest if available From 8246642a45563772a7142188d5bca564982d4aaf Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 3 Jun 2016 12:11:31 +0200 Subject: [PATCH 0141/1332] Bugfix: ssh mux controlpath too long on some envs. --- scripts/cdist | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 6baa28f3..55113be0 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -26,8 +26,11 @@ def inspect_ssh_mux_opts(control_path_dir="~/.ssh/"): import subprocess import os - control_path = os.path.join(control_path_dir, - "cdist.socket.master-%l-%r@%h:%p") + # socket is always local to each cdist run, it is created in + # temp directory that is created at starting cdist, so + # control_path file name can be static, it will always be + # unique due to unique temp directory name + control_path = os.path.join(control_path_dir, "ssh-control-path") wanted_mux_opts = { "ControlPath": control_path, "ControlMaster": "auto", @@ -147,7 +150,7 @@ def commandline(): # didn't specify command line options nor env vars: # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC if args_dict['remote_copy'] is None or args_dict['remote_exec'] is None: - control_path_dir = tempfile.mkdtemp() + control_path_dir = tempfile.mkdtemp(prefix="cdist") import atexit atexit.register(lambda: shutil.rmtree(control_path_dir)) mux_opts = inspect_ssh_mux_opts(control_path_dir) From fd8e10e12adaf9c4dce88868ea26bb5ee859db8e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 3 Jun 2016 12:20:28 +0200 Subject: [PATCH 0142/1332] Improve error reporting for local and remote run. --- cdist/__init__.py | 4 ++-- cdist/exec/local.py | 13 ++++++++----- cdist/exec/remote.py | 13 ++++++++----- cdist/exec/util.py | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 12 deletions(-) create mode 100644 cdist/exec/util.py diff --git a/cdist/__init__.py b/cdist/__init__.py index 4454a3ac..e789499c 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -41,8 +41,8 @@ BANNER = """ "P' "" "" """ -REMOTE_COPY = "scp -o User=root -q" -REMOTE_EXEC = "ssh -o User=root -q" +REMOTE_COPY = "scp -o User=root" +REMOTE_EXEC = "ssh -o User=root" class Error(Exception): """Base exception class for this project""" diff --git a/cdist/exec/local.py b/cdist/exec/local.py index c0554831..15f49a89 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -33,6 +33,7 @@ import tempfile import cdist import cdist.message from cdist import core +import cdist.exec.util as exec_util class Local(object): """Execute commands locally. @@ -203,12 +204,14 @@ class Local(object): env.update(message.env) try: + output = exec_util.call_get_output(command, env=env) + self.log.debug("Local output: {}".format(output)) if return_output: - return subprocess.check_output(command, env=env).decode() - else: - subprocess.check_call(command, env=env) - except subprocess.CalledProcessError: - raise cdist.Error("Command failed: " + " ".join(command)) + return output.decode() + except subprocess.CalledProcessError as e: + raise cdist.Error("Command failed: " + " ".join(command) + + " with returncode: {} and output: {}".format( + e.returncode, e.output)) except OSError as error: raise cdist.Error(" ".join(command) + ": " + error.args[1]) finally: diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 77e2c8be..c78f02cb 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -26,6 +26,7 @@ import sys import glob import subprocess import logging +import cdist.exec.util as exec_util import cdist @@ -167,12 +168,14 @@ class Remote(object): self.log.debug("Remote run: %s", command) try: + output = exec_util.call_get_output(command, env=os_environ) + self.log.debug("Remote output: {}".format(output)) if return_output: - return subprocess.check_output(command, env=os_environ).decode() - else: - subprocess.check_call(command, env=os_environ) - except subprocess.CalledProcessError: - raise cdist.Error("Command failed: " + " ".join(command)) + return output.decode() + except subprocess.CalledProcessError as e: + raise cdist.Error("Command failed: " + " ".join(command) + + " with returncode: {} and output: {}".format( + e.returncode, e.output)) except OSError as error: raise cdist.Error(" ".join(command) + ": " + error.args[1]) except UnicodeDecodeError: diff --git a/cdist/exec/util.py b/cdist/exec/util.py new file mode 100644 index 00000000..983f455c --- /dev/null +++ b/cdist/exec/util.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# +# 2016 Darko Poljak (darko.poljak 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 . +# +# + +import subprocess +from tempfile import TemporaryFile + +import cdist + +def call_get_output(command, env=None): + """Run the given command with the given environment. + Return the stdout and stderr output as a byte string. + """ + assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: {}".format(command) + + with TemporaryFile() as fout: + subprocess.check_call(command, env=env, + stdout=fout, stderr=subprocess.STDOUT) + fout.seek(0) + output = fout.read() + + return output From 88b20610cbed739a8d6b7e6edda05457d7ffdf6e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 6 Jun 2016 22:21:17 +0200 Subject: [PATCH 0143/1332] Update changelog. --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index dada1d90..b0a8be4c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Improve error reporting for local and remote run command (Darko Poljak) + 4.1.0: 2016-05-27 * Documentation: Migrate to reStructuredText format and sphinx (Darko Poljak) * Core: Add -f option to read additional hosts from file/stdin (Darko Poljak) From 35bf9aeaa5930383eee9ed58ac7eb07ecb12217b Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 6 Jun 2016 18:01:14 -0400 Subject: [PATCH 0144/1332] Updated changelog for jail types --- docs/changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog b/docs/changelog index dada1d90..9d95c1ea 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,11 @@ Changelog --------- +4.1.1: 2016-06-06 + * New type: __jail_freebsd9: Handle jail management on FreeBSD <= 9.X (Jake Guffey) + * New type: __jail_freebsd10: Handle jail management on FreeBSD >= 10.0 (Jake Guffey) + * Type __jail: Dynamically select the correct jail subtype based on target host OS (Jake Guffey) + 4.1.0: 2016-05-27 * Documentation: Migrate to reStructuredText format and sphinx (Darko Poljak) * Core: Add -f option to read additional hosts from file/stdin (Darko Poljak) From e4fe8e8f37e9c9a3da90094cdd49fdd160862987 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 7 Jun 2016 13:44:35 +0200 Subject: [PATCH 0145/1332] Implement bash and zsh completions. --- completions/bash/cdist-completion.bash | 59 ++++++++++++++++++++++++++ completions/zsh/_cdist | 48 +++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 completions/bash/cdist-completion.bash create mode 100644 completions/zsh/_cdist diff --git a/completions/bash/cdist-completion.bash b/completions/bash/cdist-completion.bash new file mode 100644 index 00000000..3d396bb4 --- /dev/null +++ b/completions/bash/cdist-completion.bash @@ -0,0 +1,59 @@ +_cdist() +{ + local cur prev prevprev opts cmds projects + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + prevprev="${COMP_WORDS[COMP_CWORD-2]}" + opts="-h --help -d --debug -v --verbose -V --version" + cmds="banner shell config" + + case "${prevprev}" in + shell) + case "${prev}" in + -s|--shell) + shells=$(grep -v '^#' /etc/shells) + COMPREPLY=( $(compgen -W "${shells}" -- ${cur}) ) + return 0 + ;; + esac + ;; + esac + + case "${prev}" in + -*) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + banner) + opts="-h --help -d --debug -v --verbose" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + shell) + opts="-h --help -d --debug -v --verbose -s --shell" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + config) + opts="-h --help -d --debug -v --verbose \ + -c --conf-dir -f --file -i --initial-manifest -n --dry-run \ + -o --out-dir -p --parallel -s --sequential --remote-copy \ + --remote-exec" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + *) + ;; + esac + + if [[ ${cur} == -* ]]; then + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + COMPREPLY=( $(compgen -W "${cmds}" -- ${cur}) ) + return 0 +} + +complete -F _cdist cdist diff --git a/completions/zsh/_cdist b/completions/zsh/_cdist new file mode 100644 index 00000000..2bf324a6 --- /dev/null +++ b/completions/zsh/_cdist @@ -0,0 +1,48 @@ +#compdef cdist + +_cdist() +{ + local curcontext="$curcontext" state line + typeset -A opt_args + + _arguments \ + '1: :->opts_cmds'\ + '*: :->opts' + + case $state in + opts_cmds) + _arguments '1:Options and commands:(banner config shell -h --help -d --debug -v --verbose -V --version)' + ;; + *) + case $words[2] in + -*) + opts=(-h --help -d --debug -v --verbose -V --version) + compadd "$@" -- $opts + ;; + banner) + opts=(-h --help -d --debug -v --verbose) + compadd "$@" -- $opts + ;; + shell) + case $words[3] in + -s|--shell) + shells=($(grep -v '^#' /etc/shells)) + compadd "$@" -- $shells + ;; + *) + opts=(-h --help -d --debug -v --verbose -s --shell) + compadd "$@" -- $opts + ;; + esac + ;; + config) + opts=(-h --help -d --debug -v --verbose -c --conf-dir -f --file -i --initial-manifest -n --dry-run -o --out-dir -p --parallel -s --sequential --remote-copy --remote-exec) + compadd "$@" -- $opts + ;; + *) + ;; + esac + esac +} + +_cdist "$@" From bd9008794c5f620ae3957af78881887c9e85d3cc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 10 Jun 2016 07:50:07 +0200 Subject: [PATCH 0146/1332] Conflicting requirements bugfix. --- cdist/emulator.py | 37 +++++++++++++++++++--- cdist/test/emulator/__init__.py | 55 +++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 3f553412..f5a9f645 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -77,6 +77,9 @@ class Emulator(object): self.type_name = os.path.basename(argv[0]) self.cdist_type = core.CdistType(self.type_base_path, self.type_name) + # if set then object already exists and this var holds existing + # requirements + self._existing_reqs = None self.__init_log() @@ -150,10 +153,18 @@ class Emulator(object): self.parameters[key] = value if self.cdist_object.exists and not 'CDIST_OVERRIDE' in self.env: + # make existing requirements a set, so we can compare it + # later with new requirements + self._existing_reqs = set(self.cdist_object.requirements) if self.cdist_object.parameters != self.parameters: - raise cdist.Error("Object %s already exists with conflicting parameters:\n%s: %s\n%s: %s" - % (self.cdist_object.name, " ".join(self.cdist_object.source), self.cdist_object.parameters, self.object_source, self.parameters) - ) + errmsg = ("Object %s already exists with conflicting " + "parameters:\n%s: %s\n%s: %s" % (self.cdist_object.name, + " ".join(self.cdist_object.source), + self.cdist_object.parameters, + self.object_source, + self.parameters)) + self.log.error(errmsg) + raise cdist.Error(errmsg) else: if self.cdist_object.exists: self.log.debug('Object %s override forced with CDIST_OVERRIDE',self.cdist_object.name) @@ -210,7 +221,7 @@ class Emulator(object): # if no second last line, we are on the first type, so do not set a requirement pass - + reqs = set() if "require" in self.env: requirements = self.env['require'] self.log.debug("reqs = " + requirements) @@ -234,6 +245,24 @@ class Emulator(object): # (__file//bar => __file/bar) # This ensures pattern matching is done against sanitised list self.cdist_object.requirements.append(cdist_object.name) + reqs.add(cdist_object.name) + if self._existing_reqs is not None: + # if object exists then compare existing and new requirements + self.log.debug("OBJ: {} {}".format(self.cdist_type, self.object_id)) + self.log.debug("EXISTING REQS: {}".format(self._existing_reqs)) + self.log.debug("REQS: {}".format(reqs)) + + if self._existing_reqs != reqs: + errmsg = ("Object {} already exists with conflicting " + "requirements:\n{}: {}\n{}: {}".format( + self.cdist_object.name, + " ".join(self.cdist_object.source), + self._existing_reqs, + self.object_source, + reqs)) + self.log.error(errmsg) + raise cdist.Error(errmsg) + def record_auto_requirements(self): """An object shall automatically depend on all objects that it defined in it's type manifest. diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index f90e5320..b91c1e8f 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -133,6 +133,56 @@ class EmulatorTestCase(test.CdistTestCase): self.assertEqual(list(file_object.requirements), ['__planet/mars']) # if we get here all is fine +class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): + + def setUp(self): + self.temp_dir = self.mkdtemp() + handle, self.script = self.mkstemp(dir=self.temp_dir) + os.close(handle) + base_path = self.temp_dir + + self.local = local.Local( + target_host=self.target_host, + base_path=base_path, + exec_path=test.cdist_exec_path, + add_conf_dirs=[conf_dir]) + self.local.create_files_dirs() + + self.manifest = core.Manifest(self.target_host, self.local) + self.env = self.manifest.env_initial_manifest(self.script) + self.env['__cdist_object_marker'] = self.local.object_marker_name + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_object_conflicting_requirements_req_none(self): + argv = ['__directory', 'spam'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', 'eggs'] + self.env['require'] = '__directory/spam' + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', 'eggs'] + if 'require' in self.env: + del self.env['require'] + emu = emulator.Emulator(argv, env=self.env) + self.assertRaises(cdist.Error, emu.run) + + def test_object_conflicting_requirements_none_req(self): + argv = ['__directory', 'spam'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', 'eggs'] + if 'require' in self.env: + del self.env['require'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', 'eggs'] + self.env['require'] = '__directory/spam' + emu = emulator.Emulator(argv, env=self.env) + self.assertRaises(cdist.Error, emu.run) + class AutoRequireEmulatorTestCase(test.CdistTestCase): @@ -366,3 +416,8 @@ class StdinTestCase(test.CdistTestCase): stdin_saved_by_emulator = fd.read() self.assertEqual(random_string, stdin_saved_by_emulator) + + +if __name__ == '__main__': + import unittest + unittest.main() From 0049b62cca56929ab2ab2feca3b22b24fa9cbdb1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 11 Jun 2016 12:02:13 +0200 Subject: [PATCH 0147/1332] Add files conf subdirectory for static files. --- cdist/core/code.py | 3 +++ cdist/core/manifest.py | 2 ++ cdist/exec/local.py | 3 ++- cdist/test/code/__init__.py | 6 ++++++ .../fixtures/conf/type/__dump_environment/gencode-local | 1 + cdist/test/manifest/__init__.py | 7 +++++++ .../test/manifest/fixtures/conf/manifest/dump_environment | 1 + .../fixtures/conf/type/__dump_environment/manifest | 1 + docs/changelog | 3 +++ 9 files changed, 26 insertions(+), 1 deletion(-) diff --git a/cdist/core/code.py b/cdist/core/code.py index 5374bcdf..64517532 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -50,6 +50,7 @@ gencode-local __object_id: the objects id __object_fq: full qualified object id, iow: $type.name + / + object_id __type: full qualified path to the type's dir + __files: full qualified path to the files dir returns: string containing the generated code or None @@ -63,6 +64,7 @@ gencode-remote __object_id: the objects id __object_fq: full qualified object id, iow: $type.name + / + object_id __type: full qualified path to the type's dir + __files: full qualified path to the files dir returns: string containing the generated code or None @@ -91,6 +93,7 @@ class Code(object): self.env = { '__target_host': self.target_host, '__global': self.local.base_path, + '__files': self.local.files_path, } def _run_gencode(self, cdist_object, which): diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 240e57a1..3b71a215 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -36,6 +36,7 @@ common: __cdist_manifest: full qualified path of the manifest == script __cdist_type_base_path: full qualified path to the directory where types are defined for use in type emulator == local.type_path + __files: full qualified path to the files dir initial manifest is: script: full qualified path to the initial manifest @@ -96,6 +97,7 @@ class Manifest(object): '__cdist_type_base_path': self.local.type_path, # for use in type emulator '__global': self.local.base_path, '__target_host': self.target_host, + '__files': self.local.files_path, } if self.log.getEffectiveLevel() == logging.DEBUG: self.env.update({'__cdist_debug': "yes" }) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index fa003cb0..6f4bd239 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -34,7 +34,7 @@ import cdist import cdist.message from cdist import core -CONF_SUBDIRS_LINKED = [ "explorer", "files", "manifest", "type" ]: +CONF_SUBDIRS_LINKED = [ "explorer", "files", "manifest", "type" ] class Local(object): """Execute commands locally. @@ -111,6 +111,7 @@ class Local(object): self.global_explorer_out_path = os.path.join(self.base_path, "explorer") self.object_path = os.path.join(self.base_path, "object") self.messages_path = os.path.join(self.base_path, "messages") + self.files_path = os.path.join(self.conf_path, "files") # Depending on conf_path self.global_explorer_path = os.path.join(self.conf_path, "explorer") diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 689fcff6..811d3a33 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -82,6 +82,7 @@ class CodeTestCase(test.CdistTestCase): self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) self.assertEqual(output_dict['__object_name'], self.cdist_object.name) + self.assertEqual(output_dict['__files'], self.local.files_path) def test_run_gencode_remote_environment(self): output_string = self.code.run_gencode_remote(self.cdist_object) @@ -97,6 +98,7 @@ class CodeTestCase(test.CdistTestCase): self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) self.assertEqual(output_dict['__object_name'], self.cdist_object.name) + self.assertEqual(output_dict['__files'], self.local.files_path) def test_transfer_code_remote(self): self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) @@ -112,3 +114,7 @@ class CodeTestCase(test.CdistTestCase): self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) self.code.transfer_code_remote(self.cdist_object) self.code.run_code_remote(self.cdist_object) + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local index 771894fb..5883c268 100755 --- a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local +++ b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local @@ -6,3 +6,4 @@ echo "echo __type: $__type" echo "echo __object: $__object" echo "echo __object_id: $__object_id" echo "echo __object_name: $__object_name" +echo "echo __files: $__files" diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index cc60c844..f9eb8b8a 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -81,6 +81,7 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) self.assertEqual(output_dict['__manifest'], self.local.manifest_path) + self.assertEqual(output_dict['__files'], self.local.files_path) def test_type_manifest_environment(self): cdist_type = core.CdistType(self.local.type_path, '__dump_environment') @@ -105,6 +106,7 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__object'], cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], cdist_object.object_id) self.assertEqual(output_dict['__object_name'], cdist_object.name) + self.assertEqual(output_dict['__files'], self.local.files_path) def test_debug_env_setup(self): current_level = self.log.getEffectiveLevel() @@ -112,3 +114,8 @@ class ManifestTestCase(test.CdistTestCase): manifest = cdist.core.manifest.Manifest(self.target_host, self.local) self.assertTrue("__cdist_debug" in manifest.env) self.log.setLevel(current_level) + + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/cdist/test/manifest/fixtures/conf/manifest/dump_environment b/cdist/test/manifest/fixtures/conf/manifest/dump_environment index 7ce983ab..df901910 100755 --- a/cdist/test/manifest/fixtures/conf/manifest/dump_environment +++ b/cdist/test/manifest/fixtures/conf/manifest/dump_environment @@ -6,4 +6,5 @@ __target_host: $__target_host __global: $__global __cdist_type_base_path: $__cdist_type_base_path __manifest: $__manifest +__files: $__files DONE diff --git a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest index e135de35..13efe038 100755 --- a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest +++ b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest @@ -10,4 +10,5 @@ __self: $__self __object: $__object __object_id: $__object_id __object_name: $__object_name +__files: $__files DONE diff --git a/docs/changelog b/docs/changelog index dada1d90..ca567627 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Add files directory for static files (Darko Poljak) + 4.1.0: 2016-05-27 * Documentation: Migrate to reStructuredText format and sphinx (Darko Poljak) * Core: Add -f option to read additional hosts from file/stdin (Darko Poljak) From d7583e7a1a33763df579e5ef0294b4f42616e52e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 12 Jun 2016 17:55:29 +0200 Subject: [PATCH 0148/1332] Add __files to shell env. --- cdist/shell.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/shell.py b/cdist/shell.py index d0921bc9..83b2acf7 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -60,6 +60,7 @@ class Shell(object): '__target_host': self.target_host, '__manifest': self.local.manifest_path, '__explorer': self.local.global_explorer_path, + '__files': self.local.files_path, } self.env.update(additional_env) From e6d439f2e984fab61594c12d346e21c2c5373f6d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 12 Jun 2016 20:51:14 +0200 Subject: [PATCH 0149/1332] Fix changelog: 'next'. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 9d95c1ea..8ad8e953 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -4.1.1: 2016-06-06 +next: * New type: __jail_freebsd9: Handle jail management on FreeBSD <= 9.X (Jake Guffey) * New type: __jail_freebsd10: Handle jail management on FreeBSD >= 10.0 (Jake Guffey) * Type __jail: Dynamically select the correct jail subtype based on target host OS (Jake Guffey) From 2e1cc0a89b489abfa07d72a584eb45aafb19f2e9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 22 Jun 2016 12:20:34 +0200 Subject: [PATCH 0150/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8ad8e953..207125db 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Custom: Add bash and zsh completions (Darko Poljak) * New type: __jail_freebsd9: Handle jail management on FreeBSD <= 9.X (Jake Guffey) * New type: __jail_freebsd10: Handle jail management on FreeBSD >= 10.0 (Jake Guffey) * Type __jail: Dynamically select the correct jail subtype based on target host OS (Jake Guffey) From 5ee20f7886d81be81407c33cc205d82d1dc51c2e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 22 Jun 2016 12:23:31 +0200 Subject: [PATCH 0151/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8ad8e953..31f2bb35 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Core: Fix conflicting requirements (Darko Poljak) * New type: __jail_freebsd9: Handle jail management on FreeBSD <= 9.X (Jake Guffey) * New type: __jail_freebsd10: Handle jail management on FreeBSD >= 10.0 (Jake Guffey) * Type __jail: Dynamically select the correct jail subtype based on target host OS (Jake Guffey) From 9802467bbb26ae74d5702f814a440642009edfc9 Mon Sep 17 00:00:00 2001 From: Stephan Leemburg Date: Wed, 22 Jun 2016 13:17:03 +0200 Subject: [PATCH 0152/1332] Add openvz/lxc discovery --- cdist/conf/explorer/machine_type | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cdist/conf/explorer/machine_type b/cdist/conf/explorer/machine_type index 74789f5a..c0541ad5 100755 --- a/cdist/conf/explorer/machine_type +++ b/cdist/conf/explorer/machine_type @@ -22,6 +22,17 @@ # FIXME: other system types (not linux ...) +if [ -d "/proc/vz" -a ! -d "/proc/bc" ]; then + echo openvz + exit +fi + +if [ -e "/proc/1/environ" ] && + cat "/proc/1/environ" | tr '\000' '\n' | grep -Eiq '^container='; then + echo lxc + exit +fi + if [ -r /proc/cpuinfo ]; then # this should only exist on virtual guest machines, # tested on vmware, xen, kvm From 98160624a0069521d9593f46fae61b73cfb68d12 Mon Sep 17 00:00:00 2001 From: Stephan Leemburg Date: Wed, 22 Jun 2016 13:17:03 +0200 Subject: [PATCH 0153/1332] Add openvz/lxc discovery --- cdist/conf/explorer/machine_type | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cdist/conf/explorer/machine_type b/cdist/conf/explorer/machine_type index 74789f5a..c0541ad5 100755 --- a/cdist/conf/explorer/machine_type +++ b/cdist/conf/explorer/machine_type @@ -22,6 +22,17 @@ # FIXME: other system types (not linux ...) +if [ -d "/proc/vz" -a ! -d "/proc/bc" ]; then + echo openvz + exit +fi + +if [ -e "/proc/1/environ" ] && + cat "/proc/1/environ" | tr '\000' '\n' | grep -Eiq '^container='; then + echo lxc + exit +fi + if [ -r /proc/cpuinfo ]; then # this should only exist on virtual guest machines, # tested on vmware, xen, kvm From 95461cded786c58fd09962756809e55666198fc7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 22 Jun 2016 13:24:12 +0200 Subject: [PATCH 0154/1332] Fix tabulation (Dmitry Bogatov). --- docs/man/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/Makefile b/docs/man/Makefile index 721acaf6..c2e398c5 100644 --- a/docs/man/Makefile +++ b/docs/man/Makefile @@ -9,7 +9,7 @@ BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) - $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) + $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. From 9300eda3c6fa7960d6d179fe0cfde073b84ad309 Mon Sep 17 00:00:00 2001 From: Stephan Leemburg Date: Wed, 22 Jun 2016 13:32:51 +0200 Subject: [PATCH 0155/1332] Add scientific --- cdist/conf/explorer/os | 5 +++++ cdist/conf/explorer/os_version | 2 +- cdist/conf/type/__consul/manifest | 2 +- cdist/conf/type/__consul_agent/manifest | 2 +- cdist/conf/type/__consul_template/manifest | 2 +- cdist/conf/type/__hostname/gencode-remote | 2 +- cdist/conf/type/__hostname/manifest | 2 +- cdist/conf/type/__locale/manifest | 2 +- cdist/conf/type/__package/manifest | 2 +- cdist/conf/type/__package_update_index/gencode-remote | 2 +- cdist/conf/type/__package_upgrade_all/gencode-remote | 2 +- cdist/conf/type/__package_yum/gencode-remote | 2 +- cdist/conf/type/__postfix/manifest | 2 +- cdist/conf/type/__postfix_master/manifest | 2 +- cdist/conf/type/__postfix_postconf/explorer/value | 2 +- cdist/conf/type/__postfix_postconf/gencode-remote | 2 +- cdist/conf/type/__postfix_reload/gencode-remote | 2 +- cdist/conf/type/__start_on_boot/explorer/state | 2 +- cdist/conf/type/__start_on_boot/gencode-remote | 2 +- cdist/conf/type/__timezone/manifest | 2 +- cdist/conf/type/__yum_repo/manifest | 2 +- docs/web/cdist/os.mdwn | 1 + 22 files changed, 26 insertions(+), 20 deletions(-) diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index de1d29c3..550192d4 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -72,6 +72,11 @@ if [ -f /etc/owl-release ]; then fi ### Redhat and derivatives +if grep -q ^Scientific /etc/redhat-release 2>/dev/null; then + echo scientific + exit 0 +fi + if grep -q ^CentOS /etc/redhat-release 2>/dev/null; then echo centos exit 0 diff --git a/cdist/conf/explorer/os_version b/cdist/conf/explorer/os_version index 6c7becdc..58f750b0 100755 --- a/cdist/conf/explorer/os_version +++ b/cdist/conf/explorer/os_version @@ -54,7 +54,7 @@ case "$($__explorer/os)" in owl) cat /etc/owl-release ;; - redhat|centos|mitel) + redhat|centos|mitel|scientific) cat /etc/redhat-release ;; slackware) diff --git a/cdist/conf/type/__consul/manifest b/cdist/conf/type/__consul/manifest index 0187d959..b16c5749 100755 --- a/cdist/conf/type/__consul/manifest +++ b/cdist/conf/type/__consul/manifest @@ -23,7 +23,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - centos|redhat|ubuntu|debian|archlinux|gentoo) + scientific|centos|redhat|ubuntu|debian|archlinux|gentoo) # any linux should work : ;; diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index b4d1d75c..7f180494 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -23,7 +23,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - centos|debian|redhat|ubuntu) + scientific|centos|debian|redhat|ubuntu) # whitelist safeguard : ;; diff --git a/cdist/conf/type/__consul_template/manifest b/cdist/conf/type/__consul_template/manifest index cedcb413..4448cc71 100755 --- a/cdist/conf/type/__consul_template/manifest +++ b/cdist/conf/type/__consul_template/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - centos|redhat) + scientific|centos|redhat) # whitelist safeguard service_onchange='service consul-template status >/dev/null && service consul-template reload || true' \ ;; diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 9fac7bf4..c1808de0 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -40,7 +40,7 @@ case "$os" in exit 0 fi ;; - centos) + scientific|centos) if [ "$name_sysconfig" = "$name_should" -a "$name_running" = "$name_should" ]; then exit 0 fi diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 76f962e0..842075e0 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -38,7 +38,7 @@ case "$os" in # handled in gencode-remote : ;; - centos) + scientific|centos) __key_value sysconfig-hostname \ --file /etc/sysconfig/network \ --delimiter '=' \ diff --git a/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest index c1837ae3..d360e9f3 100644 --- a/cdist/conf/type/__locale/manifest +++ b/cdist/conf/type/__locale/manifest @@ -30,7 +30,7 @@ case "$os" in # Debian needs a seperate package __package locales --state present ;; - archlinux|suse|ubuntu|centos) + archlinux|suse|ubuntu|scientific|centos) : ;; *) diff --git a/cdist/conf/type/__package/manifest b/cdist/conf/type/__package/manifest index 6b0daa98..c745f85f 100755 --- a/cdist/conf/type/__package/manifest +++ b/cdist/conf/type/__package/manifest @@ -30,7 +30,7 @@ else # By default determine package manager based on operating system os="$(cat "$__global/explorer/os")" case "$os" in - amazon|centos|fedora|redhat) type="yum" ;; + amazon|scientific|centos|fedora|redhat) type="yum" ;; archlinux) type="pacman" ;; debian|ubuntu|devuan) type="apt" ;; freebsd) diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index 589e7202..bf6a532d 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -29,7 +29,7 @@ else # By default determine package manager based on operating system os="$(cat "$__global/explorer/os")" case "$os" in - amazon|centos|fedora|redhat) type="yum" ;; + amazon|scientific|centos|fedora|redhat) type="yum" ;; debian|ubuntu|devuan) type="apt" ;; archlinux) type="pacman" ;; *) diff --git a/cdist/conf/type/__package_upgrade_all/gencode-remote b/cdist/conf/type/__package_upgrade_all/gencode-remote index 4d034816..9dd3ddf6 100755 --- a/cdist/conf/type/__package_upgrade_all/gencode-remote +++ b/cdist/conf/type/__package_upgrade_all/gencode-remote @@ -30,7 +30,7 @@ else # By default determine package manager based on operating system os="$(cat "$__global/explorer/os")" case "$os" in - amazon|centos|fedora|redhat) type="yum" ;; + amazon|scientific|centos|fedora|redhat) type="yum" ;; debian|ubuntu|devuan) type="apt" ;; archlinux) type="pacman" ;; *) diff --git a/cdist/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote index 32a794a0..08c5c2b5 100755 --- a/cdist/conf/type/__package_yum/gencode-remote +++ b/cdist/conf/type/__package_yum/gencode-remote @@ -37,7 +37,7 @@ fi state_should="$(cat "$__object/parameter/state")" -if grep -q -E "(centos|redhat|amazon)" "$__global/explorer/os"; then +if grep -q -E "(scientific|centos|redhat|amazon)" "$__global/explorer/os"; then opts="-y --quiet" else opts="--assumeyes --quiet" diff --git a/cdist/conf/type/__postfix/manifest b/cdist/conf/type/__postfix/manifest index 43443e1e..b425e072 100755 --- a/cdist/conf/type/__postfix/manifest +++ b/cdist/conf/type/__postfix/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|suse|centos|devuan) + ubuntu|debian|archlinux|suse|scientific|centos|devuan) __package postfix --state present ;; *) diff --git a/cdist/conf/type/__postfix_master/manifest b/cdist/conf/type/__postfix_master/manifest index 3d82c526..af71b88e 100755 --- a/cdist/conf/type/__postfix_master/manifest +++ b/cdist/conf/type/__postfix_master/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|centos|devuan) + ubuntu|debian|archlinux|scientific|centos|devuan) : ;; *) diff --git a/cdist/conf/type/__postfix_postconf/explorer/value b/cdist/conf/type/__postfix_postconf/explorer/value index d451bce6..17126c94 100755 --- a/cdist/conf/type/__postfix_postconf/explorer/value +++ b/cdist/conf/type/__postfix_postconf/explorer/value @@ -22,7 +22,7 @@ os=$("$__explorer/os") case "$os" in - ubuntu|debian|archlinux|suse|centos|devuan) + ubuntu|debian|archlinux|suse|scientific|centos|devuan) : ;; *) diff --git a/cdist/conf/type/__postfix_postconf/gencode-remote b/cdist/conf/type/__postfix_postconf/gencode-remote index b3557640..f886499b 100755 --- a/cdist/conf/type/__postfix_postconf/gencode-remote +++ b/cdist/conf/type/__postfix_postconf/gencode-remote @@ -21,7 +21,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|suse|centos|devuan) + ubuntu|debian|archlinux|suse|scientific|centos|devuan) : ;; *) diff --git a/cdist/conf/type/__postfix_reload/gencode-remote b/cdist/conf/type/__postfix_reload/gencode-remote index 7323606c..0efd6022 100755 --- a/cdist/conf/type/__postfix_reload/gencode-remote +++ b/cdist/conf/type/__postfix_reload/gencode-remote @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|centos|devuan) + ubuntu|debian|archlinux|scientific|centos|devuan) echo "postfix reload" ;; *) diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index ca0f3a51..d49f01c7 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -47,7 +47,7 @@ else [ -f "/etc/init/${name}.conf" ] && state="present" ;; - amazon|centos|fedora|owl|redhat) + amazon|scientific|centos|fedora|owl|redhat) state=$(chkconfig --level "$runlevel" "$name" || echo absent) [ "$state" ] || state="present" ;; diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 057f9f48..e77132c9 100644 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -59,7 +59,7 @@ case "$state_should" in echo rc-update add \"$name\" \"$target_runlevel\" ;; - amazon|centos|fedora|owl|redhat|suse) + amazon|scientific|centos|fedora|owl|redhat|suse) echo chkconfig \"$name\" on ;; diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index 8ddfd122..bcbe41c3 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -38,7 +38,7 @@ case "$os" in # whitelist : ;; - centos) + scientific|centos) __package tzdata --state present export require="__package/tzdata" __file /etc/sysconfig/clock \ diff --git a/cdist/conf/type/__yum_repo/manifest b/cdist/conf/type/__yum_repo/manifest index 9bb63c3c..950c3b7a 100755 --- a/cdist/conf/type/__yum_repo/manifest +++ b/cdist/conf/type/__yum_repo/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") state="$(cat "$__object/parameter/state")" case "$os" in - centos) + scientific|centos) repo_name="$__object_id" export repo_name repo_file="/etc/yum.repos.d/${repo_name}.repo" diff --git a/docs/web/cdist/os.mdwn b/docs/web/cdist/os.mdwn index 24992439..3677f52c 100644 --- a/docs/web/cdist/os.mdwn +++ b/docs/web/cdist/os.mdwn @@ -5,6 +5,7 @@ cdist was tested or is know to run on at least * [Archlinux](http://www.archlinux.org/) * [Debian](http://www.debian.org/) * [CentOS](http://www.centos.org/) + * [Scientific](https://www.scientificlinux.org/) * [Fedora](http://fedoraproject.org/) * [FreeBSD](http://www.freebsd.org) * [Gentoo](http://www.gentoo.org/) From 4a7823d9b5d804b9e50bb7c12d39f2493d8ec3fa Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 22 Jun 2016 23:54:58 +0200 Subject: [PATCH 0156/1332] new consul-template version Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_template/files/versions/0.15.0/cksum | 1 + cdist/conf/type/__consul_template/files/versions/0.15.0/source | 1 + 2 files changed, 2 insertions(+) create mode 100644 cdist/conf/type/__consul_template/files/versions/0.15.0/cksum create mode 100644 cdist/conf/type/__consul_template/files/versions/0.15.0/source diff --git a/cdist/conf/type/__consul_template/files/versions/0.15.0/cksum b/cdist/conf/type/__consul_template/files/versions/0.15.0/cksum new file mode 100644 index 00000000..426338bd --- /dev/null +++ b/cdist/conf/type/__consul_template/files/versions/0.15.0/cksum @@ -0,0 +1 @@ +2643547924 12487232 consul-template diff --git a/cdist/conf/type/__consul_template/files/versions/0.15.0/source b/cdist/conf/type/__consul_template/files/versions/0.15.0/source new file mode 100644 index 00000000..fdf1fccf --- /dev/null +++ b/cdist/conf/type/__consul_template/files/versions/0.15.0/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul-template/0.15.0/consul-template_0.15.0_linux_amd64.zip From 1ed0d6bbe3eaf76f280aabc86dc629c71ab7be80 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 22 Jun 2016 23:55:20 +0200 Subject: [PATCH 0157/1332] source for old consul-template versions have changed Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_template/files/versions/0.10.0/source | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul_template/files/versions/0.10.0/source b/cdist/conf/type/__consul_template/files/versions/0.10.0/source index 7fa074b5..031b1155 100644 --- a/cdist/conf/type/__consul_template/files/versions/0.10.0/source +++ b/cdist/conf/type/__consul_template/files/versions/0.10.0/source @@ -1 +1 @@ -https://github.com/hashicorp/consul-template/releases/download/v0.10.0/consul-template_0.10.0_linux_amd64.tar.gz +https://releases.hashicorp.com/consul-template/0.10.0/consul-template_0.10.0_linux_amd64.zip From 96b49f4e9921f8468f2ff20a85ebcbc8b5d8a50e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 22 Jun 2016 23:56:27 +0200 Subject: [PATCH 0158/1332] consul-template is no longer distributed as a tar. it is now a zip archive Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_template/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul_template/manifest b/cdist/conf/type/__consul_template/manifest index cedcb413..83d2aae4 100755 --- a/cdist/conf/type/__consul_template/manifest +++ b/cdist/conf/type/__consul_template/manifest @@ -52,7 +52,7 @@ __staged_file /usr/local/bin/consul-template \ --source "$(cat "$version_dir/source")" \ --cksum "$(cat "$version_dir/cksum")" \ --fetch-command 'curl -s -L "%s"' \ - --prepare-command 'tar -xzf "%s"; cat consul-template_*/consul-template' \ + --prepare-command 'unzip -p "%s"' \ --state "$state" \ --group root \ --owner root \ From 75b32328b63624c717bccdef04349547c8054212 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 22 Jun 2016 23:56:57 +0200 Subject: [PATCH 0159/1332] use latest consul-template version by default Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_template/parameter/default/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul_template/parameter/default/version b/cdist/conf/type/__consul_template/parameter/default/version index 78bc1abd..a5510516 100644 --- a/cdist/conf/type/__consul_template/parameter/default/version +++ b/cdist/conf/type/__consul_template/parameter/default/version @@ -1 +1 @@ -0.10.0 +0.15.0 From 6944998a193261a1083ce38b13282f6564e2877c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 22 Jun 2016 23:57:25 +0200 Subject: [PATCH 0160/1332] add new --wait parameter for consul-template Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_template_template/man.rst | 11 ++++++++++- cdist/conf/type/__consul_template_template/manifest | 2 +- .../__consul_template_template/parameter/optional | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__consul_template_template/man.rst b/cdist/conf/type/__consul_template_template/man.rst index 20d0a619..6264f696 100644 --- a/cdist/conf/type/__consul_template_template/man.rst +++ b/cdist/conf/type/__consul_template_template/man.rst @@ -36,6 +36,14 @@ source-file state if this template is 'present' or 'absent'. Defaults to 'present'. +wait + The `minimum(:maximum)` time to wait before rendering a new template to + disk and triggering a command, separated by a colon (`:`). If the optional + maximum value is omitted, it is assumed to be 4x the required minimum value. + This is a numeric time with a unit suffix ("5s"). There is no default value. + The wait value for a template takes precedence over any globally-configured + wait. + EXAMPLES -------- @@ -51,6 +59,7 @@ EXAMPLES # upload a local file to the target and configure it __consul_template_template nginx \ + --wait '2s:6s' \ --source-file "$__manifest/files/nginx.ctmpl" \ --destination /etc/nginx/nginx.conf \ --command 'service nginx restart' @@ -65,5 +74,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is +Copyright \(C) 2015-2016 Steven Armstrong. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__consul_template_template/manifest b/cdist/conf/type/__consul_template_template/manifest index c997a2c8..b832075d 100755 --- a/cdist/conf/type/__consul_template_template/manifest +++ b/cdist/conf/type/__consul_template_template/manifest @@ -55,7 +55,7 @@ for param in $(ls "$__object/parameter/"); do printf ' source = "%s"\n' "$destination" ;; - source|destination|command) + source|destination|command|wait) printf ' %s = "%s"\n' "$param" "$(cat "$__object/parameter/$param")" ;; *) diff --git a/cdist/conf/type/__consul_template_template/parameter/optional b/cdist/conf/type/__consul_template_template/parameter/optional index 229f6c89..3e55fbb7 100644 --- a/cdist/conf/type/__consul_template_template/parameter/optional +++ b/cdist/conf/type/__consul_template_template/parameter/optional @@ -2,3 +2,4 @@ command source source-file state +wait From ce26deb706ef5419cd9aeb2e543f235642a0e1ea Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 22 Jun 2016 23:58:14 +0200 Subject: [PATCH 0161/1332] add support for new check types Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_check/man.rst | 44 ++++++++++++++----- cdist/conf/type/__consul_check/manifest | 30 ++++++++----- .../type/__consul_check/parameter/optional | 8 ++++ 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/cdist/conf/type/__consul_check/man.rst b/cdist/conf/type/__consul_check/man.rst index 1de65358..e12d9ca8 100644 --- a/cdist/conf/type/__consul_check/man.rst +++ b/cdist/conf/type/__consul_check/man.rst @@ -20,18 +20,17 @@ None. OPTIONAL PARAMETERS ------------------- -interval - the interval in which the script given with --script should be run +docker-container-id + the id of the docker container to run -script - the shell command to run every --interval - -ttl - how long a check is considered healthy without being updated through the - HTTP interfave +http + the url to check id - Defaults to --name + The id of this check. + +interval + the interval in which the check should run name The name of this check. Defaults to __object_id @@ -39,9 +38,34 @@ name notes human readable description +script + the shell command to run + +service-id + the id of the service this check is bound to + +shell + the shell to run inside the docker container + state if this check is 'present' or 'absent'. Defaults to 'present'. +status + specify the initial state of this health check + +tcp + the host and port to check + +timeout + after how long to timeout checks which take to long + +token + ACL token to use for interacting with the catalog + +ttl + how long a TTL check is considered healthy without being updated through the + HTTP interface + EXAMPLES -------- @@ -67,5 +91,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is +Copyright \(C) 2015-2016 Steven Armstrong. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__consul_check/manifest b/cdist/conf/type/__consul_check/manifest index 3004f319..658e2598 100755 --- a/cdist/conf/type/__consul_check/manifest +++ b/cdist/conf/type/__consul_check/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2015 Steven Armstrong (steven-cdist at armstrong.cc) +# 2015-2016 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -24,12 +24,24 @@ conf_file="check_${name}.json" state="$(cat "$__object/parameter/state")" # Sanity checks -if [ -f "$__object/parameter/script" -a -f "$__object/parameter/ttl" ]; then - echo "Use either --script together with --interval OR --ttl, but not both" >&2 - exit 1 +if [ -f "$__object/parameter/ttl" ]; then + for conflicts_ttl in 'docker-container-id' 'http' 'script' 'tcp' 'timeout'; do + if [ -f "$__object/parameter/${conflicts_ttl}" ]; then + echo "Can not use --ttl together with --${conflicts_ttl}." >&2 + exit 1 + fi + done fi -if [ -f "$__object/parameter/script" -a ! -f "$__object/parameter/interval" ]; then - echo "When using --script you must also define --interval" >&2 +if [ ! -f "$__object/parameter/interval" ]; then + for requires_interval in 'docker-id' 'http' 'script' 'tcp'; do + if [ -f "$__object/parameter/${requires_interval}" ]; then + echo "When using --${requires_interval} you must also define --interval." >&2 + exit 1 + fi + done +fi +if [ -f "$__object/parameter/docker-container-id" -a ! -f "$__object/parameter/script" ]; then + echo "When using --docker-container-id you must also define --script." >&2 exit 1 fi @@ -40,11 +52,7 @@ printf ' "check": {\n' printf ' "name": "%s"\n' "$name" for param in $(ls "$__object/parameter/"); do case "$param" in - state|name|interval) continue ;; - script) - printf ' ,"script": "%s"\n' "$(cat "$__object/parameter/script")" - printf ' ,"interval": "%s"\n' "$(cat "$__object/parameter/interval")" - ;; + state|name) continue ;; *) key="$(echo "$param" | tr '-' '_')" printf ' ,"%s": "%s"\n' "$key" "$(cat "$__object/parameter/$param")" diff --git a/cdist/conf/type/__consul_check/parameter/optional b/cdist/conf/type/__consul_check/parameter/optional index f6c3a6e4..0e392956 100644 --- a/cdist/conf/type/__consul_check/parameter/optional +++ b/cdist/conf/type/__consul_check/parameter/optional @@ -1,7 +1,15 @@ +docker-container-id +http id interval name notes script +service-id +shell state +status +tcp +timeout +token ttl From d48b65ed53cd0e376198f443b6ea8913324876d6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 23 Jun 2016 10:56:37 +0200 Subject: [PATCH 0162/1332] Fix process error handling in local. --- cdist/exec/local.py | 9 ++++----- cdist/exec/util.py | 49 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index e02a33aa..5a0a8644 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -207,14 +207,13 @@ class Local(object): env.update(message.env) try: - output = exec_util.call_get_output(command, env=env) - self.log.debug("Local output: {}".format(output)) + output, errout = exec_util.call_get_output(command, env=env) + self.log.debug("Local stdout: {}".format(output)) + self.log.debug("Local stderr: {}".format(errout)) if return_output: return output.decode() except subprocess.CalledProcessError as e: - raise cdist.Error("Command failed: " + " ".join(command) - + " with returncode: {} and output: {}".format( - e.returncode, e.output)) + exec_util.handle_called_process_error(e, command) except OSError as error: raise cdist.Error(" ".join(command) + ": " + error.args[1]) finally: diff --git a/cdist/exec/util.py b/cdist/exec/util.py index 983f455c..15430f13 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -20,20 +20,61 @@ # import subprocess +import sys from tempfile import TemporaryFile import cdist +STDERR_UNSUPPORTED = 'Not supported in this python version' + def call_get_output(command, env=None): """Run the given command with the given environment. - Return the stdout and stderr output as a byte string. + Return the tuple of stdout and stderr output as a byte strings. """ - assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: {}".format(command) + + assert isinstance(command, (list, tuple)), ( + "list or tuple argument expected, got: {}".format(command)) + + if sys.version_info >= (3, 5): + return call_get_out_err(command, env) + else: + return (call_get_stdout(command, env), STDERR_UNSUPPORTED) + +def handle_called_process_error(err, command): + if sys.version_info >= (3, 5): + errout = err.stderr + else: + errout = STDERR_UNSUPPORTED + raise cdist.Error("Command failed: " + " ".join(command) + + " with returncode: {} and stdout: {}, stderr: {}".format( + err.returncode, err.output, errout)) + +def call_get_stdout(command, env=None): + """Run the given command with the given environment. + Return the stdout output as a byte string, stderr is ignored. + """ + assert isinstance(command, (list, tuple)), ( + "list or tuple argument expected, got: {}".format(command)) with TemporaryFile() as fout: - subprocess.check_call(command, env=env, - stdout=fout, stderr=subprocess.STDOUT) + subprocess.check_call(command, env=env, stdout=fout) fout.seek(0) output = fout.read() return output + +def call_get_out_err(command, env=None): + """Run the given command with the given environment. + Return the tuple of stdout and stderr output as a byte strings. + """ + assert isinstance(command, (list, tuple)), ( + "list or tuple argument expected, got: {}".format(command)) + + with TemporaryFile() as fout, TemporaryFile() as ferr: + subprocess.check_call(command, env=env, + stdout=fout, stderr=ferr) + fout.seek(0) + ferr.seek(0) + output = (fout.read(), ferr.read()) + + return output From b89077f9a50df525a3ab996b0a83baa1c8f8c1c1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 23 Jun 2016 16:08:59 +0200 Subject: [PATCH 0163/1332] Better sphinx manpage ext. Add custom dotman Makefile target for custom .cdist directory. --- Makefile | 23 ++++++ cdist/conf/type/__apt_key/man.rst | 5 +- cdist/conf/type/__apt_key_uri/man.rst | 5 +- cdist/conf/type/__apt_norecommends/man.rst | 5 +- cdist/conf/type/__apt_ppa/man.rst | 5 +- cdist/conf/type/__apt_source/man.rst | 5 +- cdist/conf/type/__apt_update_index/man.rst | 5 +- cdist/conf/type/__block/man.rst | 5 +- cdist/conf/type/__ccollect_source/man.rst | 5 +- cdist/conf/type/__cdist/man.rst | 5 +- cdist/conf/type/__cdistmarker/man.rst | 5 +- cdist/conf/type/__config_file/man.rst | 5 +- cdist/conf/type/__consul/man.rst | 5 +- cdist/conf/type/__consul_agent/man.rst | 5 +- cdist/conf/type/__consul_check/man.rst | 5 +- cdist/conf/type/__consul_reload/man.rst | 5 +- cdist/conf/type/__consul_service/man.rst | 5 +- cdist/conf/type/__consul_template/man.rst | 5 +- .../type/__consul_template_template/man.rst | 5 +- cdist/conf/type/__consul_watch_checks/man.rst | 5 +- cdist/conf/type/__consul_watch_event/man.rst | 5 +- cdist/conf/type/__consul_watch_key/man.rst | 5 +- .../type/__consul_watch_keyprefix/man.rst | 5 +- cdist/conf/type/__consul_watch_nodes/man.rst | 5 +- .../conf/type/__consul_watch_service/man.rst | 5 +- .../conf/type/__consul_watch_services/man.rst | 5 +- cdist/conf/type/__cron/man.rst | 5 +- .../type/__debconf_set_selections/man.rst | 5 +- cdist/conf/type/__directory/man.rst | 5 +- cdist/conf/type/__dog_vdi/man.rst | 5 +- cdist/conf/type/__file/man.rst | 5 +- cdist/conf/type/__firewalld_rule/man.rst | 5 +- cdist/conf/type/__git/man.rst | 5 +- cdist/conf/type/__group/man.rst | 5 +- cdist/conf/type/__hostname/man.rst | 5 +- cdist/conf/type/__iptables_apply/man.rst | 5 +- cdist/conf/type/__iptables_rule/man.rst | 5 +- cdist/conf/type/__issue/man.rst | 5 +- cdist/conf/type/__jail/man.rst | 5 +- cdist/conf/type/__jail_freebsd10/man.rst | 5 +- cdist/conf/type/__jail_freebsd9/man.rst | 5 +- cdist/conf/type/__key_value/man.rst | 5 +- cdist/conf/type/__line/man.rst | 5 +- cdist/conf/type/__link/man.rst | 5 +- cdist/conf/type/__locale/man.rst | 5 +- cdist/conf/type/__motd/man.rst | 5 +- cdist/conf/type/__mount/man.rst | 5 +- cdist/conf/type/__mysql_database/man.rst | 5 +- cdist/conf/type/__package/man.rst | 5 +- cdist/conf/type/__package_apt/man.rst | 5 +- cdist/conf/type/__package_emerge/man.rst | 5 +- .../__package_emerge_dependencies/man.rst | 5 +- cdist/conf/type/__package_luarocks/man.rst | 5 +- cdist/conf/type/__package_opkg/man.rst | 5 +- cdist/conf/type/__package_pacman/man.rst | 5 +- cdist/conf/type/__package_pip/man.rst | 5 +- cdist/conf/type/__package_pkg_freebsd/man.rst | 5 +- cdist/conf/type/__package_pkg_openbsd/man.rst | 5 +- .../conf/type/__package_pkgng_freebsd/man.rst | 5 +- cdist/conf/type/__package_rubygem/man.rst | 5 +- .../conf/type/__package_update_index/man.rst | 5 +- cdist/conf/type/__package_upgrade_all/man.rst | 5 +- cdist/conf/type/__package_yum/man.rst | 5 +- cdist/conf/type/__package_zypper/man.rst | 5 +- cdist/conf/type/__pacman_conf/man.rst | 5 +- .../conf/type/__pacman_conf_integrate/man.rst | 5 +- cdist/conf/type/__pf_apply/man.rst | 7 +- cdist/conf/type/__pf_ruleset/man.rst | 5 +- cdist/conf/type/__postfix/man.rst | 5 +- cdist/conf/type/__postfix_master/man.rst | 5 +- cdist/conf/type/__postfix_postconf/man.rst | 5 +- cdist/conf/type/__postfix_postmap/man.rst | 5 +- cdist/conf/type/__postfix_reload/man.rst | 5 +- cdist/conf/type/__postgres_database/man.rst | 5 +- cdist/conf/type/__postgres_role/man.rst | 5 +- cdist/conf/type/__process/man.rst | 5 +- cdist/conf/type/__pyvenv/man.rst | 5 +- cdist/conf/type/__qemu_img/man.rst | 5 +- cdist/conf/type/__rbenv/man.rst | 5 +- cdist/conf/type/__rsync/man.rst | 5 +- cdist/conf/type/__rvm/man.rst | 5 +- cdist/conf/type/__rvm_gem/man.rst | 5 +- cdist/conf/type/__rvm_gemset/man.rst | 5 +- cdist/conf/type/__rvm_ruby/man.rst | 5 +- cdist/conf/type/__ssh_authorized_key/man.rst | 5 +- cdist/conf/type/__ssh_authorized_keys/man.rst | 5 +- cdist/conf/type/__ssh_dot_ssh/man.rst | 7 +- cdist/conf/type/__staged_file/man.rst | 5 +- cdist/conf/type/__start_on_boot/man.rst | 5 +- cdist/conf/type/__timezone/man.rst | 5 +- cdist/conf/type/__update_alternatives/man.rst | 5 +- cdist/conf/type/__user/man.rst | 5 +- cdist/conf/type/__user_groups/man.rst | 5 +- cdist/conf/type/__yum_repo/man.rst | 5 +- cdist/conf/type/__zypper_repo/man.rst | 5 +- cdist/conf/type/__zypper_service/man.rst | 5 +- cdist/sphinxext/__init__.py | 0 cdist/sphinxext/manpage.py | 80 +++++++++++++++++++ docs/man/Makefile | 2 +- docs/man/cdist-reference.rst.sh | 5 +- docs/man/conf.py | 17 ++-- docs/man/man1/cdist.rst | 5 +- docs/man/man7/cdist-best-practice.rst | 5 +- docs/man/man7/cdist-bootstrap.rst | 5 +- docs/man/man7/cdist-explorer.rst | 5 +- docs/man/man7/cdist-hacker.rst | 5 +- docs/man/man7/cdist-manifest.rst | 5 +- docs/man/man7/cdist-messaging.rst | 5 +- docs/man/man7/cdist-quickstart.rst | 5 +- docs/man/man7/cdist-remote-exec-copy.rst | 5 +- docs/man/man7/cdist-stages.rst | 5 +- docs/man/man7/cdist-troubleshooting.rst | 5 +- docs/man/man7/cdist-tutorial.rst | 5 +- docs/man/man7/cdist-type.rst | 5 +- 114 files changed, 549 insertions(+), 122 deletions(-) create mode 100644 cdist/sphinxext/__init__.py create mode 100644 cdist/sphinxext/manpage.py diff --git a/Makefile b/Makefile index e584fc63..d00739bb 100644 --- a/Makefile +++ b/Makefile @@ -88,6 +88,29 @@ man-latest-link: web-pub ssh staticweb.ungleich.ch \ "cd /home/services/www/nico/nico.schottelius.org/www/software/cdist/man/ && rm -f latest && ln -sf "$(CHANGELOG_VERSION)" latest" +# Manpages: .cdist Types +DOT_CDIST_PATH=${HOME}/.cdist +DOTMAN7DSTDIR=$(MAN7DSTDIR) +DOTTYPEDIR=$(DOT_CDIST_PATH)/type +$(info $(DOTTYPEDIR)) +DOTMANTYPESRC=$(shell ls $(DOTTYPEDIR)/*/man.rst) +$(info $(DOTMANTYPESRC)) +DOTMANTYPEPREFIX=$(subst $(DOTTYPEDIR)/,$(DOTMAN7DSTDIR)/cdist-type,$(DOTMANTYPESRC)) +$(info $(DOTMANTYPEPREFIX)) +DOTMANTYPES=$(subst /man.rst,.rst,$(DOTMANTYPEPREFIX)) +$(info $(DOTMANTYPES)) + +# Link manpage: do not create man.html but correct named file +$(DOTMAN7DSTDIR)/cdist-type%.rst: $(DOTTYPEDIR)/%/man.rst + ln -sf "$^" $@ + +# Manpages #3: generic part +dotmansphinxman: $(DOTMANTYPES) + $(SPHINXM) + +dotman: dotmansphinxman + + ################################################################################ # Speeches # diff --git a/cdist/conf/type/__apt_key/man.rst b/cdist/conf/type/__apt_key/man.rst index 43dc89b1..cb4c4108 100644 --- a/cdist/conf/type/__apt_key/man.rst +++ b/cdist/conf/type/__apt_key/man.rst @@ -1,6 +1,9 @@ cdist-type__apt_key(7) ====================== -Manage the list of keys used by apt + +NAME +---- +cdist-type__apt_key - Manage the list of keys used by apt Steven Armstrong diff --git a/cdist/conf/type/__apt_key_uri/man.rst b/cdist/conf/type/__apt_key_uri/man.rst index a235e13a..ee8d1601 100644 --- a/cdist/conf/type/__apt_key_uri/man.rst +++ b/cdist/conf/type/__apt_key_uri/man.rst @@ -1,6 +1,9 @@ cdist-type__apt_key_uri(7) ========================== -Add apt key from uri + +NAME +---- +cdist-type__apt_key_uri - Add apt key from uri Steven Armstrong diff --git a/cdist/conf/type/__apt_norecommends/man.rst b/cdist/conf/type/__apt_norecommends/man.rst index 232bb166..09ea9d16 100644 --- a/cdist/conf/type/__apt_norecommends/man.rst +++ b/cdist/conf/type/__apt_norecommends/man.rst @@ -1,6 +1,9 @@ cdist-type__apt_norecommends(7) =============================== -Configure apt to not install recommended packages + +NAME +---- +cdist-type__apt_norecommends - Configure apt to not install recommended packages Steven Armstrong diff --git a/cdist/conf/type/__apt_ppa/man.rst b/cdist/conf/type/__apt_ppa/man.rst index e39bd6b2..922b18d5 100644 --- a/cdist/conf/type/__apt_ppa/man.rst +++ b/cdist/conf/type/__apt_ppa/man.rst @@ -1,6 +1,9 @@ cdist-type__apt_ppa(7) ====================== -Manage ppa repositories + +NAME +---- +cdist-type__apt_ppa - Manage ppa repositories Steven Armstrong diff --git a/cdist/conf/type/__apt_source/man.rst b/cdist/conf/type/__apt_source/man.rst index 70649c4b..2e09aee5 100644 --- a/cdist/conf/type/__apt_source/man.rst +++ b/cdist/conf/type/__apt_source/man.rst @@ -1,6 +1,9 @@ cdist-type__apt_source(7) ========================= -Manage apt sources + +NAME +---- +cdist-type__apt_source - Manage apt sources Steven Armstrong diff --git a/cdist/conf/type/__apt_update_index/man.rst b/cdist/conf/type/__apt_update_index/man.rst index 2fc66c65..ce8610f3 100644 --- a/cdist/conf/type/__apt_update_index/man.rst +++ b/cdist/conf/type/__apt_update_index/man.rst @@ -1,6 +1,9 @@ cdist-type__apt_update_index(7) =============================== -Update apt's package index + +NAME +---- +cdist-type__apt_update_index - Update apt's package index Steven Armstrong diff --git a/cdist/conf/type/__block/man.rst b/cdist/conf/type/__block/man.rst index 4b7d61dc..bd5304d8 100644 --- a/cdist/conf/type/__block/man.rst +++ b/cdist/conf/type/__block/man.rst @@ -1,6 +1,9 @@ cdist-type__block(7) ==================== -Manage blocks of text in files + +NAME +---- +cdist-type__block - Manage blocks of text in files Steven Armstrong diff --git a/cdist/conf/type/__ccollect_source/man.rst b/cdist/conf/type/__ccollect_source/man.rst index 12fb8f42..29baa5c4 100644 --- a/cdist/conf/type/__ccollect_source/man.rst +++ b/cdist/conf/type/__ccollect_source/man.rst @@ -1,6 +1,9 @@ cdist-type__ccollect_source(7) ============================== -Manage ccollect sources + +NAME +---- +cdist-type__ccollect_source - Manage ccollect sources Nico Schottelius diff --git a/cdist/conf/type/__cdist/man.rst b/cdist/conf/type/__cdist/man.rst index f15d3b73..c0e8365e 100644 --- a/cdist/conf/type/__cdist/man.rst +++ b/cdist/conf/type/__cdist/man.rst @@ -1,6 +1,9 @@ cdist-type__cdist(7) ==================== -Manage cdist installations + +NAME +---- +cdist-type__cdist - Manage cdist installations Nico Schottelius diff --git a/cdist/conf/type/__cdistmarker/man.rst b/cdist/conf/type/__cdistmarker/man.rst index 22e711b6..efd696ef 100644 --- a/cdist/conf/type/__cdistmarker/man.rst +++ b/cdist/conf/type/__cdistmarker/man.rst @@ -1,6 +1,9 @@ cdist-type__cdistmarker(7) ========================== -Add a timestamped cdist marker. + +NAME +---- +cdist-type__cdistmarker - Add a timestamped cdist marker. Daniel Maher diff --git a/cdist/conf/type/__config_file/man.rst b/cdist/conf/type/__config_file/man.rst index 49b63984..8eec81b0 100644 --- a/cdist/conf/type/__config_file/man.rst +++ b/cdist/conf/type/__config_file/man.rst @@ -1,6 +1,9 @@ cdist-type__config_file(7) ========================== -Manages config files + +NAME +---- +cdist-type__config_file - _Manages config files Steven Armstrong diff --git a/cdist/conf/type/__consul/man.rst b/cdist/conf/type/__consul/man.rst index 77fae852..e6a9d2d7 100644 --- a/cdist/conf/type/__consul/man.rst +++ b/cdist/conf/type/__consul/man.rst @@ -1,6 +1,9 @@ cdist-type__consul(7) ===================== -Install consul + +NAME +---- +cdist-type__consul - Install consul Steven Armstrong diff --git a/cdist/conf/type/__consul_agent/man.rst b/cdist/conf/type/__consul_agent/man.rst index 8285cb25..25ad4d5b 100644 --- a/cdist/conf/type/__consul_agent/man.rst +++ b/cdist/conf/type/__consul_agent/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_agent(7) =========================== -Manage the consul agent + +NAME +---- +cdist-type__consul_agent - Manage the consul agent Steven Armstrong diff --git a/cdist/conf/type/__consul_check/man.rst b/cdist/conf/type/__consul_check/man.rst index 1de65358..f04645fd 100644 --- a/cdist/conf/type/__consul_check/man.rst +++ b/cdist/conf/type/__consul_check/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_check(7) ============================= -Manages consul checks + +NAME +---- +cdist-type__consul_check - Manages consul checks Steven Armstrong diff --git a/cdist/conf/type/__consul_reload/man.rst b/cdist/conf/type/__consul_reload/man.rst index f66bb545..38618aba 100644 --- a/cdist/conf/type/__consul_reload/man.rst +++ b/cdist/conf/type/__consul_reload/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_reload(7) ============================ -Reload consul + +NAME +---- +cdist-type__consul_reload - Reload consul Steven Armstrong diff --git a/cdist/conf/type/__consul_service/man.rst b/cdist/conf/type/__consul_service/man.rst index 9a8efaab..f7d34f4a 100644 --- a/cdist/conf/type/__consul_service/man.rst +++ b/cdist/conf/type/__consul_service/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_service(7) ============================= -Manages consul services + +NAME +---- +cdist-type__consul_service - Manages consul services Steven Armstrong diff --git a/cdist/conf/type/__consul_template/man.rst b/cdist/conf/type/__consul_template/man.rst index bcdb94e3..8e01ee04 100644 --- a/cdist/conf/type/__consul_template/man.rst +++ b/cdist/conf/type/__consul_template/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_template(7) ============================== -Manage the consul-template service + +NAME +---- +cdist-type__consul_template - Manage the consul-template service Steven Armstrong diff --git a/cdist/conf/type/__consul_template_template/man.rst b/cdist/conf/type/__consul_template_template/man.rst index 20d0a619..30832bc8 100644 --- a/cdist/conf/type/__consul_template_template/man.rst +++ b/cdist/conf/type/__consul_template_template/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_template_template(7) ======================================= -Manage consul-template templates + +NAME +---- +cdist-type__consul_template_template - Manage consul-template templates Steven Armstrong diff --git a/cdist/conf/type/__consul_watch_checks/man.rst b/cdist/conf/type/__consul_watch_checks/man.rst index c1e8c0a7..cfb451d6 100644 --- a/cdist/conf/type/__consul_watch_checks/man.rst +++ b/cdist/conf/type/__consul_watch_checks/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_watch_checks(7) ================================== -Manages consul checks watches + +NAME +---- +cdist-type__consul_watch_checks - Manages consul checks watches Steven Armstrong diff --git a/cdist/conf/type/__consul_watch_event/man.rst b/cdist/conf/type/__consul_watch_event/man.rst index ea9bc61a..871c0704 100644 --- a/cdist/conf/type/__consul_watch_event/man.rst +++ b/cdist/conf/type/__consul_watch_event/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_watch_event(7) ================================= -Manages consul event watches + +NAME +---- +cdist-type__consul_watch_event - Manages consul event watches Steven Armstrong diff --git a/cdist/conf/type/__consul_watch_key/man.rst b/cdist/conf/type/__consul_watch_key/man.rst index 90e952b8..d7554df2 100644 --- a/cdist/conf/type/__consul_watch_key/man.rst +++ b/cdist/conf/type/__consul_watch_key/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_watch_key(7) =============================== -Manages consul key watches + +NAME +---- +cdist-type__consul_watch_key - Manages consul key watches Steven Armstrong diff --git a/cdist/conf/type/__consul_watch_keyprefix/man.rst b/cdist/conf/type/__consul_watch_keyprefix/man.rst index 8ee5822d..42f675a4 100644 --- a/cdist/conf/type/__consul_watch_keyprefix/man.rst +++ b/cdist/conf/type/__consul_watch_keyprefix/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_watch_keyprefix(7) ===================================== -Manages consul keyprefix watches + +NAME +---- +cdist-type__consul_watch_keyprefix - Manages consul keyprefix watches Steven Armstrong diff --git a/cdist/conf/type/__consul_watch_nodes/man.rst b/cdist/conf/type/__consul_watch_nodes/man.rst index b5f0a5ce..c92a8d01 100644 --- a/cdist/conf/type/__consul_watch_nodes/man.rst +++ b/cdist/conf/type/__consul_watch_nodes/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_watch_nodes(7) ================================= -Manages consul nodes watches + +NAME +---- +cdist-type__consul_watch_nodes - Manages consul nodes watches Steven Armstrong diff --git a/cdist/conf/type/__consul_watch_service/man.rst b/cdist/conf/type/__consul_watch_service/man.rst index 1cc2c00d..f37a0dea 100644 --- a/cdist/conf/type/__consul_watch_service/man.rst +++ b/cdist/conf/type/__consul_watch_service/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_watch_service(7) =================================== -Manages consul service watches + +NAME +---- +cdist-type__consul_watch_service - Manages consul service watches Steven Armstrong diff --git a/cdist/conf/type/__consul_watch_services/man.rst b/cdist/conf/type/__consul_watch_services/man.rst index bf766222..3d39da00 100644 --- a/cdist/conf/type/__consul_watch_services/man.rst +++ b/cdist/conf/type/__consul_watch_services/man.rst @@ -1,6 +1,9 @@ cdist-type__consul_watch_services(7) ==================================== -Manages consul services watches + +NAME +---- +cdist-type__consul_watch_services - Manages consul services watches Steven Armstrong diff --git a/cdist/conf/type/__cron/man.rst b/cdist/conf/type/__cron/man.rst index 353f6bae..33f2b185 100644 --- a/cdist/conf/type/__cron/man.rst +++ b/cdist/conf/type/__cron/man.rst @@ -1,6 +1,9 @@ cdist-type__cron(7) =================== -Installs and manages cron jobs + +NAME +---- +cdist-type__cron - Installs and manages cron jobs Steven Armstrong diff --git a/cdist/conf/type/__debconf_set_selections/man.rst b/cdist/conf/type/__debconf_set_selections/man.rst index 37aa65b9..60cdd5f0 100644 --- a/cdist/conf/type/__debconf_set_selections/man.rst +++ b/cdist/conf/type/__debconf_set_selections/man.rst @@ -1,6 +1,9 @@ cdist-type__debconf_set_selections(7) ===================================== -Setup debconf selections + +NAME +---- +cdist-type__debconf_set_selections - Setup debconf selections Nico Schottelius diff --git a/cdist/conf/type/__directory/man.rst b/cdist/conf/type/__directory/man.rst index 279763a1..8ca292ff 100644 --- a/cdist/conf/type/__directory/man.rst +++ b/cdist/conf/type/__directory/man.rst @@ -1,6 +1,9 @@ cdist-type__directory(7) ======================== -Manage a directory + +NAME +---- +cdist-type__directory - Manage a directory Nico Schottelius diff --git a/cdist/conf/type/__dog_vdi/man.rst b/cdist/conf/type/__dog_vdi/man.rst index 3e6155a6..3e0c27c9 100644 --- a/cdist/conf/type/__dog_vdi/man.rst +++ b/cdist/conf/type/__dog_vdi/man.rst @@ -1,6 +1,9 @@ cdist-type__dog_vdi(7) ====================== -Manage Sheepdog VM images + +NAME +---- +cdist-type__dog_vdi - Manage Sheepdog VM images Nico Schottelius diff --git a/cdist/conf/type/__file/man.rst b/cdist/conf/type/__file/man.rst index 73336581..89efebdb 100644 --- a/cdist/conf/type/__file/man.rst +++ b/cdist/conf/type/__file/man.rst @@ -1,6 +1,9 @@ cdist-type__file(7) =================== -Manage files. + +NAME +---- +cdist-type__file - Manage files. Nico Schottelius diff --git a/cdist/conf/type/__firewalld_rule/man.rst b/cdist/conf/type/__firewalld_rule/man.rst index d953b3d2..4533e193 100644 --- a/cdist/conf/type/__firewalld_rule/man.rst +++ b/cdist/conf/type/__firewalld_rule/man.rst @@ -1,6 +1,9 @@ cdist-type__firewalld_rule(7) ============================= -Configure firewalld rules + +NAME +---- +cdist-type__firewalld_rule - Configure firewalld rules Nico Schottelius diff --git a/cdist/conf/type/__git/man.rst b/cdist/conf/type/__git/man.rst index 75f6e48b..3ccc1e91 100644 --- a/cdist/conf/type/__git/man.rst +++ b/cdist/conf/type/__git/man.rst @@ -1,6 +1,9 @@ cdist-type__git(7) ================== -Get and or keep git repositories up-to-date + +NAME +---- +cdist-type__git - Get and or keep git repositories up-to-date Nico Schottelius diff --git a/cdist/conf/type/__group/man.rst b/cdist/conf/type/__group/man.rst index 912dd226..6a7d5a55 100644 --- a/cdist/conf/type/__group/man.rst +++ b/cdist/conf/type/__group/man.rst @@ -1,6 +1,9 @@ cdist-type__group(7) ==================== -Manage groups + +NAME +---- +cdist-type__group - Manage groups Steven Armstrong diff --git a/cdist/conf/type/__hostname/man.rst b/cdist/conf/type/__hostname/man.rst index 32d452f7..bd5d5a21 100644 --- a/cdist/conf/type/__hostname/man.rst +++ b/cdist/conf/type/__hostname/man.rst @@ -1,6 +1,9 @@ cdist-type__hostname(7) ======================= -Set the hostname + +NAME +---- +cdist-type__hostname - Set the hostname Steven Armstrong diff --git a/cdist/conf/type/__iptables_apply/man.rst b/cdist/conf/type/__iptables_apply/man.rst index 40605351..6a94b0af 100644 --- a/cdist/conf/type/__iptables_apply/man.rst +++ b/cdist/conf/type/__iptables_apply/man.rst @@ -1,6 +1,9 @@ cdist-type__iptables_apply(7) ============================= -Apply the rules + +NAME +---- +cdist-type__iptables_apply - Apply the rules Nico Schottelius diff --git a/cdist/conf/type/__iptables_rule/man.rst b/cdist/conf/type/__iptables_rule/man.rst index 5ee02f9c..b6ff6a32 100644 --- a/cdist/conf/type/__iptables_rule/man.rst +++ b/cdist/conf/type/__iptables_rule/man.rst @@ -1,6 +1,9 @@ cdist-type__iptables_rule(7) ============================ -Deploy iptable rulesets + +NAME +---- +cdist-type__iptables_rule - Deploy iptable rulesets Nico Schottelius diff --git a/cdist/conf/type/__issue/man.rst b/cdist/conf/type/__issue/man.rst index 4a6c1f8d..59fa6694 100644 --- a/cdist/conf/type/__issue/man.rst +++ b/cdist/conf/type/__issue/man.rst @@ -1,6 +1,9 @@ cdist-type__issue(7) ==================== -Manage issue + +NAME +---- +cdist-type__issue - Manage issue Nico Schottelius diff --git a/cdist/conf/type/__jail/man.rst b/cdist/conf/type/__jail/man.rst index 826dce21..6bbfbf47 100644 --- a/cdist/conf/type/__jail/man.rst +++ b/cdist/conf/type/__jail/man.rst @@ -1,6 +1,9 @@ cdist-type__jail(7) =================== -Manage FreeBSD jails + +NAME +---- +cdist-type__jail - Manage FreeBSD jails Jake Guffey diff --git a/cdist/conf/type/__jail_freebsd10/man.rst b/cdist/conf/type/__jail_freebsd10/man.rst index 7e167549..1a3515f0 100644 --- a/cdist/conf/type/__jail_freebsd10/man.rst +++ b/cdist/conf/type/__jail_freebsd10/man.rst @@ -1,6 +1,9 @@ cdist-type__jail_freebsd10(7) ============================= -Manage FreeBSD jails + +NAME +---- +cdist-type__jail_freeebsd10 - Manage FreeBSD jails Jake Guffey diff --git a/cdist/conf/type/__jail_freebsd9/man.rst b/cdist/conf/type/__jail_freebsd9/man.rst index 1fe20186..1e442ac0 100644 --- a/cdist/conf/type/__jail_freebsd9/man.rst +++ b/cdist/conf/type/__jail_freebsd9/man.rst @@ -1,6 +1,9 @@ cdist-type__jail_freebsd9(7) ============================ -Manage FreeBSD jails + +NAME +---- +cdist-type__jail_freebsd9 - Manage FreeBSD jails Jake Guffey diff --git a/cdist/conf/type/__key_value/man.rst b/cdist/conf/type/__key_value/man.rst index 4b259c75..467be78b 100644 --- a/cdist/conf/type/__key_value/man.rst +++ b/cdist/conf/type/__key_value/man.rst @@ -1,6 +1,9 @@ cdist-type__key_value(7) ======================== -Change property values in files + +NAME +---- +cdist-type__key_value - Change property values in files Steven Armstrong diff --git a/cdist/conf/type/__line/man.rst b/cdist/conf/type/__line/man.rst index f6d71a5a..81f57039 100644 --- a/cdist/conf/type/__line/man.rst +++ b/cdist/conf/type/__line/man.rst @@ -1,6 +1,9 @@ cdist-type__line(7) =================== -Manage lines in files + +NAME +---- +cdist-type__line - Manage lines in files Nico Schottelius diff --git a/cdist/conf/type/__link/man.rst b/cdist/conf/type/__link/man.rst index 654b097b..750874c1 100644 --- a/cdist/conf/type/__link/man.rst +++ b/cdist/conf/type/__link/man.rst @@ -1,6 +1,9 @@ cdist-type__link(7) =================== -Manage links (hard and symbolic) + +NAME +---- +cdist-type__link - Manage links (hard and symbolic) Nico Schottelius diff --git a/cdist/conf/type/__locale/man.rst b/cdist/conf/type/__locale/man.rst index df337739..2d947da8 100644 --- a/cdist/conf/type/__locale/man.rst +++ b/cdist/conf/type/__locale/man.rst @@ -1,6 +1,9 @@ cdist-type__locale(7) ===================== -Configure locales + +NAME +---- +cdit-type__locale - Configure locales Nico Schottelius diff --git a/cdist/conf/type/__motd/man.rst b/cdist/conf/type/__motd/man.rst index 988e2d02..1de8b258 100644 --- a/cdist/conf/type/__motd/man.rst +++ b/cdist/conf/type/__motd/man.rst @@ -1,6 +1,9 @@ cdist-type__motd(7) =================== -Manage message of the day + +NAME +---- +cdist-type__motd - Manage message of the day Nico Schottelius diff --git a/cdist/conf/type/__mount/man.rst b/cdist/conf/type/__mount/man.rst index 696dfbd4..eab304db 100644 --- a/cdist/conf/type/__mount/man.rst +++ b/cdist/conf/type/__mount/man.rst @@ -1,6 +1,9 @@ cdist-type__mount(7) ==================== -Manage filesystem mounts + +NAME +---- +cdit-type__mount - Manage filesystem mounts Steven Armstrong diff --git a/cdist/conf/type/__mysql_database/man.rst b/cdist/conf/type/__mysql_database/man.rst index 88f1eecd..d8d2626d 100644 --- a/cdist/conf/type/__mysql_database/man.rst +++ b/cdist/conf/type/__mysql_database/man.rst @@ -1,6 +1,9 @@ cdist-type__mysql_database(7) ============================= -Manage a MySQL database + +NAME +---- +cdist-type__mysql_database - Manage a MySQL database Benedikt Koeppel diff --git a/cdist/conf/type/__package/man.rst b/cdist/conf/type/__package/man.rst index 1ada06a7..b412af69 100644 --- a/cdist/conf/type/__package/man.rst +++ b/cdist/conf/type/__package/man.rst @@ -1,6 +1,9 @@ cdist-type__package(7) ====================== -Manage packages + +NAME +---- +cdist-type__package - Manage packages Steven Armstrong diff --git a/cdist/conf/type/__package_apt/man.rst b/cdist/conf/type/__package_apt/man.rst index ec28c0cc..65ebf6fa 100644 --- a/cdist/conf/type/__package_apt/man.rst +++ b/cdist/conf/type/__package_apt/man.rst @@ -1,6 +1,9 @@ cdist-type__package_apt(7) ========================== -Manage packages with apt-get + +NAME +---- +cdist-type__package_apt - Manage packages with apt-get Nico Schottelius diff --git a/cdist/conf/type/__package_emerge/man.rst b/cdist/conf/type/__package_emerge/man.rst index fe06031e..c9ac59b9 100644 --- a/cdist/conf/type/__package_emerge/man.rst +++ b/cdist/conf/type/__package_emerge/man.rst @@ -1,6 +1,9 @@ cdist-type__package_emerge(7) ============================= -Manage packages with portage + +NAME +---- +cdist-type__package_emerge - Manage packages with portage Thomas Oettli diff --git a/cdist/conf/type/__package_emerge_dependencies/man.rst b/cdist/conf/type/__package_emerge_dependencies/man.rst index 21af86e3..1c4d291b 100644 --- a/cdist/conf/type/__package_emerge_dependencies/man.rst +++ b/cdist/conf/type/__package_emerge_dependencies/man.rst @@ -1,6 +1,9 @@ cdist-type__package_emerge_dependencies(7) ========================================== -Install dependencies for __package_emerge + +NAME +---- +cdist-type__package_emerge_dependencies - Install dependencies for __package_emerge Thomas Oettli diff --git a/cdist/conf/type/__package_luarocks/man.rst b/cdist/conf/type/__package_luarocks/man.rst index ff7fea83..e097b4d6 100644 --- a/cdist/conf/type/__package_luarocks/man.rst +++ b/cdist/conf/type/__package_luarocks/man.rst @@ -1,6 +1,9 @@ cdist-type__package_luarocks(7) =============================== -Manage luarocks packages + +NAME +---- +cdist-type__package_luarocks - Manage luarocks packages Christian G. Warden diff --git a/cdist/conf/type/__package_opkg/man.rst b/cdist/conf/type/__package_opkg/man.rst index 9af17988..0104bbf2 100644 --- a/cdist/conf/type/__package_opkg/man.rst +++ b/cdist/conf/type/__package_opkg/man.rst @@ -1,6 +1,9 @@ cdist-type__package_opkg(7) =========================== -Manage packages with opkg + +NAME +---- +cdist-type__package_opkg - Manage packages with opkg Giel van Schijndel diff --git a/cdist/conf/type/__package_pacman/man.rst b/cdist/conf/type/__package_pacman/man.rst index 3d8845a5..6f3fc5b3 100644 --- a/cdist/conf/type/__package_pacman/man.rst +++ b/cdist/conf/type/__package_pacman/man.rst @@ -1,6 +1,9 @@ cdist-type__package_pacman(7) ============================= -Manage packages with pacman + +NAME +---- +cdist-type__package_pacman - Manage packages with pacman Nico Schottelius diff --git a/cdist/conf/type/__package_pip/man.rst b/cdist/conf/type/__package_pip/man.rst index b312fff5..0630274a 100644 --- a/cdist/conf/type/__package_pip/man.rst +++ b/cdist/conf/type/__package_pip/man.rst @@ -1,6 +1,9 @@ cdist-type__package_pip(7) ========================== -Manage packages with pip + +NAME +---- +cdist-type__package_pip - Manage packages with pip Nico Schottelius diff --git a/cdist/conf/type/__package_pkg_freebsd/man.rst b/cdist/conf/type/__package_pkg_freebsd/man.rst index c728cc9a..9246d09c 100644 --- a/cdist/conf/type/__package_pkg_freebsd/man.rst +++ b/cdist/conf/type/__package_pkg_freebsd/man.rst @@ -1,6 +1,9 @@ cdist-type__package_pkg_freebsd(7) ================================== -Manage FreeBSD packages + +NAME +---- +cdist-type__package_pkg_freebsd - Manage FreeBSD packages Jake Guffey diff --git a/cdist/conf/type/__package_pkg_openbsd/man.rst b/cdist/conf/type/__package_pkg_openbsd/man.rst index f9a746b9..f584864b 100644 --- a/cdist/conf/type/__package_pkg_openbsd/man.rst +++ b/cdist/conf/type/__package_pkg_openbsd/man.rst @@ -1,6 +1,9 @@ cdist-type__package_pkg(7) ========================== -Manage OpenBSD packages + +NAME +---- +cdist-type__package_pkg - Manage OpenBSD packages Andi Brönnimann diff --git a/cdist/conf/type/__package_pkgng_freebsd/man.rst b/cdist/conf/type/__package_pkgng_freebsd/man.rst index 36f1a7d8..b81ef75c 100644 --- a/cdist/conf/type/__package_pkgng_freebsd/man.rst +++ b/cdist/conf/type/__package_pkgng_freebsd/man.rst @@ -1,6 +1,9 @@ cdist-type__package_pkgng_freebsd(7) ==================================== -Manage FreeBSD packages with pkg-ng + +NAME +---- +cdist-type__package_pkgng_freebsd - Manage FreeBSD packages with pkg-ng Jake Guffey diff --git a/cdist/conf/type/__package_rubygem/man.rst b/cdist/conf/type/__package_rubygem/man.rst index 4cb9af04..d74149b0 100644 --- a/cdist/conf/type/__package_rubygem/man.rst +++ b/cdist/conf/type/__package_rubygem/man.rst @@ -1,6 +1,9 @@ cdist-type__package_rubygem(7) ============================== -Manage rubygem packages + +NAME +---- +cdist-type__package_rubygem - Manage rubygem packages Chase Allen James diff --git a/cdist/conf/type/__package_update_index/man.rst b/cdist/conf/type/__package_update_index/man.rst index a16d29ce..ae05b3c5 100644 --- a/cdist/conf/type/__package_update_index/man.rst +++ b/cdist/conf/type/__package_update_index/man.rst @@ -1,6 +1,9 @@ cdist-type__package_update_index(7) =================================== -Update the package index + +NAME +---- +cdist-type__update_index - Update the package index Ricardo Catalinas Jiménez diff --git a/cdist/conf/type/__package_upgrade_all/man.rst b/cdist/conf/type/__package_upgrade_all/man.rst index 146a8259..af6a2373 100644 --- a/cdist/conf/type/__package_upgrade_all/man.rst +++ b/cdist/conf/type/__package_upgrade_all/man.rst @@ -1,6 +1,9 @@ cdist-type__package_upgrade_all(7) ================================== -Upgrade all the installed packages + +NAME +---- +cdist-type__package_upgrade_all - Upgrade all the installed packages Ricardo Catalinas Jiménez diff --git a/cdist/conf/type/__package_yum/man.rst b/cdist/conf/type/__package_yum/man.rst index 65e56c7a..440d0723 100644 --- a/cdist/conf/type/__package_yum/man.rst +++ b/cdist/conf/type/__package_yum/man.rst @@ -1,6 +1,9 @@ cdist-type__package_yum(7) ========================== -Manage packages with yum + +NAME +---- +cdist-type__package_yum - Manage packages with yum Nico Schottelius diff --git a/cdist/conf/type/__package_zypper/man.rst b/cdist/conf/type/__package_zypper/man.rst index 2df22e72..74648c9e 100644 --- a/cdist/conf/type/__package_zypper/man.rst +++ b/cdist/conf/type/__package_zypper/man.rst @@ -1,6 +1,9 @@ cdist-type__package_zypper(7) ============================= -Manage packages with zypper + +NAME +---- +cdist-type__package_zypper - Manage packages with zypper Daniel Heule diff --git a/cdist/conf/type/__pacman_conf/man.rst b/cdist/conf/type/__pacman_conf/man.rst index 930035fa..0a8eb62a 100644 --- a/cdist/conf/type/__pacman_conf/man.rst +++ b/cdist/conf/type/__pacman_conf/man.rst @@ -1,6 +1,9 @@ cdist-type__pacman_conf(7) ========================== -Manage pacman configuration + +NAME +---- +cdist-type__pacman_conf - Manage pacman configuration Dominique Roux diff --git a/cdist/conf/type/__pacman_conf_integrate/man.rst b/cdist/conf/type/__pacman_conf_integrate/man.rst index 6a856efe..30ef6cd9 100644 --- a/cdist/conf/type/__pacman_conf_integrate/man.rst +++ b/cdist/conf/type/__pacman_conf_integrate/man.rst @@ -1,6 +1,9 @@ cdist-type__pacman_conf_integrate(7) ==================================== -Integrate default pacman.conf to cdist conform and vice versa + +NAME +---- +cdist-type__pacman_conf_integrate - Integrate default pacman.conf to cdist conform and vice versa Dominique Roux diff --git a/cdist/conf/type/__pf_apply/man.rst b/cdist/conf/type/__pf_apply/man.rst index 0b440e2d..acebcb96 100644 --- a/cdist/conf/type/__pf_apply/man.rst +++ b/cdist/conf/type/__pf_apply/man.rst @@ -1,12 +1,11 @@ cdist-type__pf_apply(7) ======================= -Apply pf(4) ruleset on \*BSD - -Jake Guffey - NAME ---- +cdist-type__pf_apply - Apply pf(4) ruleset on \*BSD + +Jake Guffey DESCRIPTION diff --git a/cdist/conf/type/__pf_ruleset/man.rst b/cdist/conf/type/__pf_ruleset/man.rst index b3e9b073..7edc0f91 100644 --- a/cdist/conf/type/__pf_ruleset/man.rst +++ b/cdist/conf/type/__pf_ruleset/man.rst @@ -1,6 +1,9 @@ cdist-type__pf_ruleset(7) ========================= -Copy a pf(4) ruleset to $__target_host + +NAME +---- +cdist-type__pf_ruleset - Copy a pf(4) ruleset to $__target_host Jake Guffey diff --git a/cdist/conf/type/__postfix/man.rst b/cdist/conf/type/__postfix/man.rst index d10a9960..73347e38 100644 --- a/cdist/conf/type/__postfix/man.rst +++ b/cdist/conf/type/__postfix/man.rst @@ -1,6 +1,9 @@ cdist-type__postfix(7) ====================== -Install postfix + +NAME +---- +cdist-type__postfix - Install postfix Steven Armstrong diff --git a/cdist/conf/type/__postfix_master/man.rst b/cdist/conf/type/__postfix_master/man.rst index 4853e687..86fa5f8c 100644 --- a/cdist/conf/type/__postfix_master/man.rst +++ b/cdist/conf/type/__postfix_master/man.rst @@ -1,6 +1,9 @@ cdist-type__postfix_master(7) ============================= -Configure postfix master.cf + +NAME +---- +cdist-type__postfix_master - Configure postfix master.cf Steven Armstrong diff --git a/cdist/conf/type/__postfix_postconf/man.rst b/cdist/conf/type/__postfix_postconf/man.rst index e07e136f..ab0192b8 100644 --- a/cdist/conf/type/__postfix_postconf/man.rst +++ b/cdist/conf/type/__postfix_postconf/man.rst @@ -1,6 +1,9 @@ cdist-type__postfix_postconf(7) =============================== -Configure postfix main.cf + +NAME +---- +cdist-type__postfix_postconf - Configure postfix main.cf Steven Armstrong diff --git a/cdist/conf/type/__postfix_postmap/man.rst b/cdist/conf/type/__postfix_postmap/man.rst index ecee6722..5e9d3c2d 100644 --- a/cdist/conf/type/__postfix_postmap/man.rst +++ b/cdist/conf/type/__postfix_postmap/man.rst @@ -1,6 +1,9 @@ cdist-type__postfix_postmap(7) ============================== -Run postmap on the given file + +NAME +---- +cdist-type__postfix_postmap - Run postmap on the given file Steven Armstrong diff --git a/cdist/conf/type/__postfix_reload/man.rst b/cdist/conf/type/__postfix_reload/man.rst index c5101953..330ed51c 100644 --- a/cdist/conf/type/__postfix_reload/man.rst +++ b/cdist/conf/type/__postfix_reload/man.rst @@ -1,6 +1,9 @@ cdist-type__postfix_reload(7) ============================= -Tell postfix to reload its configuration + +NAME +---- +cdist-type__postfix_reload - Tell postfix to reload its configuration Steven Armstrong diff --git a/cdist/conf/type/__postgres_database/man.rst b/cdist/conf/type/__postgres_database/man.rst index 152ee910..34cd2f03 100644 --- a/cdist/conf/type/__postgres_database/man.rst +++ b/cdist/conf/type/__postgres_database/man.rst @@ -1,6 +1,9 @@ cdist-type__postgres_database(7) ================================ -Create/drop postgres databases + +NAME +---- +cdist-type__postgres_database - Create/drop postgres databases Steven Armstrong diff --git a/cdist/conf/type/__postgres_role/man.rst b/cdist/conf/type/__postgres_role/man.rst index 6384568f..4b8d291f 100644 --- a/cdist/conf/type/__postgres_role/man.rst +++ b/cdist/conf/type/__postgres_role/man.rst @@ -1,6 +1,9 @@ cdist-type__postgres_role(7) ============================ -Manage postgres roles + +NAME +---- +cdist-type__postgres_role - Manage postgres roles Steven Armstrong diff --git a/cdist/conf/type/__process/man.rst b/cdist/conf/type/__process/man.rst index 09032a1a..3f17076d 100644 --- a/cdist/conf/type/__process/man.rst +++ b/cdist/conf/type/__process/man.rst @@ -1,6 +1,9 @@ cdist-type__process(7) ====================== -Start or stop process + +NAME +---- +cdist-type__process - Start or stop process Nico Schottelius diff --git a/cdist/conf/type/__pyvenv/man.rst b/cdist/conf/type/__pyvenv/man.rst index bdc1166c..ff7a922b 100755 --- a/cdist/conf/type/__pyvenv/man.rst +++ b/cdist/conf/type/__pyvenv/man.rst @@ -1,6 +1,9 @@ cdist-type__pyvenv(7) ===================== -Create or remove python virtual environment + +NAME +---- +cdist-type__pyvenv - Create or remove python virtual environment Darko Poljak diff --git a/cdist/conf/type/__qemu_img/man.rst b/cdist/conf/type/__qemu_img/man.rst index 598e06ab..4492c260 100644 --- a/cdist/conf/type/__qemu_img/man.rst +++ b/cdist/conf/type/__qemu_img/man.rst @@ -1,6 +1,9 @@ cdist-type__qemu_img(7) ======================= -Manage VM disk images + +NAME +---- +cdist-type__qemu_img - Manage VM disk images Nico Schottelius diff --git a/cdist/conf/type/__rbenv/man.rst b/cdist/conf/type/__rbenv/man.rst index 314507fe..d13f407c 100644 --- a/cdist/conf/type/__rbenv/man.rst +++ b/cdist/conf/type/__rbenv/man.rst @@ -1,6 +1,9 @@ cdist-type__rbenv(7) ==================== -Manage rbenv installation + +NAME +---- +cdist-type__rbenv - Manage rbenv installation Nico Schottelius diff --git a/cdist/conf/type/__rsync/man.rst b/cdist/conf/type/__rsync/man.rst index bc7b1bca..afca11d5 100644 --- a/cdist/conf/type/__rsync/man.rst +++ b/cdist/conf/type/__rsync/man.rst @@ -1,6 +1,9 @@ cdist-type__rsync(7) ==================== -Mirror directories using rsync + +NAME +---- +cdist-type__rsync - Mirror directories using rsync Nico Schottelius diff --git a/cdist/conf/type/__rvm/man.rst b/cdist/conf/type/__rvm/man.rst index 8a3f72f5..5aa264e0 100644 --- a/cdist/conf/type/__rvm/man.rst +++ b/cdist/conf/type/__rvm/man.rst @@ -1,6 +1,9 @@ cdist-type__rvm(7) ================== -Install rvm for a given user + +NAME +---- +cdist-type__rvm - Install rvm for a given user Evax Software diff --git a/cdist/conf/type/__rvm_gem/man.rst b/cdist/conf/type/__rvm_gem/man.rst index 39d93065..c6011f45 100644 --- a/cdist/conf/type/__rvm_gem/man.rst +++ b/cdist/conf/type/__rvm_gem/man.rst @@ -1,6 +1,9 @@ cdist-type__rvm_gemset(7) ========================== -Manage Ruby gems through rvm + +NAME +---- +cdist-type__rvm_gemset - Manage Ruby gems through rvm Evax Software diff --git a/cdist/conf/type/__rvm_gemset/man.rst b/cdist/conf/type/__rvm_gemset/man.rst index 422130cb..6792b14e 100644 --- a/cdist/conf/type/__rvm_gemset/man.rst +++ b/cdist/conf/type/__rvm_gemset/man.rst @@ -1,6 +1,9 @@ cdist-type__rvm_gemset(7) ========================== -Manage gemsets through rvm + +NAME +---- +cdist-type__rvm_gemset - Manage gemsets through rvm Evax Software diff --git a/cdist/conf/type/__rvm_ruby/man.rst b/cdist/conf/type/__rvm_ruby/man.rst index dbb1c9a2..235731cd 100644 --- a/cdist/conf/type/__rvm_ruby/man.rst +++ b/cdist/conf/type/__rvm_ruby/man.rst @@ -1,6 +1,9 @@ cdist-type__rvm_ruby(7) ======================= -Manage ruby installations through rvm + +NAME +---- +cdist-type__rvm_ruby - Manage ruby installations through rvm Evax Software diff --git a/cdist/conf/type/__ssh_authorized_key/man.rst b/cdist/conf/type/__ssh_authorized_key/man.rst index 984ea51b..767fb1d2 100644 --- a/cdist/conf/type/__ssh_authorized_key/man.rst +++ b/cdist/conf/type/__ssh_authorized_key/man.rst @@ -1,6 +1,9 @@ cdist-type__ssh_authorized_key(7) ================================= -Manage a single ssh authorized key entry + +NAME +---- +cdist-type__ssh_authorized_key - Manage a single ssh authorized key entry Steven Armstrong diff --git a/cdist/conf/type/__ssh_authorized_keys/man.rst b/cdist/conf/type/__ssh_authorized_keys/man.rst index 0907c2b3..54e294b3 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.rst +++ b/cdist/conf/type/__ssh_authorized_keys/man.rst @@ -1,6 +1,9 @@ cdist-type__ssh_authorized_keys(7) ================================== -Manage ssh authorized_keys files + +NAME +---- +cdist-type__ssh_authorized_keys - Manage ssh authorized_keys files Steven Armstrong diff --git a/cdist/conf/type/__ssh_dot_ssh/man.rst b/cdist/conf/type/__ssh_dot_ssh/man.rst index 1b84c924..12b4c2e7 100644 --- a/cdist/conf/type/__ssh_dot_ssh/man.rst +++ b/cdist/conf/type/__ssh_dot_ssh/man.rst @@ -1,12 +1,11 @@ cdist-type__ssh_dot_ssh(7) ========================== -Manage .ssh directory - -Nico Schottelius - NAME ---- +cdist-type__ssh_dot_ssh - Manage .ssh directory + +Nico Schottelius DESCRIPTION diff --git a/cdist/conf/type/__staged_file/man.rst b/cdist/conf/type/__staged_file/man.rst index ed977b28..aec11707 100644 --- a/cdist/conf/type/__staged_file/man.rst +++ b/cdist/conf/type/__staged_file/man.rst @@ -1,6 +1,9 @@ cdist-type__staged_file(7) ========================== -Manage staged files + +NAME +---- +cdist-type__staged_file - Manage staged files Steven Armstrong diff --git a/cdist/conf/type/__start_on_boot/man.rst b/cdist/conf/type/__start_on_boot/man.rst index 2fb2c7d9..2f07362b 100644 --- a/cdist/conf/type/__start_on_boot/man.rst +++ b/cdist/conf/type/__start_on_boot/man.rst @@ -1,6 +1,9 @@ cdist-type__start_on_boot(7) ============================ -Manage stuff to be started at boot + +NAME +---- +cdist-type__start_on_boot - Manage stuff to be started at boot Nico Schottelius diff --git a/cdist/conf/type/__timezone/man.rst b/cdist/conf/type/__timezone/man.rst index 083f4fe6..838f4c46 100644 --- a/cdist/conf/type/__timezone/man.rst +++ b/cdist/conf/type/__timezone/man.rst @@ -1,6 +1,9 @@ cdist-type__timezone(7) ======================= -Allows one to configure the desired localtime timezone. + +NAME +---- +cdist-type__timezone - Allows one to configure the desired localtime timezone. Ramon Salvadó diff --git a/cdist/conf/type/__update_alternatives/man.rst b/cdist/conf/type/__update_alternatives/man.rst index 477ee88c..f321b02f 100644 --- a/cdist/conf/type/__update_alternatives/man.rst +++ b/cdist/conf/type/__update_alternatives/man.rst @@ -1,6 +1,9 @@ cdist-type__update_alternatives(7) ================================== -Configure alternatives + +NAME +---- +cdist-type__update_alternatives - Configure alternatives Nico Schottelius diff --git a/cdist/conf/type/__user/man.rst b/cdist/conf/type/__user/man.rst index c690a559..6a055a4e 100644 --- a/cdist/conf/type/__user/man.rst +++ b/cdist/conf/type/__user/man.rst @@ -1,6 +1,9 @@ cdist-type__user(7) =================== -Manage users + +NAME +---- +cdist-type__user - Manage users Steven Armstrong diff --git a/cdist/conf/type/__user_groups/man.rst b/cdist/conf/type/__user_groups/man.rst index 4458a6cf..8857feb1 100644 --- a/cdist/conf/type/__user_groups/man.rst +++ b/cdist/conf/type/__user_groups/man.rst @@ -1,6 +1,9 @@ cdist-type__user_groups(7) ========================== -Manage user groups + +NAME +---- +cdist-type__user_groups - Manage user groups Steven Armstrong diff --git a/cdist/conf/type/__yum_repo/man.rst b/cdist/conf/type/__yum_repo/man.rst index 396f271c..3df9f1b9 100644 --- a/cdist/conf/type/__yum_repo/man.rst +++ b/cdist/conf/type/__yum_repo/man.rst @@ -1,6 +1,9 @@ cdist-type__yum_repo(7) ======================= -Manage yum repositories + +NAME +---- +cdist-type__yum_repo - Manage yum repositories Steven Armstrong diff --git a/cdist/conf/type/__zypper_repo/man.rst b/cdist/conf/type/__zypper_repo/man.rst index e3bc1d4f..d1b87a5b 100644 --- a/cdist/conf/type/__zypper_repo/man.rst +++ b/cdist/conf/type/__zypper_repo/man.rst @@ -1,6 +1,9 @@ cdist-type__zypper_repo(7) ========================== -Repository management with zypper + +NAME +---- +cdist-type__zypper_repo - Repository management with zypper Daniel Heule diff --git a/cdist/conf/type/__zypper_service/man.rst b/cdist/conf/type/__zypper_service/man.rst index 377d30e1..9d538208 100644 --- a/cdist/conf/type/__zypper_service/man.rst +++ b/cdist/conf/type/__zypper_service/man.rst @@ -1,6 +1,9 @@ cdist-type__zypper_service(7) ============================= -Service management with zypper + +NAME +---- +cdist-type__zypper_service - Service management with zypper Daniel Heule diff --git a/cdist/sphinxext/__init__.py b/cdist/sphinxext/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cdist/sphinxext/manpage.py b/cdist/sphinxext/manpage.py new file mode 100644 index 00000000..433f6a1b --- /dev/null +++ b/cdist/sphinxext/manpage.py @@ -0,0 +1,80 @@ +import sphinx.builders.manpage +import sphinx.writers.manpage +from docutils.frontend import OptionParser +from sphinx.util.console import bold, darkgreen +from six import string_types +from docutils.io import FileOutput +from os import path +from sphinx.util.nodes import inline_all_toctrees +from sphinx import addnodes + +""" + Extension based on sphinx builtin manpage. + It does not write its own .SH NAME based on config, + but leaves everything to actual reStructuredText file content. +""" + +class ManualPageTranslator(sphinx.writers.manpage.ManualPageTranslator): + + def header(self): + tmpl = (".TH \"%(title_upper)s\" \"%(manual_section)s\"" + " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n") + return tmpl % self._docinfo + + +class ManualPageWriter(sphinx.writers.manpage.ManualPageWriter): + + def __init__(self, builder): + super().__init__(builder) + self.translator_class = ( + self.builder.translator_class or ManualPageTranslator) + + +class ManualPageBuilder(sphinx.builders.manpage.ManualPageBuilder): + + name = 'cman' + + def write(self, *ignored): + docwriter = ManualPageWriter(self) + docsettings = OptionParser( + defaults=self.env.settings, + components=(docwriter,), + read_config_files=True).get_default_values() + + self.info(bold('writing... '), nonl=True) + + for info in self.config.man_pages: + docname, name, description, authors, section = info + if isinstance(authors, string_types): + if authors: + authors = [authors] + else: + authors = [] + + targetname = '%s.%s' % (name, section) + self.info(darkgreen(targetname) + ' { ', nonl=True) + destination = FileOutput( + destination_path=path.join(self.outdir, targetname), + encoding='utf-8') + + tree = self.env.get_doctree(docname) + docnames = set() + largetree = inline_all_toctrees(self, docnames, docname, tree, + darkgreen, [docname]) + self.info('} ', nonl=True) + self.env.resolve_references(largetree, docname, self) + # remove pending_xref nodes + for pendingnode in largetree.traverse(addnodes.pending_xref): + pendingnode.replace_self(pendingnode.children) + + largetree.settings = docsettings + largetree.settings.title = name + largetree.settings.subtitle = description + largetree.settings.authors = authors + largetree.settings.section = section + + docwriter.write(largetree, destination) + self.info() + +def setup(app): + app.add_builder(ManualPageBuilder) diff --git a/docs/man/Makefile b/docs/man/Makefile index c2e398c5..6d3ec6dc 100644 --- a/docs/man/Makefile +++ b/docs/man/Makefile @@ -161,7 +161,7 @@ text: .PHONY: man man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + $(SPHINXBUILD) -b cman $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." diff --git a/docs/man/cdist-reference.rst.sh b/docs/man/cdist-reference.rst.sh index 0dd7c634..687394d2 100755 --- a/docs/man/cdist-reference.rst.sh +++ b/docs/man/cdist-reference.rst.sh @@ -37,7 +37,10 @@ exec > "$dest" cat << eof cdist-reference(7) ================== -Variable, path and type reference for cdist + +NAME +---- +cdist-reference - Variable, path and type reference for cdist Nico Schottelius diff --git a/docs/man/conf.py b/docs/man/conf.py index 7df4ed25..d8843011 100644 --- a/docs/man/conf.py +++ b/docs/man/conf.py @@ -29,7 +29,9 @@ import os # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] +extensions = [ + 'cdist.sphinxext.manpage', +] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -257,15 +259,18 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -mandir = os.path.dirname(os.path.realpath(__file__)) -man_pages = [] +root_mandir = os.path.dirname(os.path.realpath(__file__)) +mandirs = [] for mansubdir in ('man1', 'man7'): - for root, dirs, files in os.walk(os.path.join(mandir, mansubdir)): + mandirs.append((os.path.join(root_mandir, mansubdir), mansubdir[-1])) +man_pages = [] +for mandir, section in mandirs: + for root, dirs, files in os.walk(mandir): for fname in files: froot, fext = os.path.splitext(fname) if fext == '.rst': - man_page = (os.path.join(mansubdir, froot), froot, '', - [], mansubdir[-1]) + man_page = (os.path.join('man' + str(section), froot), + froot, '', [], section) man_pages.append(man_page) #man_pages = [ diff --git a/docs/man/man1/cdist.rst b/docs/man/man1/cdist.rst index 21edee11..f2b4c5d4 100644 --- a/docs/man/man1/cdist.rst +++ b/docs/man/man1/cdist.rst @@ -1,6 +1,9 @@ cdist(1) ======== -Usable Configuration Management + +NAME +---- +cdist - Usable Configuration Management Nico Schottelius diff --git a/docs/man/man7/cdist-best-practice.rst b/docs/man/man7/cdist-best-practice.rst index 13d65cce..7c19c038 100644 --- a/docs/man/man7/cdist-best-practice.rst +++ b/docs/man/man7/cdist-best-practice.rst @@ -1,6 +1,9 @@ cdist-best-practice(7) ====================== -Practices used in real environments + +NAME +---- +cdist-best-practice - Practices used in real environments Nico Schottelius diff --git a/docs/man/man7/cdist-bootstrap.rst b/docs/man/man7/cdist-bootstrap.rst index df55e2af..6a070afa 100644 --- a/docs/man/man7/cdist-bootstrap.rst +++ b/docs/man/man7/cdist-bootstrap.rst @@ -1,6 +1,9 @@ cdist-bootstrap(7) ================== -Setup cdist environment + +NAME +---- +cdist-bootstrap - Setup cdist environment Nico Schottelius diff --git a/docs/man/man7/cdist-explorer.rst b/docs/man/man7/cdist-explorer.rst index 1bbd7e75..66c20d67 100644 --- a/docs/man/man7/cdist-explorer.rst +++ b/docs/man/man7/cdist-explorer.rst @@ -1,6 +1,9 @@ cdist-explorer(7) ================= -Explore the target systems + +NAME +---- +cdist-explorer - Explore the target systems Nico Schottelius diff --git a/docs/man/man7/cdist-hacker.rst b/docs/man/man7/cdist-hacker.rst index 1d0e7f2e..4e3a21b6 100644 --- a/docs/man/man7/cdist-hacker.rst +++ b/docs/man/man7/cdist-hacker.rst @@ -1,6 +1,9 @@ cdist-hacker(7) =============== -How to get (stuff) into cdist + +NAME +---- +cdist-hacker - How to get (stuff) into cdist Nico Schottelius diff --git a/docs/man/man7/cdist-manifest.rst b/docs/man/man7/cdist-manifest.rst index c8984acf..04609b73 100644 --- a/docs/man/man7/cdist-manifest.rst +++ b/docs/man/man7/cdist-manifest.rst @@ -1,6 +1,9 @@ cdist-manifest(7) ================= -(Re-)Use types + +NAME +---- +cdist-manifest - (Re-)Use types Nico Schottelius diff --git a/docs/man/man7/cdist-messaging.rst b/docs/man/man7/cdist-messaging.rst index 6f29a363..b0d5e3b4 100644 --- a/docs/man/man7/cdist-messaging.rst +++ b/docs/man/man7/cdist-messaging.rst @@ -1,6 +1,9 @@ cdist-messaging(7) ================== -How the initial manifest and types can communication + +NAME +---- +cdist-messaging - How the initial manifest and types can communication Nico Schottelius diff --git a/docs/man/man7/cdist-quickstart.rst b/docs/man/man7/cdist-quickstart.rst index d1186ffe..fd7d2cde 100644 --- a/docs/man/man7/cdist-quickstart.rst +++ b/docs/man/man7/cdist-quickstart.rst @@ -1,6 +1,9 @@ cdist-quickstart(7) =================== -Jump in and enjoy cdist + +NAME +---- +cdist-quickstart - Jump in and enjoy cdist Nico Schottelius diff --git a/docs/man/man7/cdist-remote-exec-copy.rst b/docs/man/man7/cdist-remote-exec-copy.rst index 27b78d42..b8d54f8f 100644 --- a/docs/man/man7/cdist-remote-exec-copy.rst +++ b/docs/man/man7/cdist-remote-exec-copy.rst @@ -1,6 +1,9 @@ cdist-remote-exec-copy(7) ========================= -How to use remote exec and copy + +NAME +---- +cdist-remote-exec-copy - How to use remote exec and copy Nico Schottelius diff --git a/docs/man/man7/cdist-stages.rst b/docs/man/man7/cdist-stages.rst index 4b29585d..b58bb368 100644 --- a/docs/man/man7/cdist-stages.rst +++ b/docs/man/man7/cdist-stages.rst @@ -1,6 +1,9 @@ cdist-stages(7) =============== -Stages used during configuration deployment + +NAME +---- +cdist-stages - Stages used during configuration deployment Nico Schottelius diff --git a/docs/man/man7/cdist-troubleshooting.rst b/docs/man/man7/cdist-troubleshooting.rst index 075c3480..edfadc34 100644 --- a/docs/man/man7/cdist-troubleshooting.rst +++ b/docs/man/man7/cdist-troubleshooting.rst @@ -1,6 +1,9 @@ cdist-troubleshooting(7) ======================== -Common problems and their solutions + +NAME +---- +cdist-troubleshooting - Common problems and their solutions Nico Schottelius diff --git a/docs/man/man7/cdist-tutorial.rst b/docs/man/man7/cdist-tutorial.rst index 4899dcb0..fece6f36 100644 --- a/docs/man/man7/cdist-tutorial.rst +++ b/docs/man/man7/cdist-tutorial.rst @@ -1,6 +1,9 @@ cdist-tutorial(7) ================= -A guided introduction into cdist + +NAME +---- +cdist-tutorial - A guided introduction into cdist Nico Schottelius diff --git a/docs/man/man7/cdist-type.rst b/docs/man/man7/cdist-type.rst index cfd331e1..5500d9b3 100644 --- a/docs/man/man7/cdist-type.rst +++ b/docs/man/man7/cdist-type.rst @@ -1,6 +1,9 @@ cdist-type(7) ============= -Functionality bundled + +NAME +---- +cdist-type - Functionality bundled Nico Schottelius From f6ea90c3a50f757871504675084c8da70ca76097 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 24 Jun 2016 11:18:24 +0200 Subject: [PATCH 0164/1332] Update remote.py according to new exec_util api. --- cdist/exec/remote.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index c78f02cb..0331f402 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -168,14 +168,13 @@ class Remote(object): self.log.debug("Remote run: %s", command) try: - output = exec_util.call_get_output(command, env=os_environ) - self.log.debug("Remote output: {}".format(output)) + output, errout = exec_util.call_get_output(command, env=os_environ) + self.log.debug("Remote stdout: {}".format(output)) + self.log.debug("Remote stderr: {}".format(errout)) if return_output: return output.decode() except subprocess.CalledProcessError as e: - raise cdist.Error("Command failed: " + " ".join(command) - + " with returncode: {} and output: {}".format( - e.returncode, e.output)) + exec_util.handle_called_process_error(e, command) except OSError as error: raise cdist.Error(" ".join(command) + ": " + error.args[1]) except UnicodeDecodeError: From 7a9a04592bce29196e8d4df8ba05fea191fad4b8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 25 Jun 2016 19:30:22 +0200 Subject: [PATCH 0165/1332] Fix Makefile for dotman target. --- Makefile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index d00739bb..faa8e9d5 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,8 @@ MAN7DSTDIR=$(MANDIR)/man7 # Manpages #1: Types # Use shell / ls to get complete list - $(TYPEDIR)/*/man.rst does not work -MANTYPESRC=$(shell ls $(TYPEDIR)/*/man.rst) +# Using ls does not work if no file with given pattern exist, so use wildcard +MANTYPESRC=$(wildcard $(TYPEDIR)/*/man.rst) MANTYPEPREFIX=$(subst $(TYPEDIR)/,$(MAN7DSTDIR)/cdist-type,$(MANTYPESRC)) MANTYPES=$(subst /man.rst,.rst,$(MANTYPEPREFIX)) @@ -92,13 +93,9 @@ man-latest-link: web-pub DOT_CDIST_PATH=${HOME}/.cdist DOTMAN7DSTDIR=$(MAN7DSTDIR) DOTTYPEDIR=$(DOT_CDIST_PATH)/type -$(info $(DOTTYPEDIR)) -DOTMANTYPESRC=$(shell ls $(DOTTYPEDIR)/*/man.rst) -$(info $(DOTMANTYPESRC)) +DOTMANTYPESRC=$(wildcard $(DOTTYPEDIR)/*/man.rst) DOTMANTYPEPREFIX=$(subst $(DOTTYPEDIR)/,$(DOTMAN7DSTDIR)/cdist-type,$(DOTMANTYPESRC)) -$(info $(DOTMANTYPEPREFIX)) DOTMANTYPES=$(subst /man.rst,.rst,$(DOTMANTYPEPREFIX)) -$(info $(DOTMANTYPES)) # Link manpage: do not create man.html but correct named file $(DOTMAN7DSTDIR)/cdist-type%.rst: $(DOTTYPEDIR)/%/man.rst From a220d4805a57027a728ad6c8d126d39ec9abc65d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 26 Jun 2016 16:28:10 +0200 Subject: [PATCH 0166/1332] Add cdist dir to sys.path for sphinx ext and cdist modules. --- docs/man/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/man/conf.py b/docs/man/conf.py index d8843011..ed43d6d4 100644 --- a/docs/man/conf.py +++ b/docs/man/conf.py @@ -20,6 +20,7 @@ import os # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../"))) # -- General configuration ------------------------------------------------ From 51c94e9e8252443d9b9787fcafe51c07da1737e5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 17 Jun 2016 21:28:16 +0200 Subject: [PATCH 0167/1332] Restructure and fix and improve docs and manpages. --- .gitignore | 2 +- Makefile | 4 +- bin/build-helper.freebsd | 336 ++++++++++++++++++ cdist/conf/type/__apt_key/man.rst | 10 +- cdist/conf/type/__apt_key_uri/man.rst | 10 +- cdist/conf/type/__apt_norecommends/man.rst | 10 +- cdist/conf/type/__apt_ppa/man.rst | 10 +- cdist/conf/type/__apt_source/man.rst | 10 +- cdist/conf/type/__apt_update_index/man.rst | 10 +- cdist/conf/type/__block/man.rst | 10 +- cdist/conf/type/__ccollect_source/man.rst | 16 +- cdist/conf/type/__cdist/man.rst | 10 +- cdist/conf/type/__cdistmarker/man.rst | 10 +- cdist/conf/type/__config_file/man.rst | 13 +- cdist/conf/type/__consul/man.rst | 10 +- cdist/conf/type/__consul_agent/man.rst | 13 +- cdist/conf/type/__consul_check/man.rst | 13 +- cdist/conf/type/__consul_reload/man.rst | 10 +- cdist/conf/type/__consul_service/man.rst | 13 +- cdist/conf/type/__consul_template/man.rst | 13 +- .../type/__consul_template_template/man.rst | 15 +- cdist/conf/type/__consul_watch_checks/man.rst | 16 +- cdist/conf/type/__consul_watch_event/man.rst | 16 +- cdist/conf/type/__consul_watch_key/man.rst | 16 +- .../type/__consul_watch_keyprefix/man.rst | 15 +- cdist/conf/type/__consul_watch_nodes/man.rst | 16 +- .../conf/type/__consul_watch_service/man.rst | 15 +- .../conf/type/__consul_watch_services/man.rst | 16 +- cdist/conf/type/__cron/man.rst | 13 +- .../type/__debconf_set_selections/man.rst | 15 +- cdist/conf/type/__directory/man.rst | 10 +- cdist/conf/type/__dog_vdi/man.rst | 14 +- cdist/conf/type/__file/man.rst | 10 +- cdist/conf/type/__firewalld_rule/man.rst | 15 +- cdist/conf/type/__git/man.rst | 10 +- cdist/conf/type/__group/man.rst | 10 +- cdist/conf/type/__hostname/man.rst | 10 +- cdist/conf/type/__iptables_apply/man.rst | 15 +- cdist/conf/type/__iptables_rule/man.rst | 15 +- cdist/conf/type/__issue/man.rst | 10 +- cdist/conf/type/__jail/man.rst | 10 +- cdist/conf/type/__jail_freebsd10/man.rst | 10 +- cdist/conf/type/__jail_freebsd9/man.rst | 10 +- cdist/conf/type/__key_value/man.rst | 10 +- cdist/conf/type/__line/man.rst | 13 +- cdist/conf/type/__link/man.rst | 10 +- cdist/conf/type/__locale/man.rst | 14 +- cdist/conf/type/__motd/man.rst | 10 +- cdist/conf/type/__mount/man.rst | 10 +- cdist/conf/type/__mysql_database/man.rst | 10 +- cdist/conf/type/__package/man.rst | 10 +- cdist/conf/type/__package_apt/man.rst | 13 +- cdist/conf/type/__package_emerge/man.rst | 15 +- .../__package_emerge_dependencies/man.rst | 15 +- cdist/conf/type/__package_luarocks/man.rst | 13 +- cdist/conf/type/__package_opkg/man.rst | 13 +- cdist/conf/type/__package_pacman/man.rst | 13 +- cdist/conf/type/__package_pip/man.rst | 13 +- cdist/conf/type/__package_pkg_freebsd/man.rst | 13 +- cdist/conf/type/__package_pkg_openbsd/man.rst | 13 +- .../conf/type/__package_pkgng_freebsd/man.rst | 13 +- cdist/conf/type/__package_rubygem/man.rst | 13 +- .../conf/type/__package_update_index/man.rst | 10 +- cdist/conf/type/__package_upgrade_all/man.rst | 10 +- cdist/conf/type/__package_yum/man.rst | 13 +- cdist/conf/type/__package_zypper/man.rst | 13 +- cdist/conf/type/__pacman_conf/man.rst | 13 +- .../conf/type/__pacman_conf_integrate/man.rst | 13 +- cdist/conf/type/__pf_apply/man.rst | 15 +- cdist/conf/type/__pf_ruleset/man.rst | 13 +- cdist/conf/type/__postfix/man.rst | 10 +- cdist/conf/type/__postfix_master/man.rst | 13 +- cdist/conf/type/__postfix_postconf/man.rst | 13 +- cdist/conf/type/__postfix_postmap/man.rst | 10 +- cdist/conf/type/__postfix_reload/man.rst | 10 +- cdist/conf/type/__postgres_database/man.rst | 13 +- cdist/conf/type/__postgres_role/man.rst | 16 +- cdist/conf/type/__process/man.rst | 13 +- cdist/conf/type/__pyvenv/man.rst | 10 +- cdist/conf/type/__qemu_img/man.rst | 13 +- cdist/conf/type/__rbenv/man.rst | 10 +- cdist/conf/type/__rsync/man.rst | 13 +- cdist/conf/type/__rvm/man.rst | 17 +- cdist/conf/type/__rvm_gem/man.rst | 17 +- cdist/conf/type/__rvm_gemset/man.rst | 17 +- cdist/conf/type/__rvm_ruby/man.rst | 17 +- cdist/conf/type/__ssh_authorized_key/man.rst | 15 +- cdist/conf/type/__ssh_authorized_keys/man.rst | 13 +- cdist/conf/type/__ssh_dot_ssh/man.rst | 13 +- cdist/conf/type/__staged_file/man.rst | 13 +- cdist/conf/type/__start_on_boot/man.rst | 13 +- cdist/conf/type/__timezone/man.rst | 10 +- cdist/conf/type/__update_alternatives/man.rst | 15 +- cdist/conf/type/__user/man.rst | 13 +- cdist/conf/type/__user_groups/man.rst | 10 +- cdist/conf/type/__yum_repo/man.rst | 10 +- cdist/conf/type/__zypper_repo/man.rst | 10 +- cdist/conf/type/__zypper_service/man.rst | 10 +- docs/changelog | 1 + docs/man/Makefile | 2 +- docs/man/{man7 => }/cdist-best-practice.rst | 44 +-- docs/man/{man7 => }/cdist-bootstrap.rst | 40 +-- docs/man/{man7 => }/cdist-explorer.rst | 28 +- docs/man/cdist-features.rst | 48 +++ docs/man/{man7 => }/cdist-hacker.rst | 47 +-- docs/man/cdist-install.rst | 105 ++++++ docs/man/cdist-intro.rst | 15 + docs/man/cdist-logo.png | Bin 0 -> 1542 bytes docs/man/{man7 => }/cdist-manifest.rst | 45 +-- docs/man/{man7 => }/cdist-messaging.rst | 32 +- docs/man/cdist-os.rst | 16 + docs/man/{man7 => }/cdist-quickstart.rst | 37 +- docs/man/cdist-reference.rst.sh | 63 ++-- .../man/{man7 => }/cdist-remote-exec-copy.rst | 29 +- docs/man/{man7 => }/cdist-stages.rst | 40 +-- docs/man/cdist-support.rst | 28 ++ docs/man/{man7 => }/cdist-troubleshooting.rst | 25 +- docs/man/{man7 => }/cdist-type.rst | 78 ++-- docs/man/cdist-types.rst | 8 + docs/man/cdist-update.rst | 188 ++++++++++ docs/man/cdist-why.rst | 72 ++++ docs/man/conf.py | 7 + docs/man/index.rst | 25 +- docs/man/man1/cdist.rst | 8 +- docs/man/man7/cdist-tutorial.rst | 58 --- 125 files changed, 1799 insertions(+), 816 deletions(-) create mode 100755 bin/build-helper.freebsd mode change 100755 => 100644 cdist/conf/type/__pyvenv/man.rst rename docs/man/{man7 => }/cdist-best-practice.rst (90%) rename docs/man/{man7 => }/cdist-bootstrap.rst (86%) rename docs/man/{man7 => }/cdist-explorer.rst (75%) create mode 100644 docs/man/cdist-features.rst rename docs/man/{man7 => }/cdist-hacker.rst (86%) create mode 100644 docs/man/cdist-install.rst create mode 100644 docs/man/cdist-intro.rst create mode 100644 docs/man/cdist-logo.png rename docs/man/{man7 => }/cdist-manifest.rst (92%) rename docs/man/{man7 => }/cdist-messaging.rst (79%) create mode 100644 docs/man/cdist-os.rst rename docs/man/{man7 => }/cdist-quickstart.rst (82%) rename docs/man/{man7 => }/cdist-remote-exec-copy.rst (61%) rename docs/man/{man7 => }/cdist-stages.rst (77%) create mode 100644 docs/man/cdist-support.rst rename docs/man/{man7 => }/cdist-troubleshooting.rst (73%) rename docs/man/{man7 => }/cdist-type.rst (88%) create mode 100644 docs/man/cdist-types.rst create mode 100644 docs/man/cdist-update.rst create mode 100644 docs/man/cdist-why.rst delete mode 100644 docs/man/man7/cdist-tutorial.rst diff --git a/.gitignore b/.gitignore index 2a193c2a..6152451b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ docs/man/man*/*.html docs/man/man*/*.xml docs/man/man*/docbook-xsl.css docs/man/man7/cdist-type__*.rst -docs/man/man7/cdist-reference.rst +docs/man/cdist-reference.rst # Ignore cdist cache for version control /cache/ diff --git a/Makefile b/Makefile index faa8e9d5..9f3535fd 100644 --- a/Makefile +++ b/Makefile @@ -63,10 +63,10 @@ $(MANREF): $(MANREFSH) $(MANREFSH) # Manpages #3: generic part -mansphinxman: $(MANTYPES) $(MANREF) +mansphinxman: $(MANTYPES) $(MANREF) $(PYTHON_VERSION) $(SPHINXM) -mansphinxhtml: $(MANTYPES) $(MANREF) +mansphinxhtml: $(MANTYPES) $(MANREF) $(PYTHON_VERSION) $(SPHINXH) man: mansphinxman mansphinxhtml diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd new file mode 100755 index 00000000..01d86a10 --- /dev/null +++ b/bin/build-helper.freebsd @@ -0,0 +1,336 @@ +#!/bin/sh +# +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2016 Darko Poljak (darko.poljak 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 . +# +# +# This file contains the heavy lifting found usually in the Makefile +# + +# vars for make +helper=$0 + +basedir=${0%/*}/../ +# run_as is used to check how the script is called (by $0 value) +# currently supported sufixes for $0 are: +# .freebsd - run as freebsd +basename=${0##*/} +run_as=${basename#*.} +case "$run_as" in + freebsd) + to_a=cdist-configuration-management + to_d=googlegroups.com + from_a=darko.poljak + from_d=gmail.com + ml_name="Darko Poljak" + ml_sig_name="Darko" + + # vars for make + WEBDIR=../vcs/www.nico.schottelius.org + ;; + *) + to_a=cdist + to_d=l.schottelius.org + from_a=nico-cdist + from_d=schottelius.org + ml_name="Nico -telmich- Schottelius" + ml_sig_name="Nico" + + # vars for make + WEBDIR=$$HOME/vcs/www.nico.schottelius.org + ;; +esac + +# Change to checkout directory +cd "$basedir" + +version=$(git describe) + +option=$1; shift + +case "$option" in + print-make-vars) + printf "helper: ${helper}\n" + printf "WEBDIR: ${WEBDIR}\n" + ;; + print-runas) + printf "run_as: $run_as\n" + ;; + changelog-changes) + if [ "$#" -eq 1 ]; then + start=$1 + else + start="[[:digit:]]" + fi + + end="[[:digit:]]" + + awk -F: "BEGIN { start=0 } + { + if(start == 0) { + if (\$0 ~ /^$start/) { + start = 1 + } + } else { + if (\$0 ~ /^$end/) { + exit + } else { + print \$0 + } + } + }" "$basedir/docs/changelog" + ;; + + changelog-version) + # get version from changelog + grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/:.*//' + ;; + + check-date) + # verify date in changelog is today + date_today="$(date +%Y-%m-%d)" + date_changelog=$(grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/.*: //') + + if [ "$date_today" != "$date_changelog" ]; then + echo "Date in changelog is not today" + echo "Changelog: $date_changelog" + exit 1 + fi + ;; + + check-unittest) + "$0" test + ;; + + blog) + version=$1; shift + blogfile=$1; shift + dir=${blogfile%/*} + file=${blogfile##*/} + + + cat << eof > "$blogfile" +[[!meta title="Cdist $version released"]] + +Here's a short overview about the changes found in version ${version}: + +eof + + $0 changelog-changes "$version" >> "$blogfile" + + cat << eof >> "$blogfile" +For more information visit the [[cdist homepage|software/cdist]]. + +[[!tag cdist config unix]] +eof + cd "$dir" + git add "$file" + # Allow git commit to fail if there are no changes + git commit -m "cdist blog update: $version" "$blogfile" || true + ;; + + ml-release) + if [ $# -ne 1 ]; then + echo "$0 ml-release version" >&2 + exit 1 + fi + + version=$1; shift + + to=${to_a}@${to_d} + from=${from_a}@${from_d} + + ( + cat << eof +From: ${ml_name} <$from> +To: cdist mailing list <$to> +Subject: cdist $version released + +Hello .*, + +cdist $version has been released with the following changes: + +eof + + "$0" changelog-changes "$version" + cat << eof + +Cheers, + +${ml_sig_name} + +-- +Automatisation at its best level. With cdist. +eof + ) | /usr/sbin/sendmail -f "$from" "$to" + ;; + + release-git-tag) + target_version=$($0 changelog-version) + if git rev-parse --verify refs/tags/$target_version 2>/dev/null; then + echo "Tag for $target_version exists, aborting" + exit 1 + fi + printf "Enter tag description for ${target_version}: " + read tagmessage + git tag "$target_version" -m "$$tagmessage" + ;; + + release) + set -e + target_version=$($0 changelog-version) + target_branch=$($0 version-branch) + + echo "Beginning release process for $target_version" + + # First check everything is sane + "$0" check-date + "$0" check-unittest + + # Generate version file to be included in packaging + "$0" version + + # Ensure the git status is clean, else abort + if ! git diff-index --name-only --exit-code HEAD ; then + echo "Unclean tree, see files above, aborting" + exit 1 + fi + + # Ensure we are on the master branch + masterbranch=yes + if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ]; then + echo "Releases are happening from the master branch, aborting" + + echo "Enter the magic word to release anyway" + read magicword + + if [ "$magicword" = "iknowwhatido" ]; then + masterbranch=no + else + exit 1 + fi + fi + + if [ "$masterbranch" = yes ]; then + # Ensure version branch exists + if ! git rev-parse --verify refs/heads/$target_branch 2>/dev/null; then + git branch "$target_branch" + fi + + # Merge master branch into version branch + git checkout "$target_branch" + git merge master + fi + + # Verify that after the merge everything works + "$0" check-date + "$0" check-unittest + + # Generate man pages (indirect check if they build) + make helper=${helper} WEBDIR=${WEBDIR} man + + # Generate speeches (indirect check if they build) + make helper=${helper} WEBDIR=${WEBDIR} speeches + + ############################################################# + # Everything green, let's do the release + + # Tag the current commit + "$0" release-git-tag + + # Also merge back the version branch + if [ "$masterbranch" = yes ]; then + git checkout master + git merge "$target_branch" + fi + + # Publish git changes + make helper=${helper} WEBDIR=${WEBDIR} pub + + # publish man, speeches, website + if [ "$masterbranch" = yes ]; then + make helper=${helper} WEBDIR=${WEBDIR} web-release-all + else + make helper=${helper} WEBDIR=${WEBDIR} web-release-all-no-latest + fi + + # Ensure that pypi release has the right version + "$0" version + + # Create and publish package for pypi + make helper=${helper} WEBDIR=${WEBDIR} pypi-release + + case "$run_as" in + freebsd) + ;; + *) + # Archlinux release is based on pypi + make archlinux-release + ;; + esac + + # Announce change on ML + make helper=${helper} WEBDIR=${WEBDIR} ml-release + + cat << eof +Manual steps post release: + + - linkedin + - hackernews + - reddit + - twitter + +eof + + case "$run_as" in + freebsd) + cat < cdist/version.py + ;; + + *) + echo "Unknown helper target $@ - aborting" + exit 1 + ;; + +esac diff --git a/cdist/conf/type/__apt_key/man.rst b/cdist/conf/type/__apt_key/man.rst index cb4c4108..01d4eea4 100644 --- a/cdist/conf/type/__apt_key/man.rst +++ b/cdist/conf/type/__apt_key/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__apt_key - Manage the list of keys used by apt -Steven Armstrong - DESCRIPTION ----------- @@ -52,7 +50,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__apt_key_uri/man.rst b/cdist/conf/type/__apt_key_uri/man.rst index ee8d1601..9c0042bb 100644 --- a/cdist/conf/type/__apt_key_uri/man.rst +++ b/cdist/conf/type/__apt_key_uri/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__apt_key_uri - Add apt key from uri -Steven Armstrong - DESCRIPTION ----------- @@ -42,7 +40,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__apt_norecommends/man.rst b/cdist/conf/type/__apt_norecommends/man.rst index 09ea9d16..0198d7bd 100644 --- a/cdist/conf/type/__apt_norecommends/man.rst +++ b/cdist/conf/type/__apt_norecommends/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__apt_norecommends - Configure apt to not install recommended packages -Steven Armstrong - DESCRIPTION ----------- @@ -33,7 +31,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__apt_ppa/man.rst b/cdist/conf/type/__apt_ppa/man.rst index 922b18d5..e91e82fe 100644 --- a/cdist/conf/type/__apt_ppa/man.rst +++ b/cdist/conf/type/__apt_ppa/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__apt_ppa - Manage ppa repositories -Steven Armstrong - DESCRIPTION ----------- @@ -41,7 +39,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__apt_source/man.rst b/cdist/conf/type/__apt_source/man.rst index 2e09aee5..e4916515 100644 --- a/cdist/conf/type/__apt_source/man.rst +++ b/cdist/conf/type/__apt_source/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__apt_source - Manage apt sources -Steven Armstrong - DESCRIPTION ----------- @@ -60,7 +58,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__apt_update_index/man.rst b/cdist/conf/type/__apt_update_index/man.rst index ce8610f3..e0672620 100644 --- a/cdist/conf/type/__apt_update_index/man.rst +++ b/cdist/conf/type/__apt_update_index/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__apt_update_index - Update apt's package index -Steven Armstrong - DESCRIPTION ----------- @@ -32,7 +30,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__block/man.rst b/cdist/conf/type/__block/man.rst index bd5304d8..3b7c3439 100644 --- a/cdist/conf/type/__block/man.rst +++ b/cdist/conf/type/__block/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__block - Manage blocks of text in files -Steven Armstrong - DESCRIPTION ----------- @@ -73,7 +71,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__ccollect_source/man.rst b/cdist/conf/type/__ccollect_source/man.rst index 29baa5c4..5d980bda 100644 --- a/cdist/conf/type/__ccollect_source/man.rst +++ b/cdist/conf/type/__ccollect_source/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__ccollect_source - Manage ccollect sources -Nico Schottelius - DESCRIPTION ----------- @@ -55,9 +53,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- ccollect(1) -- http://www.nico.schottelius.org/software/ccollect/ +ccollect(1) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +ccollect documentation at: +. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__cdist/man.rst b/cdist/conf/type/__cdist/man.rst index c0e8365e..ad544c5c 100644 --- a/cdist/conf/type/__cdist/man.rst +++ b/cdist/conf/type/__cdist/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__cdist - Manage cdist installations -Nico Schottelius - DESCRIPTION ----------- @@ -54,7 +52,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__cdistmarker/man.rst b/cdist/conf/type/__cdistmarker/man.rst index efd696ef..156aed62 100644 --- a/cdist/conf/type/__cdistmarker/man.rst +++ b/cdist/conf/type/__cdistmarker/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__cdistmarker - Add a timestamped cdist marker. -Daniel Maher - DESCRIPTION ----------- @@ -46,7 +44,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Daniel Maher COPYING diff --git a/cdist/conf/type/__config_file/man.rst b/cdist/conf/type/__config_file/man.rst index 8eec81b0..acb3c848 100644 --- a/cdist/conf/type/__config_file/man.rst +++ b/cdist/conf/type/__config_file/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__config_file - _Manages config files -Steven Armstrong - DESCRIPTION ----------- @@ -50,8 +48,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__file(7) `_ +`cdist-type__file(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul/man.rst b/cdist/conf/type/__consul/man.rst index e6a9d2d7..4096a233 100644 --- a/cdist/conf/type/__consul/man.rst +++ b/cdist/conf/type/__consul/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul - Install consul -Steven Armstrong - DESCRIPTION ----------- @@ -45,7 +43,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_agent/man.rst b/cdist/conf/type/__consul_agent/man.rst index 25ad4d5b..7a15a058 100644 --- a/cdist/conf/type/__consul_agent/man.rst +++ b/cdist/conf/type/__consul_agent/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_agent - Manage the consul agent -Steven Armstrong - DESCRIPTION ----------- @@ -167,8 +165,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- http://www.consul.io/docs/agent/options.html +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +consul documentation at: +. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_check/man.rst b/cdist/conf/type/__consul_check/man.rst index f04645fd..87e2d7a9 100644 --- a/cdist/conf/type/__consul_check/man.rst +++ b/cdist/conf/type/__consul_check/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_check - Manages consul checks -Steven Armstrong - DESCRIPTION ----------- @@ -64,8 +62,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_agent(7) `_ +`cdist-type__consul_agent(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_reload/man.rst b/cdist/conf/type/__consul_reload/man.rst index 38618aba..62b08c7f 100644 --- a/cdist/conf/type/__consul_reload/man.rst +++ b/cdist/conf/type/__consul_reload/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_reload - Reload consul -Steven Armstrong - DESCRIPTION ----------- @@ -33,7 +31,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_service/man.rst b/cdist/conf/type/__consul_service/man.rst index f7d34f4a..560266a4 100644 --- a/cdist/conf/type/__consul_service/man.rst +++ b/cdist/conf/type/__consul_service/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_service - Manages consul services -Steven Armstrong - DESCRIPTION ----------- @@ -68,8 +66,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_agent(7) `_ +`cdist-type__consul_agent(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_template/man.rst b/cdist/conf/type/__consul_template/man.rst index 8e01ee04..d2d484e5 100644 --- a/cdist/conf/type/__consul_template/man.rst +++ b/cdist/conf/type/__consul_template/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_template - Manage the consul-template service -Steven Armstrong - DESCRIPTION ----------- @@ -127,8 +125,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- https://github.com/hashicorp/consul-template +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +consul documentation at: +. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_template_template/man.rst b/cdist/conf/type/__consul_template_template/man.rst index 30832bc8..9932346b 100644 --- a/cdist/conf/type/__consul_template_template/man.rst +++ b/cdist/conf/type/__consul_template_template/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_template_template - Manage consul-template templates -Steven Armstrong - DESCRIPTION ----------- @@ -61,9 +59,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_template(7) `_ -- `cdist-type__consul_template_config(7) `_ +`cdist-type__consul_template(7) `_, +`cdist-type__consul_template_config(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_watch_checks/man.rst b/cdist/conf/type/__consul_watch_checks/man.rst index cfb451d6..dc3c9669 100644 --- a/cdist/conf/type/__consul_watch_checks/man.rst +++ b/cdist/conf/type/__consul_watch_checks/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_watch_checks - Manages consul checks watches -Steven Armstrong - DESCRIPTION ----------- @@ -57,9 +55,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_agent(7) `_ -- http://www.consul.io/docs/agent/watches.html +`cdist-type__consul_agent(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +consul documentation at: +. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_watch_event/man.rst b/cdist/conf/type/__consul_watch_event/man.rst index 871c0704..73b16754 100644 --- a/cdist/conf/type/__consul_watch_event/man.rst +++ b/cdist/conf/type/__consul_watch_event/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_watch_event - Manages consul event watches -Steven Armstrong - DESCRIPTION ----------- @@ -50,9 +48,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_agent(7) `_ -- http://www.consul.io/docs/agent/watches.html +`cdist-type__consul_agent(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +consul documentation at: +. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_watch_key/man.rst b/cdist/conf/type/__consul_watch_key/man.rst index d7554df2..c258119c 100644 --- a/cdist/conf/type/__consul_watch_key/man.rst +++ b/cdist/conf/type/__consul_watch_key/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_watch_key - Manages consul key watches -Steven Armstrong - DESCRIPTION ----------- @@ -47,9 +45,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_agent(7) `_ -- http://www.consul.io/docs/agent/watches.html +`cdist-type__consul_agent(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +consul documentation at: +. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_watch_keyprefix/man.rst b/cdist/conf/type/__consul_watch_keyprefix/man.rst index 42f675a4..950c0a26 100644 --- a/cdist/conf/type/__consul_watch_keyprefix/man.rst +++ b/cdist/conf/type/__consul_watch_keyprefix/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_watch_keyprefix - Manages consul keyprefix watches -Steven Armstrong - DESCRIPTION ----------- @@ -47,9 +45,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_agent(7) `_ -- http://www.consul.io/docs/agent/watches.html +`cdist-type__consul_agent(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +consule documentation at: . + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_watch_nodes/man.rst b/cdist/conf/type/__consul_watch_nodes/man.rst index c92a8d01..a44dada4 100644 --- a/cdist/conf/type/__consul_watch_nodes/man.rst +++ b/cdist/conf/type/__consul_watch_nodes/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_watch_nodes - Manages consul nodes watches -Steven Armstrong - DESCRIPTION ----------- @@ -43,9 +41,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_agent(7) `_ -- http://www.consul.io/docs/agent/watches.html +`cdist-type__consul_agent(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +consul documentation at: +. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_watch_service/man.rst b/cdist/conf/type/__consul_watch_service/man.rst index f37a0dea..fa6450fe 100644 --- a/cdist/conf/type/__consul_watch_service/man.rst +++ b/cdist/conf/type/__consul_watch_service/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_watch_service - Manages consul service watches -Steven Armstrong - DESCRIPTION ----------- @@ -67,9 +65,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_agent(7) `_ -- http://www.consul.io/docs/agent/watches.html +`cdist-type__consul_agent(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +consule documentation at: . + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__consul_watch_services/man.rst b/cdist/conf/type/__consul_watch_services/man.rst index 3d39da00..db561593 100644 --- a/cdist/conf/type/__consul_watch_services/man.rst +++ b/cdist/conf/type/__consul_watch_services/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__consul_watch_services - Manages consul services watches -Steven Armstrong - DESCRIPTION ----------- @@ -43,9 +41,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__consul_agent(7) `_ -- http://www.consul.io/docs/agent/watches.html +`cdist-type__consul_agent(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +consul documentation at: +. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__cron/man.rst b/cdist/conf/type/__cron/man.rst index 33f2b185..e8f32c52 100644 --- a/cdist/conf/type/__cron/man.rst +++ b/cdist/conf/type/__cron/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__cron - Installs and manages cron jobs -Steven Armstrong - DESCRIPTION ----------- @@ -70,8 +68,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- crontab(5) +crontab(5) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__debconf_set_selections/man.rst b/cdist/conf/type/__debconf_set_selections/man.rst index 60cdd5f0..27e037e7 100644 --- a/cdist/conf/type/__debconf_set_selections/man.rst +++ b/cdist/conf/type/__debconf_set_selections/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__debconf_set_selections - Setup debconf selections -Nico Schottelius - DESCRIPTION ----------- @@ -39,9 +37,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__update_alternatives(7) `_ -- debconf-set-selections(1) +debconf-set-selections(1), +`cdist-type__update_alternatives(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__directory/man.rst b/cdist/conf/type/__directory/man.rst index 8ca292ff..abb07eff 100644 --- a/cdist/conf/type/__directory/man.rst +++ b/cdist/conf/type/__directory/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__directory - Manage a directory -Nico Schottelius - DESCRIPTION ----------- @@ -92,7 +90,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__dog_vdi/man.rst b/cdist/conf/type/__dog_vdi/man.rst index 3e0c27c9..b0f700c6 100644 --- a/cdist/conf/type/__dog_vdi/man.rst +++ b/cdist/conf/type/__dog_vdi/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__dog_vdi - Manage Sheepdog VM images -Nico Schottelius - DESCRIPTION ----------- @@ -45,9 +43,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- dog(8) -- qemu(1) +qemu(1), dog(8) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__file/man.rst b/cdist/conf/type/__file/man.rst index 89efebdb..fa71e5ce 100644 --- a/cdist/conf/type/__file/man.rst +++ b/cdist/conf/type/__file/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__file - Manage files. -Nico Schottelius - DESCRIPTION ----------- @@ -103,7 +101,13 @@ EXAMPLES SEE ALSO -------- -* `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__firewalld_rule/man.rst b/cdist/conf/type/__firewalld_rule/man.rst index 4533e193..2d1f5589 100644 --- a/cdist/conf/type/__firewalld_rule/man.rst +++ b/cdist/conf/type/__firewalld_rule/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__firewalld_rule - Configure firewalld rules -Nico Schottelius - DESCRIPTION ----------- @@ -67,9 +65,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__iptables_rule(7) `_ -- firewalld(8) +`cdist-type__iptables_rule(7) `_, +firewalld(8) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__git/man.rst b/cdist/conf/type/__git/man.rst index 3ccc1e91..2f344a69 100644 --- a/cdist/conf/type/__git/man.rst +++ b/cdist/conf/type/__git/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__git - Get and or keep git repositories up-to-date -Nico Schottelius - DESCRIPTION ----------- @@ -51,7 +49,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__group/man.rst b/cdist/conf/type/__group/man.rst index 6a7d5a55..c6c9d226 100644 --- a/cdist/conf/type/__group/man.rst +++ b/cdist/conf/type/__group/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__group - Manage groups -Steven Armstrong - DESCRIPTION ----------- @@ -71,7 +69,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__hostname/man.rst b/cdist/conf/type/__hostname/man.rst index bd5d5a21..bfb9d457 100644 --- a/cdist/conf/type/__hostname/man.rst +++ b/cdist/conf/type/__hostname/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__hostname - Set the hostname -Steven Armstrong - DESCRIPTION ----------- @@ -43,7 +41,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__iptables_apply/man.rst b/cdist/conf/type/__iptables_apply/man.rst index 6a94b0af..5f4f4dc8 100644 --- a/cdist/conf/type/__iptables_apply/man.rst +++ b/cdist/conf/type/__iptables_apply/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__iptables_apply - Apply the rules -Nico Schottelius - DESCRIPTION ----------- @@ -31,9 +29,16 @@ None (__iptables_apply is used by __iptables_rule) SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__iptables_rule(7) `_ -- iptables(8) +`cdist-type__iptables_rule(7) `_, +iptables(8) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__iptables_rule/man.rst b/cdist/conf/type/__iptables_rule/man.rst index b6ff6a32..4d02e1d7 100644 --- a/cdist/conf/type/__iptables_rule/man.rst +++ b/cdist/conf/type/__iptables_rule/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__iptables_rule - Deploy iptable rulesets -Nico Schottelius - DESCRIPTION ----------- @@ -52,9 +50,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__iptables_apply(7) `_ -- iptables(8) +`cdist-type__iptables_apply(7) `_, +iptables(8) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__issue/man.rst b/cdist/conf/type/__issue/man.rst index 59fa6694..77f28da2 100644 --- a/cdist/conf/type/__issue/man.rst +++ b/cdist/conf/type/__issue/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__issue - Manage issue -Nico Schottelius - DESCRIPTION ----------- @@ -38,7 +36,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__jail/man.rst b/cdist/conf/type/__jail/man.rst index 6bbfbf47..ba175aa4 100644 --- a/cdist/conf/type/__jail/man.rst +++ b/cdist/conf/type/__jail/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__jail - Manage FreeBSD jails -Jake Guffey - DESCRIPTION ----------- @@ -110,7 +108,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Jake Guffey COPYING diff --git a/cdist/conf/type/__jail_freebsd10/man.rst b/cdist/conf/type/__jail_freebsd10/man.rst index 1a3515f0..9916afcb 100644 --- a/cdist/conf/type/__jail_freebsd10/man.rst +++ b/cdist/conf/type/__jail_freebsd10/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__jail_freeebsd10 - Manage FreeBSD jails -Jake Guffey - DESCRIPTION ----------- @@ -109,7 +107,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Jake Guffey COPYING diff --git a/cdist/conf/type/__jail_freebsd9/man.rst b/cdist/conf/type/__jail_freebsd9/man.rst index 1e442ac0..21266dd8 100644 --- a/cdist/conf/type/__jail_freebsd9/man.rst +++ b/cdist/conf/type/__jail_freebsd9/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__jail_freebsd9 - Manage FreeBSD jails -Jake Guffey - DESCRIPTION ----------- @@ -110,7 +108,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Jake Guffey COPYING diff --git a/cdist/conf/type/__key_value/man.rst b/cdist/conf/type/__key_value/man.rst index 467be78b..78e29276 100644 --- a/cdist/conf/type/__key_value/man.rst +++ b/cdist/conf/type/__key_value/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__key_value - Change property values in files -Steven Armstrong - DESCRIPTION ----------- @@ -85,7 +83,13 @@ So you need to exactly specify the key and delimiter. Delimiter can be of any le SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__line/man.rst b/cdist/conf/type/__line/man.rst index 81f57039..3a773f6a 100644 --- a/cdist/conf/type/__line/man.rst +++ b/cdist/conf/type/__line/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__line - Manage lines in files -Nico Schottelius - DESCRIPTION ----------- @@ -63,8 +61,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- grep(1) +grep(1) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__link/man.rst b/cdist/conf/type/__link/man.rst index 750874c1..0d0f2fad 100644 --- a/cdist/conf/type/__link/man.rst +++ b/cdist/conf/type/__link/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__link - Manage links (hard and symbolic) -Nico Schottelius - DESCRIPTION ----------- @@ -51,7 +49,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__locale/man.rst b/cdist/conf/type/__locale/man.rst index 2d947da8..c555bd00 100644 --- a/cdist/conf/type/__locale/man.rst +++ b/cdist/conf/type/__locale/man.rst @@ -5,8 +5,6 @@ NAME ---- cdit-type__locale - Configure locales -Nico Schottelius - DESCRIPTION ----------- @@ -36,9 +34,15 @@ EXAMPLES SEE ALSO -------- -- locale(1) -- localedef(1) -- `cdist-type(7) `_ +locale(1), localedef(1) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__motd/man.rst b/cdist/conf/type/__motd/man.rst index 1de8b258..e1530495 100644 --- a/cdist/conf/type/__motd/man.rst +++ b/cdist/conf/type/__motd/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__motd - Manage message of the day -Nico Schottelius - DESCRIPTION ----------- @@ -39,7 +37,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__mount/man.rst b/cdist/conf/type/__mount/man.rst index eab304db..c53457ac 100644 --- a/cdist/conf/type/__mount/man.rst +++ b/cdist/conf/type/__mount/man.rst @@ -5,8 +5,6 @@ NAME ---- cdit-type__mount - Manage filesystem mounts -Steven Armstrong - DESCRIPTION ----------- @@ -75,7 +73,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__mysql_database/man.rst b/cdist/conf/type/__mysql_database/man.rst index d8d2626d..921df7f3 100644 --- a/cdist/conf/type/__mysql_database/man.rst +++ b/cdist/conf/type/__mysql_database/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__mysql_database - Manage a MySQL database -Benedikt Koeppel - DESCRIPTION ----------- @@ -40,7 +38,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Benedikt Koeppel COPYING diff --git a/cdist/conf/type/__package/man.rst b/cdist/conf/type/__package/man.rst index b412af69..fe806a53 100644 --- a/cdist/conf/type/__package/man.rst +++ b/cdist/conf/type/__package/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package - Manage packages -Steven Armstrong - DESCRIPTION ----------- @@ -55,7 +53,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__package_apt/man.rst b/cdist/conf/type/__package_apt/man.rst index 65ebf6fa..39eb550b 100644 --- a/cdist/conf/type/__package_apt/man.rst +++ b/cdist/conf/type/__package_apt/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_apt - Manage packages with apt-get -Nico Schottelius - DESCRIPTION ----------- @@ -48,8 +46,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__package_emerge/man.rst b/cdist/conf/type/__package_emerge/man.rst index c9ac59b9..24f3546d 100644 --- a/cdist/conf/type/__package_emerge/man.rst +++ b/cdist/conf/type/__package_emerge/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_emerge - Manage packages with portage -Thomas Oettli - DESCRIPTION ----------- @@ -49,9 +47,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ -- `cdist-type__package_emerge_dependencies(7) `_ +`cdist-type__package(7) `_, +`cdist-type__package_emerge_dependencies(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Thomas Oettli COPYING diff --git a/cdist/conf/type/__package_emerge_dependencies/man.rst b/cdist/conf/type/__package_emerge_dependencies/man.rst index 1c4d291b..b07d2284 100644 --- a/cdist/conf/type/__package_emerge_dependencies/man.rst +++ b/cdist/conf/type/__package_emerge_dependencies/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_emerge_dependencies - Install dependencies for __package_emerge -Thomas Oettli - DESCRIPTION ----------- @@ -38,9 +36,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ -- `cdist-type__package_emerge(7) `_ +`cdist-type__package(7) `_, +`cdist-type__package_emerge(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Thomas Oettli COPYING diff --git a/cdist/conf/type/__package_luarocks/man.rst b/cdist/conf/type/__package_luarocks/man.rst index e097b4d6..e5279513 100644 --- a/cdist/conf/type/__package_luarocks/man.rst +++ b/cdist/conf/type/__package_luarocks/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_luarocks - Manage luarocks packages -Christian G. Warden - DESCRIPTION ----------- @@ -41,8 +39,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Christian G. Warden COPYING diff --git a/cdist/conf/type/__package_opkg/man.rst b/cdist/conf/type/__package_opkg/man.rst index 0104bbf2..9ad4d99f 100644 --- a/cdist/conf/type/__package_opkg/man.rst +++ b/cdist/conf/type/__package_opkg/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_opkg - Manage packages with opkg -Giel van Schijndel - DESCRIPTION ----------- @@ -41,8 +39,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Giel van Schijndel COPYING diff --git a/cdist/conf/type/__package_pacman/man.rst b/cdist/conf/type/__package_pacman/man.rst index 6f3fc5b3..b144422b 100644 --- a/cdist/conf/type/__package_pacman/man.rst +++ b/cdist/conf/type/__package_pacman/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_pacman - Manage packages with pacman -Nico Schottelius - DESCRIPTION ----------- @@ -44,8 +42,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__package_pip/man.rst b/cdist/conf/type/__package_pip/man.rst index 0630274a..026562c1 100644 --- a/cdist/conf/type/__package_pip/man.rst +++ b/cdist/conf/type/__package_pip/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_pip - Manage packages with pip -Nico Schottelius - DESCRIPTION ----------- @@ -51,8 +49,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__package_pkg_freebsd/man.rst b/cdist/conf/type/__package_pkg_freebsd/man.rst index 9246d09c..8249c8f5 100644 --- a/cdist/conf/type/__package_pkg_freebsd/man.rst +++ b/cdist/conf/type/__package_pkg_freebsd/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_pkg_freebsd - Manage FreeBSD packages -Jake Guffey - DESCRIPTION ----------- @@ -56,8 +54,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Jake Guffey COPYING diff --git a/cdist/conf/type/__package_pkg_openbsd/man.rst b/cdist/conf/type/__package_pkg_openbsd/man.rst index f584864b..9d253dce 100644 --- a/cdist/conf/type/__package_pkg_openbsd/man.rst +++ b/cdist/conf/type/__package_pkg_openbsd/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_pkg - Manage OpenBSD packages -Andi Brönnimann - DESCRIPTION ----------- @@ -56,8 +54,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Andi Brönnimann COPYING diff --git a/cdist/conf/type/__package_pkgng_freebsd/man.rst b/cdist/conf/type/__package_pkgng_freebsd/man.rst index b81ef75c..83fbf7bf 100644 --- a/cdist/conf/type/__package_pkgng_freebsd/man.rst +++ b/cdist/conf/type/__package_pkgng_freebsd/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_pkgng_freebsd - Manage FreeBSD packages with pkg-ng -Jake Guffey - DESCRIPTION ----------- @@ -87,8 +85,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Jake Guffey COPYING diff --git a/cdist/conf/type/__package_rubygem/man.rst b/cdist/conf/type/__package_rubygem/man.rst index d74149b0..0822bcf2 100644 --- a/cdist/conf/type/__package_rubygem/man.rst +++ b/cdist/conf/type/__package_rubygem/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_rubygem - Manage rubygem packages -Chase Allen James - DESCRIPTION ----------- @@ -41,8 +39,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Chase Allen James COPYING diff --git a/cdist/conf/type/__package_update_index/man.rst b/cdist/conf/type/__package_update_index/man.rst index ae05b3c5..a8f16d21 100644 --- a/cdist/conf/type/__package_update_index/man.rst +++ b/cdist/conf/type/__package_update_index/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__update_index - Update the package index -Ricardo Catalinas Jiménez - DESCRIPTION ----------- @@ -44,7 +42,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Ricardo Catalinas Jiménez COPYING diff --git a/cdist/conf/type/__package_upgrade_all/man.rst b/cdist/conf/type/__package_upgrade_all/man.rst index af6a2373..f6b216b4 100644 --- a/cdist/conf/type/__package_upgrade_all/man.rst +++ b/cdist/conf/type/__package_upgrade_all/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_upgrade_all - Upgrade all the installed packages -Ricardo Catalinas Jiménez - DESCRIPTION ----------- @@ -44,7 +42,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Ricardo Catalinas Jiménez COPYING diff --git a/cdist/conf/type/__package_yum/man.rst b/cdist/conf/type/__package_yum/man.rst index 440d0723..487150b9 100644 --- a/cdist/conf/type/__package_yum/man.rst +++ b/cdist/conf/type/__package_yum/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_yum - Manage packages with yum -Nico Schottelius - DESCRIPTION ----------- @@ -51,8 +49,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__package_zypper/man.rst b/cdist/conf/type/__package_zypper/man.rst index 74648c9e..754b5ddd 100644 --- a/cdist/conf/type/__package_zypper/man.rst +++ b/cdist/conf/type/__package_zypper/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__package_zypper - Manage packages with zypper -Daniel Heule - DESCRIPTION ----------- @@ -58,8 +56,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__package(7) `_ +`cdist-type__package(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Daniel Heule COPYING diff --git a/cdist/conf/type/__pacman_conf/man.rst b/cdist/conf/type/__pacman_conf/man.rst index 0a8eb62a..c0040664 100644 --- a/cdist/conf/type/__pacman_conf/man.rst +++ b/cdist/conf/type/__pacman_conf/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__pacman_conf - Manage pacman configuration -Dominique Roux - DESCRIPTION ----------- @@ -61,8 +59,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- grep(1) +grep(1) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Dominique Roux COPYING diff --git a/cdist/conf/type/__pacman_conf_integrate/man.rst b/cdist/conf/type/__pacman_conf_integrate/man.rst index 30ef6cd9..10ff0c8a 100644 --- a/cdist/conf/type/__pacman_conf_integrate/man.rst +++ b/cdist/conf/type/__pacman_conf_integrate/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__pacman_conf_integrate - Integrate default pacman.conf to cdist conform and vice versa -Dominique Roux - DESCRIPTION ----------- @@ -37,8 +35,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- grep(1) +grep(1) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Dominique Roux COPYING diff --git a/cdist/conf/type/__pf_apply/man.rst b/cdist/conf/type/__pf_apply/man.rst index acebcb96..20374699 100644 --- a/cdist/conf/type/__pf_apply/man.rst +++ b/cdist/conf/type/__pf_apply/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__pf_apply - Apply pf(4) ruleset on \*BSD -Jake Guffey - DESCRIPTION ----------- @@ -41,9 +39,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__pf_ruleset(7) `_ -- pf(4) +pf(4), +`cdist-type__pf_ruleset(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Jake Guffey COPYING diff --git a/cdist/conf/type/__pf_ruleset/man.rst b/cdist/conf/type/__pf_ruleset/man.rst index 7edc0f91..15d50408 100644 --- a/cdist/conf/type/__pf_ruleset/man.rst +++ b/cdist/conf/type/__pf_ruleset/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__pf_ruleset - Copy a pf(4) ruleset to $__target_host -Jake Guffey - DESCRIPTION ----------- @@ -41,8 +39,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- pf(4) +pf(4) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Jake Guffey COPYING diff --git a/cdist/conf/type/__postfix/man.rst b/cdist/conf/type/__postfix/man.rst index 73347e38..628356b2 100644 --- a/cdist/conf/type/__postfix/man.rst +++ b/cdist/conf/type/__postfix/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__postfix - Install postfix -Steven Armstrong - DESCRIPTION ----------- @@ -33,7 +31,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__postfix_master/man.rst b/cdist/conf/type/__postfix_master/man.rst index 86fa5f8c..7f100485 100644 --- a/cdist/conf/type/__postfix_master/man.rst +++ b/cdist/conf/type/__postfix_master/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__postfix_master - Configure postfix master.cf -Steven Armstrong - DESCRIPTION ----------- @@ -70,8 +68,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- master(5) +master(5) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__postfix_postconf/man.rst b/cdist/conf/type/__postfix_postconf/man.rst index ab0192b8..f1a4b0a6 100644 --- a/cdist/conf/type/__postfix_postconf/man.rst +++ b/cdist/conf/type/__postfix_postconf/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__postfix_postconf - Configure postfix main.cf -Steven Armstrong - DESCRIPTION ----------- @@ -40,8 +38,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- postconf(5) +postconf(5) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__postfix_postmap/man.rst b/cdist/conf/type/__postfix_postmap/man.rst index 5e9d3c2d..20aeb2df 100644 --- a/cdist/conf/type/__postfix_postmap/man.rst +++ b/cdist/conf/type/__postfix_postmap/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__postfix_postmap - Run postmap on the given file -Steven Armstrong - DESCRIPTION ----------- @@ -33,7 +31,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__postfix_reload/man.rst b/cdist/conf/type/__postfix_reload/man.rst index 330ed51c..ec9529e9 100644 --- a/cdist/conf/type/__postfix_reload/man.rst +++ b/cdist/conf/type/__postfix_reload/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__postfix_reload - Tell postfix to reload its configuration -Steven Armstrong - DESCRIPTION ----------- @@ -33,7 +31,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__postgres_database/man.rst b/cdist/conf/type/__postgres_database/man.rst index 34cd2f03..2a0ad8d0 100644 --- a/cdist/conf/type/__postgres_database/man.rst +++ b/cdist/conf/type/__postgres_database/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__postgres_database - Create/drop postgres databases -Steven Armstrong - DESCRIPTION ----------- @@ -32,8 +30,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__postgres_role(7) `_ +`cdist-type__postgres_role(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__postgres_role/man.rst b/cdist/conf/type/__postgres_role/man.rst index 4b8d291f..9d0b68ab 100644 --- a/cdist/conf/type/__postgres_role/man.rst +++ b/cdist/conf/type/__postgres_role/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__postgres_role - Manage postgres roles -Steven Armstrong - DESCRIPTION ----------- @@ -50,9 +48,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__postgres_database(7) `_ -- http://www.postgresql.org/docs/current/static/sql-createrole.html +`cdist-type__postgres_database(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. +postgresql documentation at: +. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__process/man.rst b/cdist/conf/type/__process/man.rst index 3f17076d..076377e1 100644 --- a/cdist/conf/type/__process/man.rst +++ b/cdist/conf/type/__process/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__process - Start or stop process -Nico Schottelius - DESCRIPTION ----------- @@ -60,8 +58,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__start_on_boot(7) `_ +`cdist-type__start_on_boot(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__pyvenv/man.rst b/cdist/conf/type/__pyvenv/man.rst old mode 100755 new mode 100644 index ff7a922b..f43454a7 --- a/cdist/conf/type/__pyvenv/man.rst +++ b/cdist/conf/type/__pyvenv/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__pyvenv - Create or remove python virtual environment -Darko Poljak - DESCRIPTION ----------- @@ -71,7 +69,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Darko Poljak COPYING diff --git a/cdist/conf/type/__qemu_img/man.rst b/cdist/conf/type/__qemu_img/man.rst index 4492c260..3a137f4b 100644 --- a/cdist/conf/type/__qemu_img/man.rst +++ b/cdist/conf/type/__qemu_img/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__qemu_img - Manage VM disk images -Nico Schottelius - DESCRIPTION ----------- @@ -39,8 +37,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- qemu-img(1) +qemu-img(1) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__rbenv/man.rst b/cdist/conf/type/__rbenv/man.rst index d13f407c..fe965796 100644 --- a/cdist/conf/type/__rbenv/man.rst +++ b/cdist/conf/type/__rbenv/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__rbenv - Manage rbenv installation -Nico Schottelius - DESCRIPTION ----------- @@ -40,7 +38,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__rsync/man.rst b/cdist/conf/type/__rsync/man.rst index afca11d5..bac144c2 100644 --- a/cdist/conf/type/__rsync/man.rst +++ b/cdist/conf/type/__rsync/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__rsync - Mirror directories using rsync -Nico Schottelius - DESCRIPTION ----------- @@ -100,8 +98,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- rsync(1) +rsync(1) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__rvm/man.rst b/cdist/conf/type/__rvm/man.rst index 5aa264e0..bf84328c 100644 --- a/cdist/conf/type/__rvm/man.rst +++ b/cdist/conf/type/__rvm/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__rvm - Install rvm for a given user -Evax Software - DESCRIPTION ----------- @@ -33,10 +31,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__rvm_ruby(7) `_ -- `cdist-type__rvm_gemset(7) `_ -- `cdist-type__rvm_gem(7) `_ +`cdist-type__rvm_gem(7) `_, +`cdist-type__rvm_gemset(7) `_, +`cdist-type__rvm_ruby(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Evax Software COPYING diff --git a/cdist/conf/type/__rvm_gem/man.rst b/cdist/conf/type/__rvm_gem/man.rst index c6011f45..5e65a712 100644 --- a/cdist/conf/type/__rvm_gem/man.rst +++ b/cdist/conf/type/__rvm_gem/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__rvm_gemset - Manage Ruby gems through rvm -Evax Software - DESCRIPTION ----------- @@ -45,10 +43,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__rvm(7) `_ -- `cdist-type__rvm_ruby(7) `_ -- `cdist-type__rvm_gemset(7) `_ +`cdist-type__rvm(7) `_, +`cdist-type__rvm_gemset(7) `_, +`cdist-type__rvm_ruby(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Evax Software COPYING diff --git a/cdist/conf/type/__rvm_gemset/man.rst b/cdist/conf/type/__rvm_gemset/man.rst index 6792b14e..0d04ed94 100644 --- a/cdist/conf/type/__rvm_gemset/man.rst +++ b/cdist/conf/type/__rvm_gemset/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__rvm_gemset - Manage gemsets through rvm -Evax Software - DESCRIPTION ----------- @@ -43,10 +41,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__rvm(7) `_ -- `cdist-type__rvm_ruby(7) `_ -- `cdist-type__rvm_gem(7) `_ +`cdist-type__rvm(7) `_, +`cdist-type__rvm_gem(7) `_, +`cdist-type__rvm_ruby(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Evax Software COPYING diff --git a/cdist/conf/type/__rvm_ruby/man.rst b/cdist/conf/type/__rvm_ruby/man.rst index 235731cd..d2bd4d08 100644 --- a/cdist/conf/type/__rvm_ruby/man.rst +++ b/cdist/conf/type/__rvm_ruby/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__rvm_ruby - Manage ruby installations through rvm -Evax Software - DESCRIPTION ----------- @@ -44,10 +42,17 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__rvm(7) `_ -- `cdist-type__rvm_gemset(7) `_ -- `cdist-type__rvm_gem(7) `_ +`cdist-type__rvm(7) `_, +`cdist-type__rvm_gem(7) `_, +`cdist-type__rvm_gemset(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Evax Software COPYING diff --git a/cdist/conf/type/__ssh_authorized_key/man.rst b/cdist/conf/type/__ssh_authorized_key/man.rst index 767fb1d2..a2f90574 100644 --- a/cdist/conf/type/__ssh_authorized_key/man.rst +++ b/cdist/conf/type/__ssh_authorized_key/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__ssh_authorized_key - Manage a single ssh authorized key entry -Steven Armstrong - DESCRIPTION ----------- @@ -57,9 +55,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist__ssh_authorized_keys(7) `_ -- sshd(8) +`cdist__ssh_authorized_keys(7) `_, +sshd(8) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + +AUTHORS +------- +Steven Armstrong + COPYING ------- diff --git a/cdist/conf/type/__ssh_authorized_keys/man.rst b/cdist/conf/type/__ssh_authorized_keys/man.rst index 54e294b3..cab844cc 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.rst +++ b/cdist/conf/type/__ssh_authorized_keys/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__ssh_authorized_keys - Manage ssh authorized_keys files -Steven Armstrong - DESCRIPTION ----------- @@ -107,8 +105,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- sshd(8) +sshd(8) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__ssh_dot_ssh/man.rst b/cdist/conf/type/__ssh_dot_ssh/man.rst index 12b4c2e7..6d449a4c 100644 --- a/cdist/conf/type/__ssh_dot_ssh/man.rst +++ b/cdist/conf/type/__ssh_dot_ssh/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__ssh_dot_ssh - Manage .ssh directory -Nico Schottelius - DESCRIPTION ----------- @@ -35,8 +33,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__ssh_authorized_keys(7) `_ +`cdist-type__ssh_authorized_keys(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__staged_file/man.rst b/cdist/conf/type/__staged_file/man.rst index aec11707..69ea3678 100644 --- a/cdist/conf/type/__staged_file/man.rst +++ b/cdist/conf/type/__staged_file/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__staged_file - Manage staged files -Steven Armstrong - DESCRIPTION ----------- @@ -101,8 +99,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__file(7) `_ +`cdist-type__file(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__start_on_boot/man.rst b/cdist/conf/type/__start_on_boot/man.rst index 2f07362b..7d009bf0 100644 --- a/cdist/conf/type/__start_on_boot/man.rst +++ b/cdist/conf/type/__start_on_boot/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__start_on_boot - Manage stuff to be started at boot -Nico Schottelius - DESCRIPTION ----------- @@ -47,8 +45,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__process(7) `_ +`cdist-type__process(7) `_ + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__timezone/man.rst b/cdist/conf/type/__timezone/man.rst index 838f4c46..6e18c759 100644 --- a/cdist/conf/type/__timezone/man.rst +++ b/cdist/conf/type/__timezone/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__timezone - Allows one to configure the desired localtime timezone. -Ramon Salvadó - DESCRIPTION ----------- @@ -38,7 +36,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Ramon Salvadó COPYING diff --git a/cdist/conf/type/__update_alternatives/man.rst b/cdist/conf/type/__update_alternatives/man.rst index f321b02f..bcedc1bf 100644 --- a/cdist/conf/type/__update_alternatives/man.rst +++ b/cdist/conf/type/__update_alternatives/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__update_alternatives - Configure alternatives -Nico Schottelius - DESCRIPTION ----------- @@ -32,9 +30,16 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- `cdist-type__debconf_set_selections(7) `_ -- update-alternatives(8) +`cdist-type__debconf_set_selections(7) `_, +update-alternatives(8) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Nico Schottelius COPYING diff --git a/cdist/conf/type/__user/man.rst b/cdist/conf/type/__user/man.rst index 6a055a4e..0dd91ddd 100644 --- a/cdist/conf/type/__user/man.rst +++ b/cdist/conf/type/__user/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__user - Manage users -Steven Armstrong - DESCRIPTION ----------- @@ -86,8 +84,15 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ -- usermod(8) or pw(8) +pw(8), usermod(8) + +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__user_groups/man.rst b/cdist/conf/type/__user_groups/man.rst index 8857feb1..216a31c8 100644 --- a/cdist/conf/type/__user_groups/man.rst +++ b/cdist/conf/type/__user_groups/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__user_groups - Manage user groups -Steven Armstrong - DESCRIPTION ----------- @@ -43,7 +41,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__yum_repo/man.rst b/cdist/conf/type/__yum_repo/man.rst index 3df9f1b9..b3866739 100644 --- a/cdist/conf/type/__yum_repo/man.rst +++ b/cdist/conf/type/__yum_repo/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__yum_repo - Manage yum repositories -Steven Armstrong - DESCRIPTION ----------- @@ -115,7 +113,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Steven Armstrong COPYING diff --git a/cdist/conf/type/__zypper_repo/man.rst b/cdist/conf/type/__zypper_repo/man.rst index d1b87a5b..bcf376de 100644 --- a/cdist/conf/type/__zypper_repo/man.rst +++ b/cdist/conf/type/__zypper_repo/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__zypper_repo - Repository management with zypper -Daniel Heule - DESCRIPTION ----------- @@ -64,7 +62,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Daniel Heule COPYING diff --git a/cdist/conf/type/__zypper_service/man.rst b/cdist/conf/type/__zypper_service/man.rst index 9d538208..f586742a 100644 --- a/cdist/conf/type/__zypper_service/man.rst +++ b/cdist/conf/type/__zypper_service/man.rst @@ -5,8 +5,6 @@ NAME ---- cdist-type__zypper_service - Service management with zypper -Daniel Heule - DESCRIPTION ----------- @@ -57,7 +55,13 @@ EXAMPLES SEE ALSO -------- -- `cdist-type(7) `_ +Full documentation at: <:cdist_docs:`index`>, +especially cdist type chapter: <:cdist_docs:`cdist-type`>. + + +AUTHORS +------- +Daniel Heule COPYING diff --git a/docs/changelog b/docs/changelog index 33fe54b6..2ffe7a66 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Documentation: Restructure and fix and improve docs and manpages (Darko Poljak) * Core: Add files directory for static files (Darko Poljak) * Core: Fix conflicting requirements (Darko Poljak) * Custom: Add bash and zsh completions (Darko Poljak) diff --git a/docs/man/Makefile b/docs/man/Makefile index 6d3ec6dc..2bab13ce 100644 --- a/docs/man/Makefile +++ b/docs/man/Makefile @@ -9,7 +9,7 @@ BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) - $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) + $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. diff --git a/docs/man/man7/cdist-best-practice.rst b/docs/man/cdist-best-practice.rst similarity index 90% rename from docs/man/man7/cdist-best-practice.rst rename to docs/man/cdist-best-practice.rst index 7c19c038..57ce5cc1 100644 --- a/docs/man/man7/cdist-best-practice.rst +++ b/docs/man/cdist-best-practice.rst @@ -1,14 +1,8 @@ -cdist-best-practice(7) -====================== +Best practice +============= +Practices used in real environments -NAME ----- -cdist-best-practice - Practices used in real environments - -Nico Schottelius - - -PASSWORDLESS CONNECTIONS +Passwordless connections ------------------------ It is recommended to run cdist with public key authentication. This requires a private/public key pair and the entry @@ -16,7 +10,7 @@ This requires a private/public key pair and the entry See sshd_config(5) and ssh-keygen(1). -SPEEDING UP SSH CONNECTIONS +Speeding up ssh connections --------------------------- When connecting to a new host, the initial delay with ssh connections is pretty big. You can work around this by @@ -30,7 +24,7 @@ inclusion into your ~/.ssh/config:: ControlPersist 10 -SPEEDING UP SHELL EXECUTION +Speeding up shell execution ---------------------------- On the source host, ensure that /bin/sh is *not* bash: bash is quite slow for script execution. Instead, you could use dash after installing it:: @@ -38,7 +32,7 @@ script execution. Instead, you could use dash after installing it:: ln -sf /bin/dash /bin/sh -MULTI MASTER OR ENVIRONMENT SETUPS +Multi master or environment setups ---------------------------------- If you plan to distribute cdist among servers or use different environments, you can do so easily with the included version @@ -64,7 +58,7 @@ you can clone it multiple times:: machine-b % git clone git://your-git-server/cdist -SEPERATING WORK BY GROUPS +Seperating work by groups ------------------------- If you are working with different groups on one cdist-configuration, you can delegate to other manifests and have the groups edit only @@ -77,7 +71,7 @@ their manifests. You can use the following snippet in sh -e "$__manifest/cbrg" -MAINTAINING MULTIPLE CONFIGURATIONS +Maintaining multiple configurations ----------------------------------- When you need to manage multiple sites with cdist, like company_a, company_b and private for instance, you can easily use git for this purpose. @@ -138,7 +132,7 @@ The following **.git/config** is taken from a a real world scenario:: Have a look at git-remote(1) to adjust the remote configuration, which allows -MULTIPLE DEVELOPERS WITH DIFFERENT TRUST +Multiple developers with different trust ---------------------------------------- If you are working in an environment that requires different people to work on the same configuration, but having different privileges, you can @@ -155,7 +149,7 @@ implement this scenario with a gateway host and sudo: For more details consult sudoers(5) -TEMPLATING +Templating ---------- * create directory files/ in your type (convention) * create the template as an executable file like files/basic.conf.sh, it will output text using shell variables for the values @@ -193,7 +187,7 @@ TEMPLATING --source "$__object/files/basic.conf" -TESTING A NEW TYPE +Testing a new type ------------------ If you want to test a new type on a node, you can tell cdist to only use an object of this type: Use the '--initial-manifest' parameter @@ -214,7 +208,7 @@ of cdist: cdist --initial-manifest - cdist-dev-01.ungleich.ch -OTHER CONTENT IN CDIST REPOSITORY +Other content in cdist repository --------------------------------- Usually the cdist repository contains all configuration items. Sometimes you may have additional resources that @@ -227,15 +221,3 @@ in the repository for such content: It allows you to easily distinguish what is used by cdist and what not and also to store all important files in one repository. - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ -- `cdist-tutorial(7) `_ - - -COPYING -------- -Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-bootstrap.rst b/docs/man/cdist-bootstrap.rst similarity index 86% rename from docs/man/man7/cdist-bootstrap.rst rename to docs/man/cdist-bootstrap.rst index 6a070afa..c9972a99 100644 --- a/docs/man/man7/cdist-bootstrap.rst +++ b/docs/man/cdist-bootstrap.rst @@ -1,21 +1,11 @@ -cdist-bootstrap(7) -================== - -NAME ----- -cdist-bootstrap - Setup cdist environment - -Nico Schottelius - - -INTRODUCTION ------------- +Bootstrap +========= This document describes the usual steps recommended for a new cdist setup. It is recommended that you have read and understood -cdist-quickstart(7) before digging into this. +`cdist quickstart `_ before digging into this. -LOCATION +Location --------- First of all, you should think about where to store your configuration database and who will be accessing or changing it. Secondly you have to @@ -29,13 +19,13 @@ relies on is recommended, for use as backup as well as to allow easy collaborati with others. For more sophisticated setups developing cdist configurations with multiple -people, have a look at cdist-best-practice(7). +people, have a look at `cdist best practice `_. -SETUP WORKING DIRECTORY AND BRANCH +Setup working directory and branch ---------------------------------- I assume you have a fresh copy of the cdist tree in ~/cdist, cloned from -one of the official urls (see cdist-quickstart(7) if you don't). +one of the official urls (see `cdist quickstart `_ if you don't). Entering the command "git branch" should show you "* master", which indicates you are on the **master** branch. @@ -85,7 +75,7 @@ In this tutorial I use the branch **mycompany**:: From now on, you can use git as usual to commit your changes in your own branch. -PUBLISHING THE CONFIGURATION +Publishing the configuration ---------------------------- Usually a development machine like a notebook should be considered temporary only. For this reason and to enable shareability, the configuration @@ -114,7 +104,7 @@ branch with the **master** branch on the host **loch**. Thus you can commit as usual in your branch and push out changes by entering **git push**. -UPDATING FROM ORIGIN +Updating from origin -------------------- Whenever you want to update your cdist installation, you can use git to do so:: @@ -126,15 +116,3 @@ Whenever you want to update your cdist installation, you can use git to do so:: # Alternative: Update current branch with 2.0 branch from origin cdist% git merge origin/2.0 - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ -- `cdist-tutorial(7) `_ - - -COPYING -------- -Copyright \(C) 2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-explorer.rst b/docs/man/cdist-explorer.rst similarity index 75% rename from docs/man/man7/cdist-explorer.rst rename to docs/man/cdist-explorer.rst index 66c20d67..4bb61d7a 100644 --- a/docs/man/man7/cdist-explorer.rst +++ b/docs/man/cdist-explorer.rst @@ -1,14 +1,7 @@ -cdist-explorer(7) -================= +Explorer +======== -NAME ----- -cdist-explorer - Explore the target systems - -Nico Schottelius - - -DESCRIPTION +Description ----------- Explorer are small shell scripts, which will be executed on the target host. The aim of the explorer is to give hints to types on how to act on the @@ -39,7 +32,7 @@ error message on stderr, which will cause cdist to abort. You can also use stderr for debugging purposes while developing a new explorer. -EXAMPLES +Examples -------- A very simple explorer may look like this:: @@ -59,16 +52,3 @@ A type explorer, which could check for the status of a package may look like thi # Expect dpkg failing, if package is not known / installed dpkg -s "$name" 2>/dev/null || exit 0 - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ -- `cdist-reference(7) `_ -- `cdist-stages(7) `_ - - -COPYING -------- -Copyright \(C) 2010-2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/cdist-features.rst b/docs/man/cdist-features.rst new file mode 100644 index 00000000..8a147741 --- /dev/null +++ b/docs/man/cdist-features.rst @@ -0,0 +1,48 @@ +Features +======== + +But cdist ticks differently, here is the feature set that makes it unique: + +Simplicity + There is only one type to extend cdist called **type** + +Design + + Type and core cleanly seperated + + Sticks completly to the KISS (keep it simple and stupid) paradigma + + Meaningful error messages - do not lose time debugging error messages + + Consistency in behaviour, naming and documentation + + No surprise factor: Only do what is obviously clear, no magic + + Define target state, do not focus on methods or scripts + + Push architecture: Instantly apply your changes + +Small core + cdist's core is very small - less code, less bugs + +Fast development + Focus on straightforwardness of type creation is a main development objective + Batteries included: A lot of requirements can be solved using standard types + +Modern Programming Language + cdist is written in Python + +Requirements, Scalability + No central server needed, cdist operates in push mode and can be run from any computer + +Requirements, Scalability, Upgrade + cdist only needs to be updated on the master, not on the target hosts + +Requirements, Security + Uses well-know `SSH `_ as transport protocol + +Requirements, Simplicity + Requires only shell and SSH server on the target + +UNIX + Reuse of existing tools like cat, find, mv, ... + +UNIX, familar environment, documentation + Is available as manpages and HTML + +UNIX, simplicity, familar environment + cdist is configured in POSIX shell + diff --git a/docs/man/man7/cdist-hacker.rst b/docs/man/cdist-hacker.rst similarity index 86% rename from docs/man/man7/cdist-hacker.rst rename to docs/man/cdist-hacker.rst index 4e3a21b6..326d83ba 100644 --- a/docs/man/man7/cdist-hacker.rst +++ b/docs/man/cdist-hacker.rst @@ -1,14 +1,7 @@ -cdist-hacker(7) -=============== +Hacking +======= -NAME ----- -cdist-hacker - How to get (stuff) into cdist - -Nico Schottelius - - -WELCOME +Welcome ------- Welcome dear hacker! I invite you to a tour of pointers to get into the usable configuration mangament system, cdist. @@ -19,14 +12,14 @@ twice before merging or implementing a feature: Less features with good usability are far better than the opposite. -REPORTING BUGS +Reporting bugs -------------- If you believe you've found a bug and verified that it is in the latest version, drop a mail to the cdist mailing list, subject prefixed with "[BUG] " or create an issue on github. -CODING CONVENTIONS (EVERYWHERE) +Coding conventions (everywhere) ------------------------------- If something should be better done or needs to fixed, add the word FIXME nearby, so grepping for FIXME gives all positions that need to be fixed. @@ -34,7 +27,7 @@ nearby, so grepping for FIXME gives all positions that need to be fixed. Indention is 4 spaces (welcome to the python world). -HOW TO SUBMIT STUFF FOR INCLUSION INTO UPSTREAM CDIST +How to submit stuff for inclusion into upstream cdist ----------------------------------------------------- If you did some cool changes to cdist, which you value as a benefit for everybody using cdist, you're welcome to propose inclusion into upstream. @@ -61,9 +54,9 @@ for inclusion to the mailinglist **cdist at cdist -- at -- l.schottelius.org** or open a pull request at http://github.com/telmich/cdist. -HOW TO SUBMIT A NEW TYPE +How to submit a new type ------------------------ -For detailled information about types, see cdist-type(7). +For detailled information about types, see `cdist type `_. Submitting a type works as described above, with the additional requirement that a corresponding manpage named man.text in asciidoc format with @@ -77,9 +70,11 @@ code and thus such a type introduces redundant functionality that is given by core cdist already. -EXAMPLE GIT WORKFLOW +Example git workflow --------------------- -The following workflow works fine for most developers:: +The following workflow works fine for most developers + +.. code-block:: sh # get latest upstream master branch git clone https://github.com/telmich/cdist.git @@ -125,6 +120,8 @@ The following workflow works fine for most developers:: If at any point you want to go back to the original master branch, you can use **git stash** to stash your changes away:: +.. code-block:: sh + # assume you are on documentation_cleanup git stash @@ -136,6 +133,8 @@ use **git stash** to stash your changes away:: Similar when you want to develop another new feature, you go back to the master branch and create another branch based on it:: +.. code-block:: sh + # change to master and update to most recent upstream version git checkout master git fetch -v origin @@ -145,17 +144,3 @@ to the master branch and create another branch based on it:: (you can repeat the code above for as many features as you want to develop in parallel) - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ -- git(1) -- git-checkout(1) -- git-stash(1) - - -COPYING -------- -Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/cdist-install.rst b/docs/man/cdist-install.rst new file mode 100644 index 00000000..7e8bba7a --- /dev/null +++ b/docs/man/cdist-install.rst @@ -0,0 +1,105 @@ +How to install cdist +==================== + +Requirements +------------- + +Source Host +~~~~~~~~~~~ + +This is the machine you use to configure the target hosts. + + * /bin/sh: A posix like shell (for instance bash, dash, zsh) + * Python >= 3.2 + * SSH client + * sphinx (for building html docs and/or the manpages) + +Target Hosts +~~~~~~~~~~~~ + + * /bin/sh: A posix like shell (for instance bash, dash, zsh) + * SSH server + +Install cdist +------------- + +You can install cdist either from git or as a python package. + +From git +~~~~~~~~ + +Cloning cdist from git gives you the advantage of having +a version control in place for development of your own stuff +immediately. + +To install cdist, execute the following commands: + +.. code-block:: sh + + git clone https://github.com/ungleich/cdist.git + cd cdist + export PATH=$PATH:$(pwd -P)/bin + +Available versions in git +^^^^^^^^^^^^^^^^^^^^^^^^^ + + * The active development takes place in the **master** branch + * The released versions can be found in the tags + +Other branches may be available for features or bugfixes, but they +may vanish at any point. To select a specific branch use + +.. code-block:: sh + + # Generic code + git checkout -b origin/ + +So for instance if you want to use and stay with version 4.1, you can use + +.. code-block:: sh + + git checkout -b 4.1 origin/4.1 + +Git mirrors +^^^^^^^^^^^ + +If the main site is down, you can acquire cdist from one of the following sites: + + * git://github.com/telmich/cdist.git `github `_ + * git://git.code.sf.net/p/cdist/code `sourceforge `_ + +Building and using manpages +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you want to build and use the manpages, run: + +.. code-block:: sh + + make man + export MANPATH=$MANPATH:$(pwd -P)/docs/man/_build/man + +Or you can move manpages from docs/man/_build/man directory to some +other directory and add it to MANPATH. + +You can also build manpages for types in your ~/.cdist directory: + +.. code-block:: sh + + make dotman + +Built manpages are now in docs/man/_build/man directory. If you have +some other custom .cdist directory, e.g. /custom/.cdist then use: + +.. code-block:: sh + + DOT_CDIST_PATH=/custom/.cdist make dotman + +Python package +~~~~~~~~~~~~~~ + +Cdist is available as a python package at +`PyPi `_. You can install it using + +.. code-block:: sh + + pip install cdist diff --git a/docs/man/cdist-intro.rst b/docs/man/cdist-intro.rst new file mode 100644 index 00000000..fad40fe5 --- /dev/null +++ b/docs/man/cdist-intro.rst @@ -0,0 +1,15 @@ +cdist - usable configuration management +======================================= + +.. image:: cdist-logo.png + :alt: cdist-logo + +cdist is a usable configuration management system. +It adheres to the KISS principle and +is being used in small up to enterprise grade environments. +cdist is an alternative to other configuration management systems like + +* `bcfg2 `_ +* `chef `_ +* `cfengine `_ +* `puppet `_. diff --git a/docs/man/cdist-logo.png b/docs/man/cdist-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..13c2792728d20511f18ae60df8524d68b8a35cbf GIT binary patch literal 1542 zcmV+h2Ko7kP)Px#22e~?MF0Q*|NsA`*`M72000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipS@ z0U8oZ%R(#w00o9gL_t(o!|j;OOC(1Wz^mIa(<@6fGKU5*AnRX5Vhb0Zp zl-0j^^}hPms}|z_>pi<{At%Dr`U@U4gF4RoGSKpzdV%|9@IftRZLXV9@rE>N@N!C~ zGe!OUp&qdMyVA_e*UFQ*nQ6FwG6UDY#;;ZQdr1m53*5jARMf$*1#sLK#5utjPU&db zU785>|Q;`jcYt&fW8y13Dv?GjzEFS5zgd^L_8Dcpp*UC7%Q|3g| zeW!0Xc2ln5Rr4S=Vw`9rom{QR%eaLoD99VfwGKs%e!wYXuc>Ro!YNg8JEj$j^K%vMI*!X+fZJ61zup&| z_&2@o@#j2c4Ow58Hv--l{9E;X!t)PThohc&SqQ&#?tli zeQ~q`w_7_Q4-|PvJ%@O73;v3uexPskGwxuUxYYml(wYAUI%ek9r9qEY?};s1j`9Ns zws+2%V_kFL`}_%&3B=6YnssgO7v^UEE^rn<`DuRG-WhWykyiNA+NRs7e#(n=#)dSo zC4b`2WX@hcQKUGP1Q;~i_~10#_Lg>}wnLWcfIX@<+++6!>FOsE(lNYg;o!>kuYLrZ zgn0Pmn(d&{8hK&l4S+j!SA~?-kZ(d{hS{KtRyo7mHqy$s_JuIA?hdVknB7 zLmcRLeo>TXD!t|!#KppS^(U1G?uTqIrW6TN&L%q)1U|fh!8$5_6|fyo5;wJD>?Nn8 z7@(SuyO_)`(2ft;4l8l7-_6;9W~(mlmj~#Vqtq{l($Q`rzu?yO%mX=fdC=B&2+U{e4Ydo2tmeVMoEvfXx48|#$#HqW zTvw#rm^=`@-JY`kV#Va)&A7P1?!T;r((*!4!$HtGcXKPzc`S^6g>{Se%ENDB0rpaV z5LWU)8vnI-KXJt}pCil*k@~kQ_nrqXYSH9EMl)|%efJ-1(-zZu5F_WnM!-h{74^xT z;0|clXTjlN%3T{{fFAO-|Ift!@>@-G2m|qxhyoK=0!BZA|iCn43h9NNJLMXkOv16dzyd&)Y5*|k+R=&8w!jnSNv6LK39 saY9X~U}r+kn~+ - - -DESCRIPTION +Description ----------- Manifests are used to define which objects to create. Objects are instances of **types**, like in object oriented programming languages. @@ -44,15 +37,15 @@ In general, manifests are used to define which types are used depending on given conditions. -INITIAL AND TYPE MANIFESTS +Initial and type manifests -------------------------- Cdist knows about two types of manifests: The initial manifest and type manifests. The initial manifest is used to define, which configurations to apply to which hosts. The type manifests are used to create objects -from types. More about manifests in types can be found in cdist-type(7). +from types. More about manifests in types can be found in `cdist type `_. -DEFINE STATE IN THE INITIAL MANIFEST +Define state in the initial manifest ------------------------------------ The **initial manifest** is the entry point for cdist to find out, which **objects** to configure on the selected host. @@ -82,12 +75,12 @@ utilises cdist types. Every available type can be executed like a normal command. -SPLITTING UP THE INITIAL MANIFEST +Splitting up the initial manifest --------------------------------- If you want to split up your initial manifest, you can create other shell scripts in **cdist/conf/manifest/** and include them in **cdist/conf/manifest/init**. Cdist provides the environment variable **__manifest** to reference -the directory containing the initial manifest (see cdist-reference(7)). +the directory containing the initial manifest (see `cdist reference `_). The following example would include every file with a **.sh** suffix:: @@ -98,7 +91,7 @@ The following example would include every file with a **.sh** suffix:: done -DEPENDENCIES +Dependencies ------------ If you want to describe that something requires something else, just setup the variable "require" to contain the requirements. Multiple @@ -157,10 +150,10 @@ from the type that is calling them. This is called "autorequirement" in cdist jargon. You can find an more in depth description of the flow execution of manifests -in cdist-stages(7) and of how types work in cdist-type(7). +in `cdist execution stages `_ and of how types work in `cdist type `_. -CREATE DEPENDENCIES FROM EXECUTION ORDER +Create dependencies from execution order ----------------------------------------- You can tell cdist to execute all types in the order in which they are created in the manifest by setting up the variable CDIST_ORDER_DEPENDENCY. @@ -171,7 +164,7 @@ It essentially helps you to build up blocks of code that build upon each other (like first creating the directory xyz than the file below the directory). -OVERRIDES +Overrides --------- In some special cases, you would like to create an already defined object with different parameters. In normal situations this leads to an error in cdist. @@ -187,7 +180,7 @@ CDIST_ORDER_DEPENDENCY will be ignored, because adding a dependency in case of overrides would result in circular dependencies, which is an error. -EXAMPLES +Examples -------- The initial manifest may for instance contain the following code: @@ -260,15 +253,3 @@ Dependencies defined by execution order work as following: require="__some_type_somewhere/id __sample_type/1" __sample_type 2 require="__sample_type/2" __example_type 23 __not_in_order_type 42 - - -SEE ALSO --------- -- `cdist-tutorial(7) `_ -- `cdist-type(7) `_ - - -COPYING -------- -Copyright \(C) 2010-2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-messaging.rst b/docs/man/cdist-messaging.rst similarity index 79% rename from docs/man/man7/cdist-messaging.rst rename to docs/man/cdist-messaging.rst index b0d5e3b4..ea35c404 100644 --- a/docs/man/man7/cdist-messaging.rst +++ b/docs/man/cdist-messaging.rst @@ -1,13 +1,7 @@ -cdist-messaging(7) -================== +Messaging +========= -NAME ----- -cdist-messaging - How the initial manifest and types can communication - -Nico Schottelius - -DESCRIPTION +Description ----------- cdist has a simple but powerful way of allowing communication between the initial manifest and types as well as types and types. @@ -27,11 +21,11 @@ This way overwriting any of the two files by accident does not interfere with other types. The order of execution is not defined unless you create dependencies -between the different objects (see cdist-manifest(7)) and thus you +between the different objects (see `cdist manifest `_) and thus you can only react reliably on messages by objects that you depend on. -AVAILABILITY +Availability ------------ Messaging is possible between all **local** scripts: @@ -41,7 +35,7 @@ Messaging is possible between all **local** scripts: - type/gencode-remote -EXAMPLES +Examples -------- When you want to emit a message use: @@ -98,17 +92,3 @@ Restart sshd on changes if grep -q "^__key_value/PermitRootLogin" "$__messages_in"; then echo $restart fi - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ -- `cdist-manifest(7) `_ -- `cdist-reference(7) `_ -- `cdist-type(7) `_ - - -COPYING -------- -Copyright \(C) 2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/cdist-os.rst b/docs/man/cdist-os.rst new file mode 100644 index 00000000..4f6b4820 --- /dev/null +++ b/docs/man/cdist-os.rst @@ -0,0 +1,16 @@ +Supported Operating Systems +=========================== + +cdist was tested or is know to run on at least + +* `Archlinux `_ +* `Debian `_ +* `CentOS `_ +* `Fedora `_ +* `FreeBSD `_ +* `Gentoo `_ +* `Mac OS X `_ +* `OpenBSD `_ +* `Redhat `_ +* `Ubuntu `_ +* `XenServer `_ diff --git a/docs/man/man7/cdist-quickstart.rst b/docs/man/cdist-quickstart.rst similarity index 82% rename from docs/man/man7/cdist-quickstart.rst rename to docs/man/cdist-quickstart.rst index fd7d2cde..20c33cb8 100644 --- a/docs/man/man7/cdist-quickstart.rst +++ b/docs/man/cdist-quickstart.rst @@ -1,31 +1,18 @@ -cdist-quickstart(7) -=================== +Quickstart +========== -NAME ----- -cdist-quickstart - Jump in and enjoy cdist - -Nico Schottelius - - -INTRODUCTION ------------- This tutorial is aimed at people learning cdist and shows typical approaches as well as gives an easy start into the world of configuration management. -This tutorial assumes you are configuring **localhost**, because -it is always available. Just replace **localhost** with your target -host for real life usage. - - - -QUICK START - GET YOUR HANDS DIRTY NOW --------------------------------------- For those who just want to configure a system with the cdist configuration management and do not need (or want) to understand everything. +This tutorial assumes you are configuring **localhost**, because +it is always available. Just replace **localhost** with your target +host for real life usage. + Cdist uses **ssh** for communication and transportation and usually logs into the **target host** as the **root** user. So you need to configure the **ssh server** @@ -84,15 +71,3 @@ code into your shell to get started and configure localhost:: That's it, you've successfully used cdist to configure your first host! Continue reading the next sections, to understand what you did and how to create a more sophisticated configuration. - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ -- `cdist-tutorial(7) `_ - - -COPYING -------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/cdist-reference.rst.sh b/docs/man/cdist-reference.rst.sh index 687394d2..42eced05 100755 --- a/docs/man/cdist-reference.rst.sh +++ b/docs/man/cdist-reference.rst.sh @@ -29,23 +29,17 @@ __cdist_myname=${0##*/}; __cdist_abs_myname="$__cdist_abs_mydir/$__cdist_myname" filename="${__cdist_myname%.sh}" -dest="$__cdist_abs_mydir/man7/$filename" +dest="$__cdist_abs_mydir/$filename" cd "$__cdist_abs_mydir" exec > "$dest" cat << eof -cdist-reference(7) -================== +Reference +========= +Variable, path and type reference for cdist -NAME ----- -cdist-reference - Variable, path and type reference for cdist - -Nico Schottelius - - -EXPLORERS +Explorers --------- The following global explorers are available: @@ -59,7 +53,7 @@ eof cat << eof -PATHS +Paths ----- \$HOME/.cdist The standard cdist configuration directory relative to your home directory @@ -76,10 +70,6 @@ confdir By default it consists of everything in \$HOME/.cdist and cdist/conf/. For more details see cdist(1) -confdir/files/ - Cdist does not care about this directory besides providing access to it. - It is thought to be a general file storage area. - confdir/manifest/init This is the central entry point. It is an executable (+x bit set) shell script that can use @@ -94,11 +84,11 @@ confdir/manifest/* maintain different groups of hosts. confdir/explorer/ - Contains explorers to be run on the target hosts, see cdist-explorer(7). + Contains explorers to be run on the target hosts, see \`cdist explorer \`_. confdir/type/ Contains all available types, which are used to provide - some kind of functionality. See cdist-type(7). + some kind of functionality. See \`cdist type \`_. confdir/type// Home of the type . @@ -133,7 +123,7 @@ confdir/type//parameter/boolean confdir/type//explorer Location of the type specific explorers. This directory is referenced by the variable __type_explorer (see below). - See cdist-explorer(7). + See \`cdist explorer \`_. confdir/type//files This directory is reserved for user data and will not be used @@ -158,27 +148,28 @@ out/object/ out/object//explorers Output of type specific explorers, per object. -TYPES +Types ----- The following types are available: eof -for type in $(ls man7/cdist-type__*.rst | LC_ALL=C sort); do +# If there is no such file then ls prints error to stderr, +# so redirect stderr to /dev/null. +for type in $(ls man7/cdist-type__*.rst 2>/dev/null | LC_ALL=C sort); do no_dir="${type#man7/}"; no_type="${no_dir#cdist-type}"; name="${no_type%.rst}"; - name_no_underline="$(echo $name | sed 's/^__/\\__/g')" manref="${no_dir%.rst}" man="${manref}(7)" - echo "- $name_no_underline" "(\`${man} <${manref}.html>\`_)" + echo "- $name" "(\`${man} \`_)" done cat << eof -OBJECTS +Objects ------- For object to object communication and tests, the following paths are usable within a object directory: @@ -195,17 +186,13 @@ stdin when the type was called. -ENVIRONMENT VARIABLES (FOR READING) +Environment variables (for reading) ----------------------------------- The following environment variables are exported by cdist: __explorer Directory that contains all global explorers. Available for: initial manifest, explorer, type explorer, shell -__files - Directory that contains content from the "files" subdirectories - from the configuration directories. - Available for: initial manifest, type manifest, type gencode, shell __manifest Directory that contains the initial manifest. Available for: initial manifest, type manifest, shell @@ -240,12 +227,12 @@ __type_explorer Directory that contains the type explorers. Available for: type explorer -ENVIRONMENT VARIABLES (FOR WRITING) +Environment variables (for writing) ----------------------------------- The following environment variables influence the behaviour of cdist: require - Setup dependencies between objects (see cdist-manifest(7)) + Setup dependencies between objects (see \`cdist manifest \`_) CDIST_LOCAL_SHELL Use this shell locally instead of /bin/sh to execute scripts @@ -254,24 +241,14 @@ CDIST_REMOTE_SHELL Use this shell remotely instead of /bin/sh to execute scripts CDIST_OVERRIDE - Allow overwriting type parameters (see cdist-manifest(7)) + Allow overwriting type parameters (see \`cdist manifest \`_) CDIST_ORDER_DEPENDENCY - Create dependencies based on the execution order (see cdist-manifest(7)) + Create dependencies based on the execution order (see \`cdist manifest \`_) CDIST_REMOTE_EXEC Use this command for remote execution (should behave like ssh) CDIST_REMOTE_COPY Use this command for remote copy (should behave like scp) - -SEE ALSO --------- -- \`cdist(1) <../man1/cdist.html>\`_ - - -COPYING -------- -Copyright \(C) 2011-2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). eof diff --git a/docs/man/man7/cdist-remote-exec-copy.rst b/docs/man/cdist-remote-exec-copy.rst similarity index 61% rename from docs/man/man7/cdist-remote-exec-copy.rst rename to docs/man/cdist-remote-exec-copy.rst index b8d54f8f..10a370c7 100644 --- a/docs/man/man7/cdist-remote-exec-copy.rst +++ b/docs/man/cdist-remote-exec-copy.rst @@ -1,15 +1,6 @@ -cdist-remote-exec-copy(7) -========================= +Remote exec and copy commands +============================= -NAME ----- -cdist-remote-exec-copy - How to use remote exec and copy - -Nico Schottelius - - -INTRO ------ Cdist interacts with the target host in two ways: - it executes code (__remote_exec) @@ -30,19 +21,3 @@ For __remote_copy, it must behave like scp. With this simple interface the user can take total control of how cdist interacts with the target when required, while the default implementation remains as simple as possible. - - -EXAMPLES --------- -See cdist/other/examples/remote/ for some example implementations. - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ - - -COPYING -------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-stages.rst b/docs/man/cdist-stages.rst similarity index 77% rename from docs/man/man7/cdist-stages.rst rename to docs/man/cdist-stages.rst index b58bb368..fd19ce0d 100644 --- a/docs/man/man7/cdist-stages.rst +++ b/docs/man/cdist-stages.rst @@ -1,19 +1,13 @@ -cdist-stages(7) -=============== +Execution stages +================ -NAME ----- -cdist-stages - Stages used during configuration deployment - -Nico Schottelius - -DESCRIPTION +Description ----------- Starting the execution of deployment with cdist, cdist passes through different stages. -STAGE 1: TARGET INFORMATION RETRIEVAL +Stage 1: target information retrieval ------------------------------------- In this stage information is collected about the target host using so called explorers. Every existing explorer is run on the target and the output of all @@ -21,7 +15,7 @@ explorers are copied back into the local cache. The results can be used by manifests and types. -STAGE 2: RUN THE INITIAL MANIFEST +Stage 2: run the initial manifest --------------------------------- The initial manifest, which should be used for mappings of hosts to types, is executed. This stage creates objects in a cconfig database that contains @@ -30,7 +24,7 @@ no conflicts may occur, i.e. no object of the same type with the same id may be created, if it has different parameters. -STAGE 3: OBJECT INFORMATION RETRIEVAL +Stage 3: object information retrieval ------------------------------------- Every object is checked whether its type has explorers and if so, these are executed on the target host. The results are transferred back @@ -38,7 +32,7 @@ and can be used in the following stages to decide what changes need to be made on the target to implement the desired state. -STAGE 4: RUN THE OBJECT MANIFEST +Stage 4: run the object manifest -------------------------------- Every object is checked whether its type has a executable manifest. The manifest script may generate and change the created objects. In other words, @@ -52,7 +46,7 @@ may occur during the merge. A conflict would mean that two different objects try to create the same object, which indicates a broken configuration. -STAGE 5: CODE GENERATION +Stage 5: code generation ------------------------ In this stage for every created object its type is checked for executable gencode scripts. The gencode scripts generate the code to be executed on the @@ -60,30 +54,18 @@ target on stdout. If the gencode executables fail, they must print diagnostic messages on stderr and exit non-zero. -STAGE 6: CODE EXECUTION +Stage 6: code execution ----------------------- For every object the resulting code from the previous stage is transferred to the target host and executed there to apply the configuration changes. -STAGE 7: CACHE +Stage 7: cache -------------- The cache stores the information from the current run for later use. -SUMMARY +Summary ------- If, and only if, all the stages complete without an errors, the configuration will be applied to the target. - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ -- `cdist-reference(7) `_ - - -COPYING -------- -Copyright \(C) 2010-2012 Nico Schottelius, Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/cdist-support.rst b/docs/man/cdist-support.rst new file mode 100644 index 00000000..2343500e --- /dev/null +++ b/docs/man/cdist-support.rst @@ -0,0 +1,28 @@ +Support +------- + +IRC +~~~ + +You can join the development ***IRC channel*** +`#cstar on irc.freenode.net `_. + +Mailing list +~~~~~~~~~~~~ + +Bug reports, questions, patches, etc. should be send to the +`cdist mailing list `_. + +Linkedin +~~~~~~~~ + +If you have an account +at `Linked in `_, +you can join the +`cdist group `_. + +Commercial support +~~~~~~~~~~~~~~~~~~ + +You can request commercial support for cdist from +`my company `_. diff --git a/docs/man/man7/cdist-troubleshooting.rst b/docs/man/cdist-troubleshooting.rst similarity index 73% rename from docs/man/man7/cdist-troubleshooting.rst rename to docs/man/cdist-troubleshooting.rst index edfadc34..b016e845 100644 --- a/docs/man/man7/cdist-troubleshooting.rst +++ b/docs/man/cdist-troubleshooting.rst @@ -1,14 +1,7 @@ -cdist-troubleshooting(7) -======================== +Troubleshooting +=============== -NAME ----- -cdist-troubleshooting - Common problems and their solutions - -Nico Schottelius - - -ERROR IN MANIFEST IS NOT CONSIDERED AN ERROR BY CDIST +Error in manifest is not considered an error by cdist ----------------------------------------------------- Situation: You are executing other scripts from a manifest. This script fails, but cdist does not recognise the error. @@ -50,15 +43,3 @@ you write to use the -e flag: % cat ~/.cdist/manifest/special #!/bin/sh -e ... - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ -- `cdist-tutorial(7) `_ - - -COPYING -------- -Copyright \(C) 2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/man7/cdist-type.rst b/docs/man/cdist-type.rst similarity index 88% rename from docs/man/man7/cdist-type.rst rename to docs/man/cdist-type.rst index 5500d9b3..c75d0a52 100644 --- a/docs/man/man7/cdist-type.rst +++ b/docs/man/cdist-type.rst @@ -1,31 +1,24 @@ -cdist-type(7) -============= +cdist type +========== -NAME ----- -cdist-type - Functionality bundled - -Nico Schottelius - - -SYNOPSIS --------- - -:: - - __TYPE ID --parameter value [--parameter value ...] - __TYPE --parameter value [--parameter value ...] (for singletons) - - -DESCRIPTION +Description ----------- Types are the main component of cdist and define functionality. If you use cdist, you'll write a type for every functionality you would like to use. +Synopsis +-------- -HOW TO USE A TYPE +.. code-block:: sh + + __TYPE ID --parameter value [--parameter value ...] + __TYPE --parameter value [--parameter value ...] (for singletons) + + +How to use a type ----------------- + You can use types from the initial manifest or the type manifest like a normal shell command: @@ -37,10 +30,10 @@ normal shell command: # Ensure tree is installed __package tree --state installed -A list of supported types can be found in the cdist-reference(7) manpage. +A list of supported types can be found in the `cdist reference `_ manpage. -SINGLETON TYPES +Singleton types --------------- If a type is flagged as a singleton, it may be used only once per host. This is useful for types which can be used only once on a @@ -58,7 +51,7 @@ Example: __myfancysingleton --colour green -HOW TO WRITE A NEW TYPE +How to write a new type ----------------------- A type consists of @@ -74,7 +67,7 @@ two underscores (__) to prevent collisions with other executables in $PATH. To implement a new type, create the directory **cdist/conf/type/__NAME**. -DEFINING PARAMETERS +Defining parameters ------------------- Every type consists of required, optional and boolean parameters, which must each be declared in a newline separated file in **parameter/required**, @@ -102,7 +95,7 @@ Example: echo use_ssl >> cdist/conf/type/__nginx_vhost/parameter/boolean -USING PARAMETERS +Using parameters ---------------- The parameters given to a type can be accessed and used in all type scripts (e.g manifest, gencode, explorer). Note that boolean parameters are @@ -138,7 +131,7 @@ Example: (e.g. in cdist/conf/type/__nginx_vhost/manifest) fi -INPUT FROM STDIN +Input from stdin ---------------- Every type can access what has been written on stdin when it has been called. The result is saved into the **stdin** file in the object directory. @@ -168,7 +161,7 @@ In the __file type, stdin is used as source for the file, if - is used for sourc .... -WRITING THE MANIFEST +Writing the manifest -------------------- In the manifest of a type you can use other types, so your type extends their functionality. A good example is the __package type, which in @@ -190,13 +183,13 @@ a shortened version looks like this: __package_$type "$@" As you can see, the type can reference different environment variables, -which are documented in cdist-reference(7). +which are documented in `cdist reference `_. Always ensure the manifest is executable, otherwise cdist will not be able -to execute it. For more information about manifests see cdist-manifest(7). +to execute it. For more information about manifests see `cdist manifest `_. -SINGLETON - ONE INSTANCE ONLY +Singleton - one instance only ----------------------------- If you want to ensure that a type can only be used once per target, you can mark it as a singleton: Just create the (empty) file "singleton" in your type @@ -216,7 +209,7 @@ As you can see, the object ID is omitted, because it does not make any sense, if your type can be used only once. -THE TYPE EXPLORERS +The type explorers ------------------ If a type needs to explore specific details, it can provide type specific explorers, which will be executed on the target for every created object. @@ -238,7 +231,7 @@ client, like this (shortened version from the type __file): fi -WRITING THE GENCODE SCRIPT +Writing the gencode script -------------------------- There are two gencode scripts: **gencode-local** and **gencode-remote**. The output of gencode-local is executed locally, whereas @@ -259,7 +252,7 @@ script, you can write to stderr: echo "touch /etc/cdist-configured" -VARIABLE ACCESS FROM THE GENERATED SCRIPTS +Variable access from the generated scripts ------------------------------------------ In the generated scripts, you have access to the following cdist variables @@ -280,7 +273,7 @@ So when you generate a script with the following content, it will work: fi -HINTS FOR TYPEWRITERS +Hints for typewriters ---------------------- It must be assumed that the target is pretty dumb and thus does not have high level tools like ruby installed. If a type requires specific tools to be present @@ -297,21 +290,8 @@ a folder named "files" within the type (again, because cdist guarantees to never ever touch this folder). -HOW TO INCLUDE A TYPE INTO UPSTREAM CDIST +How to include a type into upstream cdist ----------------------------------------- If you think your type may be useful for others, ensure it works with the -current master branch of cdist and have a look at cdist-hacker(7) on +current master branch of cdist and have a look at `cdist hacking `_ on how to submit it. - -SEE ALSO --------- -- `cdist-explorer(7) `_ -- `cdist-hacker(7) `_ -- `cdist-stages(7) `_ -- `cdist-tutorial(7) `_ - - -COPYING -------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/docs/man/cdist-types.rst b/docs/man/cdist-types.rst new file mode 100644 index 00000000..d5104667 --- /dev/null +++ b/docs/man/cdist-types.rst @@ -0,0 +1,8 @@ +cdist types +=========== + +.. toctree:: + :titlesonly: + :glob: + + man7/* diff --git a/docs/man/cdist-update.rst b/docs/man/cdist-update.rst new file mode 100644 index 00000000..0b445ba4 --- /dev/null +++ b/docs/man/cdist-update.rst @@ -0,0 +1,188 @@ +How to update cdist +=================== + +Update the git installation +--------------------------- + +To upgrade cdist in the current branch use + +.. code-block:: sh + + git pull + + # Also update the manpages + ./build man + export MANPATH=$MANPATH:$(pwd -P)/doc/man + +If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. +The master branch on the other hand is the development branch and may not be +working, break your setup or eat the tree in your garden. + +Safely upgrading to new versions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To upgrade to **any** further cdist version, you can take the +following procedure to do a safe upgrade: + +.. code-block:: sh + + # Create new branch to try out the update + git checkout -b upgrade_cdist + + # Get latest cdist version in git database + git fetch -v + + # see what will happen on merge - replace + # master with the branch you plan to merge + git diff upgrade_cdist..origin/master + + # Merge the new version + git merge origin/master + +Now you can ensure all custom types work with the new version. +Assume that you need to go back to an older version during +the migration/update, you can do so as follows: + +.. code-block:: sh + + # commit changes + git commit -m ... + + # go back to original branch + git checkout master + +After that, you can go back and continue the upgrade: + +.. code-block:: sh + + # git checkout upgrade_cdist + + +Update the python package +------------------------- + +To upgrade to the lastet version do + +.. code-block:: sh + + pip install --upgrade cdist + +General update instructions +--------------------------- + +Updating from 3.0 to 3.1 +~~~~~~~~~~~~~~~~~~~~~~~~ + +The type **\_\_ssh_authorized_keys** now also manages existing keys, +not only the ones added by cdist. + +Updating from 2.3 to 3.0 +~~~~~~~~~~~~~~~~~~~~~~~~ + +The **changed** attribute of objects has been removed. +Use `messaging `_ instead. + +Updating from 2.2 to 2.3 +~~~~~~~~~~~~~~~~~~~~~~~~ + +No incompatiblities. + +Updating from 2.1 to 2.2 +~~~~~~~~~~~~~~~~~~~~~~~~ + +Starting with 2.2, the syntax for requiring a singleton type changed: +Old format: + +.. code-block:: sh + + require="__singleton_type/singleton" ... + +New format: + +.. code-block:: sh + + require="__singleton_type" ... + +Internally the "singleton" object id was dropped to make life more easy. +You can probably fix your configuration by running the following code +snippet (currently untested, please report back if it works for you): + +.. code-block:: sh + + find ~/.cdist/* -type f -exec sed -i 's,/singleton,,' {} \; + +Updating from 2.0 to 2.1 +~~~~~~~~~~~~~~~~~~~~~~~~ + +Have a look at the update guide for [[2.0 to 2.1|2.0-to-2.1]]. + + * Type **\_\_package* and \_\_process** use --state **present** or **absent**. + The states **removed/installed** and **stopped/running** have been removed. + Support for the new states is already present in 2.0. + * Type **\_\_directory**: Parameter --parents and --recursive are now boolean + The old "yes/no" values need to be removed. + * Type **\_\_rvm_ruby**: Parameter --default is now boolean + The old "yes/no" values need to be removed. + * Type **\_\_rvm_gemset**: Parameter --default is now boolean + The old "yes/no" values need to be removed. + * Type **\_\_addifnosuchline** and **\_\_removeline** have been replaced by **\_\_line** + * The **conf** directory is now located at **cdist/conf**. + You need to migrate your types, explorers and manifests + manually to the new location. + * Replace the variable **\_\_self** by **\_\_object_name** + Support for the variable **\_\_object_name** is already present in 2.0. + * The types **\_\_autofs**, **\_\_autofs_map** and **\_\_autofs_reload** have been removed + (no maintainer, no users) + * Type **\_\_user**: Parameter --groups removed (use the new \_\_user_groups type) + * Type **\_\_ssh_authorized_key** has been replaced by more flexible type + **\_\_ssh_authorized_keys** + +Updating from 1.7 to 2.0 +~~~~~~~~~~~~~~~~~~~~~~~~ + +* Ensure python (>= 3.2) is installed on the source host +* Use "cdist config host" instead of "cdist-deploy-to host" +* Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" +* Use "cdist banner" for fun +* Use **\_\_object_name** instead of **\_\_self** in manifests + +Updating from 1.6 to 1.7 +~~~~~~~~~~~~~~~~~~~~~~~~ + +* If you used the global explorer **hardware_type**, you need to change + your code to use **machine** instead. + +Updating from 1.5 to 1.6 +~~~~~~~~~~~~~~~~~~~~~~~~ + +* If you used **\_\_package_apt --preseed**, you need to use the new + type **\_\_debconf_set_selections** instead. +* The **\_\_package** types accepted either --state deinstalled or + --state uninstaaled. Starting with 1.6, it was made consistently + to --state removed. + +Updating from 1.3 to 1.5 +~~~~~~~~~~~~~~~~~~~~~~~~ + +No incompatiblities. + +Updating from 1.2 to 1.3 +~~~~~~~~~~~~~~~~~~~~~~~~ + +Rename **gencode** of every type to **gencode-remote**. + +Updating from 1.1 to 1.2 +~~~~~~~~~~~~~~~~~~~~~~~~ + +No incompatiblities. + +Updating from 1.0 to 1.1 +~~~~~~~~~~~~~~~~~~~~~~~~ + +In 1.1 the type **\_\_file** was split into **\_\_directory**, **\_\_file** and +**\_\_link**. The parameter **--type** was removed from **\_\_file**. Thus you +need to replace **\_\_file** calls in your manifests: + + * Remove --type from all \_\_file calls + * If type was symlink, use \_\_link and --type symbolic + * If type was directory, use \_\_directory diff --git a/docs/man/cdist-why.rst b/docs/man/cdist-why.rst new file mode 100644 index 00000000..e6aefefd --- /dev/null +++ b/docs/man/cdist-why.rst @@ -0,0 +1,72 @@ +Why should I use cdist? +======================= + +There are several motivations to use cdist, these +are probably the most popular ones. + +Known language +-------------- + +Cdist is being configured in +`shell script `_. +Shell script is used by UNIX system engineers for decades. +So when cdist is introduced, your staff does not need to learn a new +`DSL `_ +or programming language. + +Powerful language +----------------- + +Not only is shell scripting widely known by system engineers, +but it is also a very powerful language. Here are some features +which make daily work easy: + + * Configuration can react dynamicly on explored values + * High level string manipulation (using sed, awk, grep) + * Conditional support (**if, case**) + * Loop support (**for, while**) + * Support for dependencies between cdist types + +More than shell scripting +------------------------- + +If you compare regular shell scripting with cdist, there is one major +difference: When using cdist types, +the results are +`idempotent `_. +In practise that means it does not matter in which order you +call cdist types, the result is always the same. + +Zero dependency configuration management +---------------------------------------- + +Cdist requires very litte on a target system. Even better, +in almost all cases all dependencies are usually fulfilled. +Cdist does not require an agent or a high level programming +languages on the target host: it will run on any host that +has a **ssh server running** and a posix compatible shell +(**/bin/sh**). Compared to other configuration management systems, +it does not require to open up an additional port. + +Push based distribution +----------------------- + +Cdist uses the push based model for configuration. In this +scenario, one (or more) computers connect the target hosts +and apply the configuration. That way the source host has +very little requirements: Cdist can even run on a sysadmin +notebook that is loosely connected to the network and has +limited amount of resources. + +Furthermore, from a security point of view, only one machine +needs access to the target hosts. No target hosts will ever +need to connect back to the source host, which contains the +full configuration. + +Highly scalable +--------------- + +If at some point you manage more hosts than can be handled from +a single source host, you can simply add more resources: Either +add more cores to one host or add hosts. +Cdist will utilise the given resources in parallel. diff --git a/docs/man/conf.py b/docs/man/conf.py index ed43d6d4..24a040b2 100644 --- a/docs/man/conf.py +++ b/docs/man/conf.py @@ -32,6 +32,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.realpath # ones. extensions = [ 'cdist.sphinxext.manpage', + 'sphinx.ext.extlinks', ] # Add any paths that contain templates here, relative to this directory. @@ -309,3 +310,9 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False + +extlinks = { + 'cdist_docs': + ('http://www.nico.schottelius.org/software/cdist/man/{}/%s.html'.format( + release), None), +} diff --git a/docs/man/index.rst b/docs/man/index.rst index f0638779..a34231f8 100644 --- a/docs/man/index.rst +++ b/docs/man/index.rst @@ -4,9 +4,28 @@ Welcome to cdist documentation Contents: .. toctree:: - :titlesonly: + :maxdepth: 2 :glob: :numbered: - man1/* - man7/* + cdist-intro + cdist-why + cdist-os + cdist-install + cdist-update + cdist-support + cdist-features + cdist-quickstart + man1/cdist + cdist-bootstrap + cdist-manifest + cdist-type + cdist-types + cdist-explorer + cdist-messaging + cdist-reference + cdist-best-practice + cdist-stages + cdist-remote-exec-copy + cdist-hacker + cdist-troubleshooting diff --git a/docs/man/man1/cdist.rst b/docs/man/man1/cdist.rst index f2b4c5d4..2a056482 100644 --- a/docs/man/man1/cdist.rst +++ b/docs/man/man1/cdist.rst @@ -5,8 +5,6 @@ NAME ---- cdist - Usable Configuration Management -Nico Schottelius - SYNOPSIS -------- @@ -179,9 +177,11 @@ The following exit values shall be returned: SEE ALSO -------- -- `cdist-type(7) <../man7/cdist-type.html>`_ -- `cdist-reference(7) <../man7/cdist-reference.html>`_ +Full documentation at: <:cdist_docs:`index`>. +AUTHORS +------- +Nico Schottelius COPYING ------- diff --git a/docs/man/man7/cdist-tutorial.rst b/docs/man/man7/cdist-tutorial.rst deleted file mode 100644 index fece6f36..00000000 --- a/docs/man/man7/cdist-tutorial.rst +++ /dev/null @@ -1,58 +0,0 @@ -cdist-tutorial(7) -================= - -NAME ----- -cdist-tutorial - A guided introduction into cdist - -Nico Schottelius - - -INTRODUCTION ------------- -This document gives you a pointer on what to read in -which order and is thus a "guide to the right locations". -So in case you are just starting, just "begin at the beginning" -(Brave New World). You can see the target audience in [] brackets -after the description. - -cdist-quickstart - New to cdist? Want to get your hands dirty? Read this. [beginner] - -cdist-bootstrap - The comprehensive guide to your first cdist installation [beginner] - -cdist-manifest - Learn how to define which hosts get which configurations [beginner] - -cdist-type - Understand how types are working and created [intermediate] - -cdist-best-practice - Hints from real life experience to help you to organise cdist [intermediate] - -cdist-reference - The type, explorers and environment variables reference [intermediate] - -cdist-explorer - Interested in getting more information about the target system? [intermediate] - -cdist-stages - Understand the internal workflow of cdist. [advanced] - -cdist-hacker - README, if you want to extend or modify cdist. [hacker] - - -SEE ALSO --------- -- `cdist(1) <../man1/cdist.html>`_ -- `cdist-type(7) `_ -- `cdist-best-practice(7) `_ -- `cdist-stages(7) `_ -- Brave New World by Aldous Huxley - -COPYING -------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). From f2ccb00f3ba22a9c39beca9d12159a0072d70e8f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 29 Jun 2016 09:12:40 +0200 Subject: [PATCH 0168/1332] Fix sphinx warning about html_static_path. --- docs/man/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/conf.py b/docs/man/conf.py index 24a040b2..916b06a4 100644 --- a/docs/man/conf.py +++ b/docs/man/conf.py @@ -144,7 +144,7 @@ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +# html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied From b4c77a6ef660511d4d2def5b946a9b218869e596 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 29 Jun 2016 09:13:33 +0200 Subject: [PATCH 0169/1332] Fix empty man7 dir - Makefile fails. --- docs/man/man7/.gitignore | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/man/man7/.gitignore diff --git a/docs/man/man7/.gitignore b/docs/man/man7/.gitignore new file mode 100644 index 00000000..e69de29b From 7f5f09830a017c85fbcedaca849c834523c125cf Mon Sep 17 00:00:00 2001 From: Stephan Leemburg Date: Wed, 29 Jun 2016 13:31:23 +0200 Subject: [PATCH 0170/1332] added changes to next: --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 33fe54b6..3be460b4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,9 @@ next: * New type: __jail_freebsd9: Handle jail management on FreeBSD <= 9.X (Jake Guffey) * New type: __jail_freebsd10: Handle jail management on FreeBSD >= 10.0 (Jake Guffey) * Type __jail: Dynamically select the correct jail subtype based on target host OS (Jake Guffey) + * Explorer __machine_type: add openvz and lxc + * Explorer __os __os_version: add scientific + * Type various: add scientific 4.1.0: 2016-05-27 * Documentation: Migrate to reStructuredText format and sphinx (Darko Poljak) From f98208f250085e7b683d0c7a82ea4ac2e3fbc11b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 30 Jun 2016 12:09:07 +0200 Subject: [PATCH 0171/1332] Make man pages SEE ALSO by convention. Improve docs building. --- .gitignore | 3 ++- cdist/conf/type/__apt_key/man.rst | 6 ------ cdist/conf/type/__apt_key_uri/man.rst | 6 ------ cdist/conf/type/__apt_norecommends/man.rst | 6 ------ cdist/conf/type/__apt_ppa/man.rst | 6 ------ cdist/conf/type/__apt_source/man.rst | 6 ------ cdist/conf/type/__apt_update_index/man.rst | 6 ------ cdist/conf/type/__block/man.rst | 6 ------ cdist/conf/type/__ccollect_source/man.rst | 7 +------ cdist/conf/type/__cdist/man.rst | 6 ------ cdist/conf/type/__cdistmarker/man.rst | 6 ------ cdist/conf/type/__config_file/man.rst | 5 +---- cdist/conf/type/__consul/man.rst | 6 ------ cdist/conf/type/__consul_agent/man.rst | 5 +---- cdist/conf/type/__consul_check/man.rst | 5 +---- cdist/conf/type/__consul_reload/man.rst | 6 ------ cdist/conf/type/__consul_service/man.rst | 5 +---- cdist/conf/type/__consul_template/man.rst | 5 +---- .../type/__consul_template_template/man.rst | 6 +----- cdist/conf/type/__consul_watch_checks/man.rst | 7 ++----- cdist/conf/type/__consul_watch_event/man.rst | 7 ++----- cdist/conf/type/__consul_watch_key/man.rst | 7 ++----- .../type/__consul_watch_keyprefix/man.rst | 6 ++---- cdist/conf/type/__consul_watch_nodes/man.rst | 7 ++----- .../conf/type/__consul_watch_service/man.rst | 6 ++---- .../conf/type/__consul_watch_services/man.rst | 7 ++----- cdist/conf/type/__cron/man.rst | 5 +---- .../type/__debconf_set_selections/man.rst | 6 +----- cdist/conf/type/__directory/man.rst | 6 ------ cdist/conf/type/__dog_vdi/man.rst | 5 +---- cdist/conf/type/__file/man.rst | 6 ------ cdist/conf/type/__firewalld_rule/man.rst | 6 +----- cdist/conf/type/__git/man.rst | 6 ------ cdist/conf/type/__group/man.rst | 6 ------ cdist/conf/type/__hostname/man.rst | 6 ------ cdist/conf/type/__iptables_apply/man.rst | 6 +----- cdist/conf/type/__iptables_rule/man.rst | 6 +----- cdist/conf/type/__issue/man.rst | 6 ------ cdist/conf/type/__jail/man.rst | 3 +-- cdist/conf/type/__jail_freebsd10/man.rst | 3 +-- cdist/conf/type/__jail_freebsd9/man.rst | 3 +-- cdist/conf/type/__key_value/man.rst | 6 ------ cdist/conf/type/__line/man.rst | 5 +---- cdist/conf/type/__link/man.rst | 6 ------ cdist/conf/type/__locale/man.rst | 5 +---- cdist/conf/type/__motd/man.rst | 6 ------ cdist/conf/type/__mount/man.rst | 6 ------ cdist/conf/type/__mysql_database/man.rst | 6 ------ cdist/conf/type/__package/man.rst | 6 ------ cdist/conf/type/__package_apt/man.rst | 5 +---- cdist/conf/type/__package_emerge/man.rst | 6 +----- .../__package_emerge_dependencies/man.rst | 6 +----- cdist/conf/type/__package_luarocks/man.rst | 5 +---- cdist/conf/type/__package_opkg/man.rst | 5 +---- cdist/conf/type/__package_pacman/man.rst | 5 +---- cdist/conf/type/__package_pip/man.rst | 5 +---- cdist/conf/type/__package_pkg_freebsd/man.rst | 5 +---- cdist/conf/type/__package_pkg_openbsd/man.rst | 5 +---- .../conf/type/__package_pkgng_freebsd/man.rst | 5 +---- cdist/conf/type/__package_rubygem/man.rst | 5 +---- .../conf/type/__package_update_index/man.rst | 6 ------ cdist/conf/type/__package_upgrade_all/man.rst | 6 ------ cdist/conf/type/__package_yum/man.rst | 5 +---- cdist/conf/type/__package_zypper/man.rst | 5 +---- cdist/conf/type/__pacman_conf/man.rst | 5 +---- .../conf/type/__pacman_conf_integrate/man.rst | 5 +---- cdist/conf/type/__pf_apply/man.rst | 6 +----- cdist/conf/type/__pf_ruleset/man.rst | 5 +---- cdist/conf/type/__postfix/man.rst | 6 ------ cdist/conf/type/__postfix_master/man.rst | 5 +---- cdist/conf/type/__postfix_postconf/man.rst | 5 +---- cdist/conf/type/__postfix_postmap/man.rst | 6 ------ cdist/conf/type/__postfix_reload/man.rst | 6 ------ cdist/conf/type/__postgres_database/man.rst | 5 +---- cdist/conf/type/__postgres_role/man.rst | 4 +--- cdist/conf/type/__process/man.rst | 5 +---- cdist/conf/type/__pyvenv/man.rst | 6 ------ cdist/conf/type/__qemu_img/man.rst | 5 +---- cdist/conf/type/__rbenv/man.rst | 6 ------ cdist/conf/type/__rsync/man.rst | 5 +---- cdist/conf/type/__rvm/man.rst | 8 ++----- cdist/conf/type/__rvm_gem/man.rst | 8 ++----- cdist/conf/type/__rvm_gemset/man.rst | 8 ++----- cdist/conf/type/__rvm_ruby/man.rst | 8 ++----- cdist/conf/type/__ssh_authorized_key/man.rst | 5 +---- cdist/conf/type/__ssh_authorized_keys/man.rst | 5 +---- cdist/conf/type/__ssh_dot_ssh/man.rst | 5 +---- cdist/conf/type/__staged_file/man.rst | 5 +---- cdist/conf/type/__start_on_boot/man.rst | 5 +---- cdist/conf/type/__timezone/man.rst | 6 ------ cdist/conf/type/__update_alternatives/man.rst | 6 +----- cdist/conf/type/__user/man.rst | 5 +---- cdist/conf/type/__user_groups/man.rst | 6 ------ cdist/conf/type/__yum_repo/man.rst | 6 ------ cdist/conf/type/__zypper_repo/man.rst | 6 ------ cdist/conf/type/__zypper_service/man.rst | 6 ------ docs/man/Makefile | 7 +++++-- docs/man/cdist-install.rst | 21 ++++++++++++++----- docs/man/conf.py | 6 ------ docs/man/man1/cdist.rst | 4 ---- 100 files changed, 94 insertions(+), 485 deletions(-) diff --git a/.gitignore b/.gitignore index 6152451b..3bbc4e99 100644 --- a/.gitignore +++ b/.gitignore @@ -20,8 +20,9 @@ MANIFEST dist/ cdist/version.py -#sphinx build dir +# sphinx build dirs, cache _build/ +docs/dist # Packaging: Archlinux /PKGBUILD diff --git a/cdist/conf/type/__apt_key/man.rst b/cdist/conf/type/__apt_key/man.rst index 01d4eea4..488a1a06 100644 --- a/cdist/conf/type/__apt_key/man.rst +++ b/cdist/conf/type/__apt_key/man.rst @@ -48,12 +48,6 @@ EXAMPLES __apt_key UbuntuArchiveKey --keyid 437D05B5 --keyserver keyserver.ubuntu.com -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__apt_key_uri/man.rst b/cdist/conf/type/__apt_key_uri/man.rst index 9c0042bb..e8741dff 100644 --- a/cdist/conf/type/__apt_key_uri/man.rst +++ b/cdist/conf/type/__apt_key_uri/man.rst @@ -38,12 +38,6 @@ EXAMPLES --state present -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__apt_norecommends/man.rst b/cdist/conf/type/__apt_norecommends/man.rst index 0198d7bd..7ef496c3 100644 --- a/cdist/conf/type/__apt_norecommends/man.rst +++ b/cdist/conf/type/__apt_norecommends/man.rst @@ -29,12 +29,6 @@ EXAMPLES __apt_norecommends -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__apt_ppa/man.rst b/cdist/conf/type/__apt_ppa/man.rst index e91e82fe..978e1252 100644 --- a/cdist/conf/type/__apt_ppa/man.rst +++ b/cdist/conf/type/__apt_ppa/man.rst @@ -37,12 +37,6 @@ EXAMPLES __apt_ppa ppa:sans-intern/missing-bits --state absent -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__apt_source/man.rst b/cdist/conf/type/__apt_source/man.rst index e4916515..31f2e9e6 100644 --- a/cdist/conf/type/__apt_source/man.rst +++ b/cdist/conf/type/__apt_source/man.rst @@ -56,12 +56,6 @@ EXAMPLES --component partner --state present -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__apt_update_index/man.rst b/cdist/conf/type/__apt_update_index/man.rst index e0672620..326d4c2f 100644 --- a/cdist/conf/type/__apt_update_index/man.rst +++ b/cdist/conf/type/__apt_update_index/man.rst @@ -28,12 +28,6 @@ EXAMPLES __apt_update_index -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__block/man.rst b/cdist/conf/type/__block/man.rst index 3b7c3439..6d7b8ba1 100644 --- a/cdist/conf/type/__block/man.rst +++ b/cdist/conf/type/__block/man.rst @@ -69,12 +69,6 @@ EXAMPLES DONE -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__ccollect_source/man.rst b/cdist/conf/type/__ccollect_source/man.rst index 5d980bda..cdacd31c 100644 --- a/cdist/conf/type/__ccollect_source/man.rst +++ b/cdist/conf/type/__ccollect_source/man.rst @@ -53,12 +53,7 @@ EXAMPLES SEE ALSO -------- -ccollect(1) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -ccollect documentation at: -. +:manpage:`ccollect`\ (1) AUTHORS diff --git a/cdist/conf/type/__cdist/man.rst b/cdist/conf/type/__cdist/man.rst index ad544c5c..1bfb35c5 100644 --- a/cdist/conf/type/__cdist/man.rst +++ b/cdist/conf/type/__cdist/man.rst @@ -50,12 +50,6 @@ EXAMPLES __cdist --source "git://git.schottelius.org/cdist" /home/cdist/cdist -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Nico Schottelius diff --git a/cdist/conf/type/__cdistmarker/man.rst b/cdist/conf/type/__cdistmarker/man.rst index 156aed62..cb4dace8 100644 --- a/cdist/conf/type/__cdistmarker/man.rst +++ b/cdist/conf/type/__cdistmarker/man.rst @@ -42,12 +42,6 @@ EXAMPLES __cdistmarker --destination /tmp/cdist_marker --format '+%s' -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Daniel Maher diff --git a/cdist/conf/type/__config_file/man.rst b/cdist/conf/type/__config_file/man.rst index acb3c848..b9d58979 100644 --- a/cdist/conf/type/__config_file/man.rst +++ b/cdist/conf/type/__config_file/man.rst @@ -48,10 +48,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__file(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__file`\ (7) AUTHORS diff --git a/cdist/conf/type/__consul/man.rst b/cdist/conf/type/__consul/man.rst index 4096a233..c15ded45 100644 --- a/cdist/conf/type/__consul/man.rst +++ b/cdist/conf/type/__consul/man.rst @@ -41,12 +41,6 @@ EXAMPLES --version 0.4.1 -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__consul_agent/man.rst b/cdist/conf/type/__consul_agent/man.rst index 7a15a058..5a35a2cc 100644 --- a/cdist/conf/type/__consul_agent/man.rst +++ b/cdist/conf/type/__consul_agent/man.rst @@ -165,10 +165,7 @@ EXAMPLES SEE ALSO -------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -consul documentation at: -. +consul documentation at: . AUTHORS diff --git a/cdist/conf/type/__consul_check/man.rst b/cdist/conf/type/__consul_check/man.rst index 87e2d7a9..c0d0b459 100644 --- a/cdist/conf/type/__consul_check/man.rst +++ b/cdist/conf/type/__consul_check/man.rst @@ -62,10 +62,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_agent(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__consul_agent`\ (7) AUTHORS diff --git a/cdist/conf/type/__consul_reload/man.rst b/cdist/conf/type/__consul_reload/man.rst index 62b08c7f..410bd5e6 100644 --- a/cdist/conf/type/__consul_reload/man.rst +++ b/cdist/conf/type/__consul_reload/man.rst @@ -29,12 +29,6 @@ EXAMPLES __consul_reload -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__consul_service/man.rst b/cdist/conf/type/__consul_service/man.rst index 560266a4..75b06aa0 100644 --- a/cdist/conf/type/__consul_service/man.rst +++ b/cdist/conf/type/__consul_service/man.rst @@ -66,10 +66,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_agent(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__consul_agent`\ (7) AUTHORS diff --git a/cdist/conf/type/__consul_template/man.rst b/cdist/conf/type/__consul_template/man.rst index d2d484e5..a6228cad 100644 --- a/cdist/conf/type/__consul_template/man.rst +++ b/cdist/conf/type/__consul_template/man.rst @@ -125,10 +125,7 @@ EXAMPLES SEE ALSO -------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -consul documentation at: -. +consul documentation at: . AUTHORS diff --git a/cdist/conf/type/__consul_template_template/man.rst b/cdist/conf/type/__consul_template_template/man.rst index 9932346b..b54f759e 100644 --- a/cdist/conf/type/__consul_template_template/man.rst +++ b/cdist/conf/type/__consul_template_template/man.rst @@ -59,11 +59,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_template(7) `_, -`cdist-type__consul_template_config(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__consul_template`\ (7), :manpage:`cdist-type__consul_template_config`\ (7) AUTHORS diff --git a/cdist/conf/type/__consul_watch_checks/man.rst b/cdist/conf/type/__consul_watch_checks/man.rst index dc3c9669..ec04b0b3 100644 --- a/cdist/conf/type/__consul_watch_checks/man.rst +++ b/cdist/conf/type/__consul_watch_checks/man.rst @@ -55,12 +55,9 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_agent(7) `_ +:manpage:`cdist-type__consul_agent`\ (7) -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -consul documentation at: -. +consul documentation at: . AUTHORS diff --git a/cdist/conf/type/__consul_watch_event/man.rst b/cdist/conf/type/__consul_watch_event/man.rst index 73b16754..664a19a2 100644 --- a/cdist/conf/type/__consul_watch_event/man.rst +++ b/cdist/conf/type/__consul_watch_event/man.rst @@ -48,12 +48,9 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_agent(7) `_ +:manpage:`cdist-type__consul_agent`\ (7) -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -consul documentation at: -. +consul documentation at: . AUTHORS diff --git a/cdist/conf/type/__consul_watch_key/man.rst b/cdist/conf/type/__consul_watch_key/man.rst index c258119c..0f90245c 100644 --- a/cdist/conf/type/__consul_watch_key/man.rst +++ b/cdist/conf/type/__consul_watch_key/man.rst @@ -45,12 +45,9 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_agent(7) `_ +:manpage:`cdist-type__consul_agent`\ (7) -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -consul documentation at: -. +consul documentation at: . AUTHORS diff --git a/cdist/conf/type/__consul_watch_keyprefix/man.rst b/cdist/conf/type/__consul_watch_keyprefix/man.rst index 950c0a26..65fa16af 100644 --- a/cdist/conf/type/__consul_watch_keyprefix/man.rst +++ b/cdist/conf/type/__consul_watch_keyprefix/man.rst @@ -45,11 +45,9 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_agent(7) `_ +:manpage:`cdist-type__consul_agent`\ (7) -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -consule documentation at: . +consul documentation at: . AUTHORS diff --git a/cdist/conf/type/__consul_watch_nodes/man.rst b/cdist/conf/type/__consul_watch_nodes/man.rst index a44dada4..5a5bdbd2 100644 --- a/cdist/conf/type/__consul_watch_nodes/man.rst +++ b/cdist/conf/type/__consul_watch_nodes/man.rst @@ -41,12 +41,9 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_agent(7) `_ +:manpage:`cdist-type__consul_agent`\ (7) -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -consul documentation at: -. +consul documentation at: . AUTHORS diff --git a/cdist/conf/type/__consul_watch_service/man.rst b/cdist/conf/type/__consul_watch_service/man.rst index fa6450fe..38ee501a 100644 --- a/cdist/conf/type/__consul_watch_service/man.rst +++ b/cdist/conf/type/__consul_watch_service/man.rst @@ -65,11 +65,9 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_agent(7) `_ +:manpage:`cdist-type__consul_agent`\ (7) -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -consule documentation at: . +consul documentation at: . AUTHORS diff --git a/cdist/conf/type/__consul_watch_services/man.rst b/cdist/conf/type/__consul_watch_services/man.rst index db561593..41b115ae 100644 --- a/cdist/conf/type/__consul_watch_services/man.rst +++ b/cdist/conf/type/__consul_watch_services/man.rst @@ -41,12 +41,9 @@ EXAMPLES SEE ALSO -------- -`cdist-type__consul_agent(7) `_ +:manpage:`cdist-type__consul_agent`\ (7) -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. -consul documentation at: -. +consul documentation at: . AUTHORS diff --git a/cdist/conf/type/__cron/man.rst b/cdist/conf/type/__cron/man.rst index e8f32c52..4b9cb83d 100644 --- a/cdist/conf/type/__cron/man.rst +++ b/cdist/conf/type/__cron/man.rst @@ -68,10 +68,7 @@ EXAMPLES SEE ALSO -------- -crontab(5) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`crontab`\ (5) AUTHORS diff --git a/cdist/conf/type/__debconf_set_selections/man.rst b/cdist/conf/type/__debconf_set_selections/man.rst index 27e037e7..b7e5f901 100644 --- a/cdist/conf/type/__debconf_set_selections/man.rst +++ b/cdist/conf/type/__debconf_set_selections/man.rst @@ -37,11 +37,7 @@ EXAMPLES SEE ALSO -------- -debconf-set-selections(1), -`cdist-type__update_alternatives(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`debconf-set-selections`\ (1), :manpage:`cdist-type__update_alternatives`\ (7) AUTHORS diff --git a/cdist/conf/type/__directory/man.rst b/cdist/conf/type/__directory/man.rst index abb07eff..e756b1d6 100644 --- a/cdist/conf/type/__directory/man.rst +++ b/cdist/conf/type/__directory/man.rst @@ -88,12 +88,6 @@ EXAMPLES --owner root --group root --mode 0755 --state present -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Nico Schottelius diff --git a/cdist/conf/type/__dog_vdi/man.rst b/cdist/conf/type/__dog_vdi/man.rst index b0f700c6..65bea479 100644 --- a/cdist/conf/type/__dog_vdi/man.rst +++ b/cdist/conf/type/__dog_vdi/man.rst @@ -43,10 +43,7 @@ EXAMPLES SEE ALSO -------- -qemu(1), dog(8) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`qemu`\ (1), :manpage:`dog`\ (8) AUTHORS diff --git a/cdist/conf/type/__file/man.rst b/cdist/conf/type/__file/man.rst index fa71e5ce..e21390c7 100644 --- a/cdist/conf/type/__file/man.rst +++ b/cdist/conf/type/__file/man.rst @@ -99,12 +99,6 @@ EXAMPLES DONE -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Nico Schottelius diff --git a/cdist/conf/type/__firewalld_rule/man.rst b/cdist/conf/type/__firewalld_rule/man.rst index 2d1f5589..414eb7e9 100644 --- a/cdist/conf/type/__firewalld_rule/man.rst +++ b/cdist/conf/type/__firewalld_rule/man.rst @@ -65,11 +65,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__iptables_rule(7) `_, -firewalld(8) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__iptables_rule`\ (7), :manpage:`firewalld`\ (8) AUTHORS diff --git a/cdist/conf/type/__git/man.rst b/cdist/conf/type/__git/man.rst index 2f344a69..c1341ec0 100644 --- a/cdist/conf/type/__git/man.rst +++ b/cdist/conf/type/__git/man.rst @@ -47,12 +47,6 @@ EXAMPLES __git /home/nico/cdist --source git://github.com/telmich/cdist.git --branch 2.1 -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Nico Schottelius diff --git a/cdist/conf/type/__group/man.rst b/cdist/conf/type/__group/man.rst index c6c9d226..daea0909 100644 --- a/cdist/conf/type/__group/man.rst +++ b/cdist/conf/type/__group/man.rst @@ -67,12 +67,6 @@ EXAMPLES __group foobar --gid 1234 --password 'crypted-password-string' -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__hostname/man.rst b/cdist/conf/type/__hostname/man.rst index bfb9d457..ea1186bc 100644 --- a/cdist/conf/type/__hostname/man.rst +++ b/cdist/conf/type/__hostname/man.rst @@ -39,12 +39,6 @@ EXAMPLES __hostname --name some-static-hostname -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__iptables_apply/man.rst b/cdist/conf/type/__iptables_apply/man.rst index 5f4f4dc8..48697f9c 100644 --- a/cdist/conf/type/__iptables_apply/man.rst +++ b/cdist/conf/type/__iptables_apply/man.rst @@ -29,11 +29,7 @@ None (__iptables_apply is used by __iptables_rule) SEE ALSO -------- -`cdist-type__iptables_rule(7) `_, -iptables(8) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__iptables_rule`\ (7), :manpage:`iptables`\ (8) AUTHORS diff --git a/cdist/conf/type/__iptables_rule/man.rst b/cdist/conf/type/__iptables_rule/man.rst index 4d02e1d7..fab6c47a 100644 --- a/cdist/conf/type/__iptables_rule/man.rst +++ b/cdist/conf/type/__iptables_rule/man.rst @@ -50,11 +50,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__iptables_apply(7) `_, -iptables(8) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__iptables_apply`\ (7), :manpage:`iptables`\ (8) AUTHORS diff --git a/cdist/conf/type/__issue/man.rst b/cdist/conf/type/__issue/man.rst index 77f28da2..eacd8378 100644 --- a/cdist/conf/type/__issue/man.rst +++ b/cdist/conf/type/__issue/man.rst @@ -34,12 +34,6 @@ EXAMPLES __issue --source "$__type/files/myfancyissue" -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Nico Schottelius diff --git a/cdist/conf/type/__jail/man.rst b/cdist/conf/type/__jail/man.rst index ba175aa4..756e7660 100644 --- a/cdist/conf/type/__jail/man.rst +++ b/cdist/conf/type/__jail/man.rst @@ -108,8 +108,7 @@ EXAMPLES SEE ALSO -------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`jail`\ (8) AUTHORS diff --git a/cdist/conf/type/__jail_freebsd10/man.rst b/cdist/conf/type/__jail_freebsd10/man.rst index 9916afcb..34dc2198 100644 --- a/cdist/conf/type/__jail_freebsd10/man.rst +++ b/cdist/conf/type/__jail_freebsd10/man.rst @@ -107,8 +107,7 @@ EXAMPLES SEE ALSO -------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`jail`\ (8) AUTHORS diff --git a/cdist/conf/type/__jail_freebsd9/man.rst b/cdist/conf/type/__jail_freebsd9/man.rst index 21266dd8..ca526cd0 100644 --- a/cdist/conf/type/__jail_freebsd9/man.rst +++ b/cdist/conf/type/__jail_freebsd9/man.rst @@ -108,8 +108,7 @@ EXAMPLES SEE ALSO -------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`jail`\ (8) AUTHORS diff --git a/cdist/conf/type/__key_value/man.rst b/cdist/conf/type/__key_value/man.rst index 78e29276..80d6aa89 100644 --- a/cdist/conf/type/__key_value/man.rst +++ b/cdist/conf/type/__key_value/man.rst @@ -81,12 +81,6 @@ This type try to handle as many values as possible, so it doesn't use regexes. So you need to exactly specify the key and delimiter. Delimiter can be of any lenght. -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__line/man.rst b/cdist/conf/type/__line/man.rst index 3a773f6a..1f38a974 100644 --- a/cdist/conf/type/__line/man.rst +++ b/cdist/conf/type/__line/man.rst @@ -61,10 +61,7 @@ EXAMPLES SEE ALSO -------- -grep(1) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`grep`\ (1) AUTHORS diff --git a/cdist/conf/type/__link/man.rst b/cdist/conf/type/__link/man.rst index 0d0f2fad..4560b1af 100644 --- a/cdist/conf/type/__link/man.rst +++ b/cdist/conf/type/__link/man.rst @@ -47,12 +47,6 @@ EXAMPLES __link /opt/plone --state absent -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Nico Schottelius diff --git a/cdist/conf/type/__locale/man.rst b/cdist/conf/type/__locale/man.rst index c555bd00..51ed38df 100644 --- a/cdist/conf/type/__locale/man.rst +++ b/cdist/conf/type/__locale/man.rst @@ -34,10 +34,7 @@ EXAMPLES SEE ALSO -------- -locale(1), localedef(1) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`locale`\ (1), :manpage:`localedef`\ (1) AUTHORS diff --git a/cdist/conf/type/__motd/man.rst b/cdist/conf/type/__motd/man.rst index e1530495..b568985f 100644 --- a/cdist/conf/type/__motd/man.rst +++ b/cdist/conf/type/__motd/man.rst @@ -35,12 +35,6 @@ EXAMPLES __motd --source "$__type/files/my-motd" -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Nico Schottelius diff --git a/cdist/conf/type/__mount/man.rst b/cdist/conf/type/__mount/man.rst index c53457ac..799288af 100644 --- a/cdist/conf/type/__mount/man.rst +++ b/cdist/conf/type/__mount/man.rst @@ -71,12 +71,6 @@ EXAMPLES --options "mfsmaster=mfsmaster.domain.tld,mfssubfolder=/one,nonempty,_netdev" -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__mysql_database/man.rst b/cdist/conf/type/__mysql_database/man.rst index 921df7f3..0e21a8a1 100644 --- a/cdist/conf/type/__mysql_database/man.rst +++ b/cdist/conf/type/__mysql_database/man.rst @@ -36,12 +36,6 @@ EXAMPLES __mysql_database "cdist" --name "cdist" --user "myuser" --password "mypwd" -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Benedikt Koeppel diff --git a/cdist/conf/type/__package/man.rst b/cdist/conf/type/__package/man.rst index fe806a53..91319e18 100644 --- a/cdist/conf/type/__package/man.rst +++ b/cdist/conf/type/__package/man.rst @@ -51,12 +51,6 @@ EXAMPLES __package vim --state present --type __package_apt -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__package_apt/man.rst b/cdist/conf/type/__package_apt/man.rst index 39eb550b..a841fc5b 100644 --- a/cdist/conf/type/__package_apt/man.rst +++ b/cdist/conf/type/__package_apt/man.rst @@ -46,10 +46,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_emerge/man.rst b/cdist/conf/type/__package_emerge/man.rst index 24f3546d..ceb0f169 100644 --- a/cdist/conf/type/__package_emerge/man.rst +++ b/cdist/conf/type/__package_emerge/man.rst @@ -47,11 +47,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_, -`cdist-type__package_emerge_dependencies(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7), :manpage:`cdist-type__package_emerge_dependencies`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_emerge_dependencies/man.rst b/cdist/conf/type/__package_emerge_dependencies/man.rst index b07d2284..1a227853 100644 --- a/cdist/conf/type/__package_emerge_dependencies/man.rst +++ b/cdist/conf/type/__package_emerge_dependencies/man.rst @@ -36,11 +36,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_, -`cdist-type__package_emerge(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7), :manpage:`cdist-type__package_emerge`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_luarocks/man.rst b/cdist/conf/type/__package_luarocks/man.rst index e5279513..399b07af 100644 --- a/cdist/conf/type/__package_luarocks/man.rst +++ b/cdist/conf/type/__package_luarocks/man.rst @@ -39,10 +39,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_opkg/man.rst b/cdist/conf/type/__package_opkg/man.rst index 9ad4d99f..203b8a36 100644 --- a/cdist/conf/type/__package_opkg/man.rst +++ b/cdist/conf/type/__package_opkg/man.rst @@ -39,10 +39,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pacman/man.rst b/cdist/conf/type/__package_pacman/man.rst index b144422b..44f36255 100644 --- a/cdist/conf/type/__package_pacman/man.rst +++ b/cdist/conf/type/__package_pacman/man.rst @@ -42,10 +42,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pip/man.rst b/cdist/conf/type/__package_pip/man.rst index 026562c1..f1ba98d9 100644 --- a/cdist/conf/type/__package_pip/man.rst +++ b/cdist/conf/type/__package_pip/man.rst @@ -49,10 +49,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pkg_freebsd/man.rst b/cdist/conf/type/__package_pkg_freebsd/man.rst index 8249c8f5..a2633bcb 100644 --- a/cdist/conf/type/__package_pkg_freebsd/man.rst +++ b/cdist/conf/type/__package_pkg_freebsd/man.rst @@ -54,10 +54,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pkg_openbsd/man.rst b/cdist/conf/type/__package_pkg_openbsd/man.rst index 9d253dce..e776956c 100644 --- a/cdist/conf/type/__package_pkg_openbsd/man.rst +++ b/cdist/conf/type/__package_pkg_openbsd/man.rst @@ -54,10 +54,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pkgng_freebsd/man.rst b/cdist/conf/type/__package_pkgng_freebsd/man.rst index 83fbf7bf..9fdd7c76 100644 --- a/cdist/conf/type/__package_pkgng_freebsd/man.rst +++ b/cdist/conf/type/__package_pkgng_freebsd/man.rst @@ -85,10 +85,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_rubygem/man.rst b/cdist/conf/type/__package_rubygem/man.rst index 0822bcf2..eb76a036 100644 --- a/cdist/conf/type/__package_rubygem/man.rst +++ b/cdist/conf/type/__package_rubygem/man.rst @@ -39,10 +39,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_update_index/man.rst b/cdist/conf/type/__package_update_index/man.rst index a8f16d21..e64fddae 100644 --- a/cdist/conf/type/__package_update_index/man.rst +++ b/cdist/conf/type/__package_update_index/man.rst @@ -40,12 +40,6 @@ EXAMPLES __package_update_index --type apt -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Ricardo Catalinas Jiménez diff --git a/cdist/conf/type/__package_upgrade_all/man.rst b/cdist/conf/type/__package_upgrade_all/man.rst index f6b216b4..fd4dba44 100644 --- a/cdist/conf/type/__package_upgrade_all/man.rst +++ b/cdist/conf/type/__package_upgrade_all/man.rst @@ -40,12 +40,6 @@ EXAMPLES __package_upgrade_all --type apt -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Ricardo Catalinas Jiménez diff --git a/cdist/conf/type/__package_yum/man.rst b/cdist/conf/type/__package_yum/man.rst index 487150b9..544afbf2 100644 --- a/cdist/conf/type/__package_yum/man.rst +++ b/cdist/conf/type/__package_yum/man.rst @@ -49,10 +49,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_zypper/man.rst b/cdist/conf/type/__package_zypper/man.rst index 754b5ddd..da8d1d81 100644 --- a/cdist/conf/type/__package_zypper/man.rst +++ b/cdist/conf/type/__package_zypper/man.rst @@ -56,10 +56,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__package(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__pacman_conf/man.rst b/cdist/conf/type/__pacman_conf/man.rst index c0040664..a61f2498 100644 --- a/cdist/conf/type/__pacman_conf/man.rst +++ b/cdist/conf/type/__pacman_conf/man.rst @@ -59,10 +59,7 @@ EXAMPLES SEE ALSO -------- -grep(1) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`grep`\ (1) AUTHORS diff --git a/cdist/conf/type/__pacman_conf_integrate/man.rst b/cdist/conf/type/__pacman_conf_integrate/man.rst index 10ff0c8a..77d5c1c3 100644 --- a/cdist/conf/type/__pacman_conf_integrate/man.rst +++ b/cdist/conf/type/__pacman_conf_integrate/man.rst @@ -35,10 +35,7 @@ EXAMPLES SEE ALSO -------- -grep(1) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`grep`\ (1) AUTHORS diff --git a/cdist/conf/type/__pf_apply/man.rst b/cdist/conf/type/__pf_apply/man.rst index 20374699..2c7fd4fb 100644 --- a/cdist/conf/type/__pf_apply/man.rst +++ b/cdist/conf/type/__pf_apply/man.rst @@ -39,11 +39,7 @@ EXAMPLES SEE ALSO -------- -pf(4), -`cdist-type__pf_ruleset(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`pf`\ (4), :manpage:`cdist-type__pf_ruleset`\ (7) AUTHORS diff --git a/cdist/conf/type/__pf_ruleset/man.rst b/cdist/conf/type/__pf_ruleset/man.rst index 15d50408..eb97e086 100644 --- a/cdist/conf/type/__pf_ruleset/man.rst +++ b/cdist/conf/type/__pf_ruleset/man.rst @@ -39,10 +39,7 @@ EXAMPLES SEE ALSO -------- -pf(4) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`pf`\ (4) AUTHORS diff --git a/cdist/conf/type/__postfix/man.rst b/cdist/conf/type/__postfix/man.rst index 628356b2..dff85fec 100644 --- a/cdist/conf/type/__postfix/man.rst +++ b/cdist/conf/type/__postfix/man.rst @@ -29,12 +29,6 @@ EXAMPLES __postfix -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__postfix_master/man.rst b/cdist/conf/type/__postfix_master/man.rst index 7f100485..27078070 100644 --- a/cdist/conf/type/__postfix_master/man.rst +++ b/cdist/conf/type/__postfix_master/man.rst @@ -68,10 +68,7 @@ EXAMPLES SEE ALSO -------- -master(5) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`master`\ (5) AUTHORS diff --git a/cdist/conf/type/__postfix_postconf/man.rst b/cdist/conf/type/__postfix_postconf/man.rst index f1a4b0a6..5773fcaf 100644 --- a/cdist/conf/type/__postfix_postconf/man.rst +++ b/cdist/conf/type/__postfix_postconf/man.rst @@ -38,10 +38,7 @@ EXAMPLES SEE ALSO -------- -postconf(5) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`postconf`\ (5) AUTHORS diff --git a/cdist/conf/type/__postfix_postmap/man.rst b/cdist/conf/type/__postfix_postmap/man.rst index 20aeb2df..2f455346 100644 --- a/cdist/conf/type/__postfix_postmap/man.rst +++ b/cdist/conf/type/__postfix_postmap/man.rst @@ -29,12 +29,6 @@ EXAMPLES __postfix_postmap /etc/postfix/generic -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__postfix_reload/man.rst b/cdist/conf/type/__postfix_reload/man.rst index ec9529e9..36a66d45 100644 --- a/cdist/conf/type/__postfix_reload/man.rst +++ b/cdist/conf/type/__postfix_reload/man.rst @@ -29,12 +29,6 @@ EXAMPLES __postfix_reload -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__postgres_database/man.rst b/cdist/conf/type/__postgres_database/man.rst index 2a0ad8d0..69e1a67f 100644 --- a/cdist/conf/type/__postgres_database/man.rst +++ b/cdist/conf/type/__postgres_database/man.rst @@ -30,10 +30,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__postgres_role(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__postgres_role`\ (7) AUTHORS diff --git a/cdist/conf/type/__postgres_role/man.rst b/cdist/conf/type/__postgres_role/man.rst index 9d0b68ab..f9293be5 100644 --- a/cdist/conf/type/__postgres_role/man.rst +++ b/cdist/conf/type/__postgres_role/man.rst @@ -48,10 +48,8 @@ EXAMPLES SEE ALSO -------- -`cdist-type__postgres_database(7) `_ +:manpage:`cdist-type__postgres_database`\ (7) -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. postgresql documentation at: . diff --git a/cdist/conf/type/__process/man.rst b/cdist/conf/type/__process/man.rst index 076377e1..19f68ddc 100644 --- a/cdist/conf/type/__process/man.rst +++ b/cdist/conf/type/__process/man.rst @@ -58,10 +58,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__start_on_boot(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__start_on_boot`\ (7) AUTHORS diff --git a/cdist/conf/type/__pyvenv/man.rst b/cdist/conf/type/__pyvenv/man.rst index f43454a7..977501e6 100644 --- a/cdist/conf/type/__pyvenv/man.rst +++ b/cdist/conf/type/__pyvenv/man.rst @@ -67,12 +67,6 @@ EXAMPLES __pyvenv /home/services/djangoenv --venvparams "--copies --system-site-packages" -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Darko Poljak diff --git a/cdist/conf/type/__qemu_img/man.rst b/cdist/conf/type/__qemu_img/man.rst index 3a137f4b..7cb4a758 100644 --- a/cdist/conf/type/__qemu_img/man.rst +++ b/cdist/conf/type/__qemu_img/man.rst @@ -37,10 +37,7 @@ EXAMPLES SEE ALSO -------- -qemu-img(1) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`qemu-img`\ (1) AUTHORS diff --git a/cdist/conf/type/__rbenv/man.rst b/cdist/conf/type/__rbenv/man.rst index fe965796..6341908a 100644 --- a/cdist/conf/type/__rbenv/man.rst +++ b/cdist/conf/type/__rbenv/man.rst @@ -36,12 +36,6 @@ EXAMPLES __rbenv /home/bastian --state absent -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Nico Schottelius diff --git a/cdist/conf/type/__rsync/man.rst b/cdist/conf/type/__rsync/man.rst index bac144c2..28e85ab2 100644 --- a/cdist/conf/type/__rsync/man.rst +++ b/cdist/conf/type/__rsync/man.rst @@ -98,10 +98,7 @@ EXAMPLES SEE ALSO -------- -rsync(1) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`rsync`\ (1) AUTHORS diff --git a/cdist/conf/type/__rvm/man.rst b/cdist/conf/type/__rvm/man.rst index bf84328c..412b651d 100644 --- a/cdist/conf/type/__rvm/man.rst +++ b/cdist/conf/type/__rvm/man.rst @@ -31,12 +31,8 @@ EXAMPLES SEE ALSO -------- -`cdist-type__rvm_gem(7) `_, -`cdist-type__rvm_gemset(7) `_, -`cdist-type__rvm_ruby(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__rvm_gem`\ (7), :manpage:`cdist-type__rvm_gemset`\ (7), +:manpage:`cdist-type__rvm_ruby`\ (7) AUTHORS diff --git a/cdist/conf/type/__rvm_gem/man.rst b/cdist/conf/type/__rvm_gem/man.rst index 5e65a712..a60fe843 100644 --- a/cdist/conf/type/__rvm_gem/man.rst +++ b/cdist/conf/type/__rvm_gem/man.rst @@ -43,12 +43,8 @@ EXAMPLES SEE ALSO -------- -`cdist-type__rvm(7) `_, -`cdist-type__rvm_gemset(7) `_, -`cdist-type__rvm_ruby(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__rvm`\ (7), :manpage:`cdist-type__rvm_gemset`\ (7), +:manpage:`cdist-type__rvm_ruby`\ (7) AUTHORS diff --git a/cdist/conf/type/__rvm_gemset/man.rst b/cdist/conf/type/__rvm_gemset/man.rst index 0d04ed94..4259ec92 100644 --- a/cdist/conf/type/__rvm_gemset/man.rst +++ b/cdist/conf/type/__rvm_gemset/man.rst @@ -41,12 +41,8 @@ EXAMPLES SEE ALSO -------- -`cdist-type__rvm(7) `_, -`cdist-type__rvm_gem(7) `_, -`cdist-type__rvm_ruby(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__rvm`\ (7), :manpage:`cdist-type__rvm_gem`\ (7), +:manpage:`cdist-type__rvm_ruby`\ (7) AUTHORS diff --git a/cdist/conf/type/__rvm_ruby/man.rst b/cdist/conf/type/__rvm_ruby/man.rst index d2bd4d08..18b6044b 100644 --- a/cdist/conf/type/__rvm_ruby/man.rst +++ b/cdist/conf/type/__rvm_ruby/man.rst @@ -42,12 +42,8 @@ EXAMPLES SEE ALSO -------- -`cdist-type__rvm(7) `_, -`cdist-type__rvm_gem(7) `_, -`cdist-type__rvm_gemset(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__rvm`\ (7), :manpage:`cdist-type__rvm_gem`\ (7), +:manpage:`cdist-type__rvm_gemset`\ (7) AUTHORS diff --git a/cdist/conf/type/__ssh_authorized_key/man.rst b/cdist/conf/type/__ssh_authorized_key/man.rst index a2f90574..3585717f 100644 --- a/cdist/conf/type/__ssh_authorized_key/man.rst +++ b/cdist/conf/type/__ssh_authorized_key/man.rst @@ -55,11 +55,8 @@ EXAMPLES SEE ALSO -------- -`cdist__ssh_authorized_keys(7) `_, -sshd(8) +:manpage:`cdist__ssh_authorized_keys`\ (7), :manpage:`sshd`\ (8) -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. AUTHORS ------- diff --git a/cdist/conf/type/__ssh_authorized_keys/man.rst b/cdist/conf/type/__ssh_authorized_keys/man.rst index cab844cc..6729660e 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.rst +++ b/cdist/conf/type/__ssh_authorized_keys/man.rst @@ -105,10 +105,7 @@ EXAMPLES SEE ALSO -------- -sshd(8) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`sshd`\ (8) AUTHORS diff --git a/cdist/conf/type/__ssh_dot_ssh/man.rst b/cdist/conf/type/__ssh_dot_ssh/man.rst index 6d449a4c..75adbde0 100644 --- a/cdist/conf/type/__ssh_dot_ssh/man.rst +++ b/cdist/conf/type/__ssh_dot_ssh/man.rst @@ -33,10 +33,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__ssh_authorized_keys(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__ssh_authorized_keys`\ (7) AUTHORS diff --git a/cdist/conf/type/__staged_file/man.rst b/cdist/conf/type/__staged_file/man.rst index 69ea3678..d11338af 100644 --- a/cdist/conf/type/__staged_file/man.rst +++ b/cdist/conf/type/__staged_file/man.rst @@ -99,10 +99,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__file(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__file`\ (7) AUTHORS diff --git a/cdist/conf/type/__start_on_boot/man.rst b/cdist/conf/type/__start_on_boot/man.rst index 7d009bf0..70c3e8d4 100644 --- a/cdist/conf/type/__start_on_boot/man.rst +++ b/cdist/conf/type/__start_on_boot/man.rst @@ -45,10 +45,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__process(7) `_ - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__process`\ (7) AUTHORS diff --git a/cdist/conf/type/__timezone/man.rst b/cdist/conf/type/__timezone/man.rst index 6e18c759..8a945c16 100644 --- a/cdist/conf/type/__timezone/man.rst +++ b/cdist/conf/type/__timezone/man.rst @@ -34,12 +34,6 @@ EXAMPLES __timezone US/Central -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Ramon Salvadó diff --git a/cdist/conf/type/__update_alternatives/man.rst b/cdist/conf/type/__update_alternatives/man.rst index bcedc1bf..c2b8bf6d 100644 --- a/cdist/conf/type/__update_alternatives/man.rst +++ b/cdist/conf/type/__update_alternatives/man.rst @@ -30,11 +30,7 @@ EXAMPLES SEE ALSO -------- -`cdist-type__debconf_set_selections(7) `_, -update-alternatives(8) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`cdist-type__debconf_set_selections`\ (7), :manpage:`update-alternatives`\ (8) AUTHORS diff --git a/cdist/conf/type/__user/man.rst b/cdist/conf/type/__user/man.rst index 0dd91ddd..1ad17b5b 100644 --- a/cdist/conf/type/__user/man.rst +++ b/cdist/conf/type/__user/man.rst @@ -84,10 +84,7 @@ EXAMPLES SEE ALSO -------- -pw(8), usermod(8) - -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. +:manpage:`pw`\ (8), :manpage:`usermod`\ (8) AUTHORS diff --git a/cdist/conf/type/__user_groups/man.rst b/cdist/conf/type/__user_groups/man.rst index 216a31c8..37fd25d7 100644 --- a/cdist/conf/type/__user_groups/man.rst +++ b/cdist/conf/type/__user_groups/man.rst @@ -39,12 +39,6 @@ EXAMPLES --group webuser2 --state absent -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__yum_repo/man.rst b/cdist/conf/type/__yum_repo/man.rst index b3866739..543a456d 100644 --- a/cdist/conf/type/__yum_repo/man.rst +++ b/cdist/conf/type/__yum_repo/man.rst @@ -111,12 +111,6 @@ EXAMPLES --gpgkey https://fedoraproject.org/static/0608B895.txt -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Steven Armstrong diff --git a/cdist/conf/type/__zypper_repo/man.rst b/cdist/conf/type/__zypper_repo/man.rst index bcf376de..9cc5e1c3 100644 --- a/cdist/conf/type/__zypper_repo/man.rst +++ b/cdist/conf/type/__zypper_repo/man.rst @@ -60,12 +60,6 @@ EXAMPLES __zypper_repo testrepo4 --state disabled --repo_id 4 -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Daniel Heule diff --git a/cdist/conf/type/__zypper_service/man.rst b/cdist/conf/type/__zypper_service/man.rst index f586742a..c596dea0 100644 --- a/cdist/conf/type/__zypper_service/man.rst +++ b/cdist/conf/type/__zypper_service/man.rst @@ -53,12 +53,6 @@ EXAMPLES __zypper_service INTERNAL_SLES11_SP3 --state absent --uri "http://path/to/your/ris/dir" -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>, -especially cdist type chapter: <:cdist_docs:`cdist-type`>. - - AUTHORS ------- Daniel Heule diff --git a/docs/man/Makefile b/docs/man/Makefile index 2bab13ce..bec5d97f 100644 --- a/docs/man/Makefile +++ b/docs/man/Makefile @@ -5,7 +5,9 @@ SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = -BUILDDIR = _build +BUILDDIR = ../dist +# for cache, etc. +_BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) @@ -15,7 +17,7 @@ endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +ALLSPHINXOPTS = -d $(_BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . @@ -52,6 +54,7 @@ help: .PHONY: clean clean: rm -rf $(BUILDDIR)/* + rm -rf $(_BUILDDIR)/* .PHONY: html html: diff --git a/docs/man/cdist-install.rst b/docs/man/cdist-install.rst index 7e8bba7a..f950a1ee 100644 --- a/docs/man/cdist-install.rst +++ b/docs/man/cdist-install.rst @@ -76,9 +76,9 @@ If you want to build and use the manpages, run: .. code-block:: sh make man - export MANPATH=$MANPATH:$(pwd -P)/docs/man/_build/man + export MANPATH=$MANPATH:$(pwd -P)/docs/dist/man -Or you can move manpages from docs/man/_build/man directory to some +Or you can move manpages from docs/dist/man directory to some other directory and add it to MANPATH. You can also build manpages for types in your ~/.cdist directory: @@ -87,12 +87,23 @@ You can also build manpages for types in your ~/.cdist directory: make dotman -Built manpages are now in docs/man/_build/man directory. If you have -some other custom .cdist directory, e.g. /custom/.cdist then use: +Built manpages are now in docs/dist/man directory. If you have +some other custom .cdist directory, e.g. /opt/cdist then use: .. code-block:: sh - DOT_CDIST_PATH=/custom/.cdist make dotman + DOT_CDIST_PATH=/opt/cdist make dotman + +Building and using HTML documentation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you want to build and use HTML documentation, run: + +.. code-block:: sh + + make html + +Now you can access docs/dist/html/index.html. Python package ~~~~~~~~~~~~~~ diff --git a/docs/man/conf.py b/docs/man/conf.py index 916b06a4..334cfd51 100644 --- a/docs/man/conf.py +++ b/docs/man/conf.py @@ -310,9 +310,3 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False - -extlinks = { - 'cdist_docs': - ('http://www.nico.schottelius.org/software/cdist/man/{}/%s.html'.format( - release), None), -} diff --git a/docs/man/man1/cdist.rst b/docs/man/man1/cdist.rst index 2a056482..efc1a201 100644 --- a/docs/man/man1/cdist.rst +++ b/docs/man/man1/cdist.rst @@ -175,10 +175,6 @@ The following exit values shall be returned: One or more host configurations failed -SEE ALSO --------- -Full documentation at: <:cdist_docs:`index`>. - AUTHORS ------- Nico Schottelius From 7d3c66859cd3fe8ac6d4e6a3ce4c5a110e22ea93 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 30 Jun 2016 12:18:42 +0200 Subject: [PATCH 0172/1332] Separate man pages by section number. --- docs/man/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/man/Makefile b/docs/man/Makefile index bec5d97f..800a80d8 100644 --- a/docs/man/Makefile +++ b/docs/man/Makefile @@ -165,6 +165,10 @@ text: .PHONY: man man: $(SPHINXBUILD) -b cman $(ALLSPHINXOPTS) $(BUILDDIR)/man + mkdir -p $(BUILDDIR)/man/man1 + mkdir -p $(BUILDDIR)/man/man7 + mv -f $(BUILDDIR)/man/*.1 $(BUILDDIR)/man/man1/ + mv -f $(BUILDDIR)/man/*.7 $(BUILDDIR)/man/man7/ @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." From b04ab0b630b9ed2ad9b8064242454cd89621210c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 30 Jun 2016 12:28:14 +0200 Subject: [PATCH 0173/1332] Fix Makefile for new sphinx build. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9f3535fd..9d494f23 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ man: mansphinxman mansphinxhtml # Manpages #5: release part MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) -MANBUILDDIR=$(MANDIR)/_build/html +MANBUILDDIR=docs/dist/html man-dist: man rm -rf "${MANWEBDIR}" @@ -212,7 +212,7 @@ release: # clean: - rm -f $(MAN7DSTDIR)/cdist-reference.rst + rm -f $(MANDIR)/cdist-reference.rst find "$(MANDIR)" -mindepth 2 -type l \ | xargs rm -f From 0d64d6a5b662b63dbe3d5491156699c1a1d2936a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 30 Jun 2016 15:05:26 +0200 Subject: [PATCH 0174/1332] docs/man -> docs/src and update Makefile and build-helper. --- .gitignore | 13 +++---- Makefile | 38 +++++++++---------- bin/build-helper | 4 +- bin/build-helper.freebsd | 4 +- docs/{man => src}/Makefile | 0 docs/{man => src}/cdist-best-practice.rst | 0 docs/{man => src}/cdist-bootstrap.rst | 0 docs/{man => src}/cdist-explorer.rst | 0 docs/{man => src}/cdist-features.rst | 0 docs/{man => src}/cdist-hacker.rst | 0 docs/{man => src}/cdist-install.rst | 0 docs/{man => src}/cdist-intro.rst | 0 docs/{man => src}/cdist-logo.png | Bin docs/{man => src}/cdist-manifest.rst | 0 docs/{man => src}/cdist-messaging.rst | 0 docs/{man => src}/cdist-os.rst | 0 docs/{man => src}/cdist-quickstart.rst | 0 docs/{man => src}/cdist-reference.rst.sh | 0 docs/{man => src}/cdist-remote-exec-copy.rst | 0 docs/{man => src}/cdist-stages.rst | 0 docs/{man => src}/cdist-support.rst | 0 docs/{man => src}/cdist-troubleshooting.rst | 0 docs/{man => src}/cdist-type.rst | 0 docs/{man => src}/cdist-types.rst | 0 docs/{man => src}/cdist-update.rst | 0 docs/{man => src}/cdist-why.rst | 0 docs/{man => src}/conf.py | 0 docs/{man => src}/index.rst | 0 docs/{man => src}/man1/cdist.rst | 0 docs/{man => src}/man7/.gitignore | 0 30 files changed, 28 insertions(+), 31 deletions(-) rename docs/{man => src}/Makefile (100%) rename docs/{man => src}/cdist-best-practice.rst (100%) rename docs/{man => src}/cdist-bootstrap.rst (100%) rename docs/{man => src}/cdist-explorer.rst (100%) rename docs/{man => src}/cdist-features.rst (100%) rename docs/{man => src}/cdist-hacker.rst (100%) rename docs/{man => src}/cdist-install.rst (100%) rename docs/{man => src}/cdist-intro.rst (100%) rename docs/{man => src}/cdist-logo.png (100%) rename docs/{man => src}/cdist-manifest.rst (100%) rename docs/{man => src}/cdist-messaging.rst (100%) rename docs/{man => src}/cdist-os.rst (100%) rename docs/{man => src}/cdist-quickstart.rst (100%) rename docs/{man => src}/cdist-reference.rst.sh (100%) rename docs/{man => src}/cdist-remote-exec-copy.rst (100%) rename docs/{man => src}/cdist-stages.rst (100%) rename docs/{man => src}/cdist-support.rst (100%) rename docs/{man => src}/cdist-troubleshooting.rst (100%) rename docs/{man => src}/cdist-type.rst (100%) rename docs/{man => src}/cdist-types.rst (100%) rename docs/{man => src}/cdist-update.rst (100%) rename docs/{man => src}/cdist-why.rst (100%) rename docs/{man => src}/conf.py (100%) rename docs/{man => src}/index.rst (100%) rename docs/{man => src}/man1/cdist.rst (100%) rename docs/{man => src}/man7/.gitignore (100%) diff --git a/.gitignore b/.gitignore index 3bbc4e99..74014aba 100644 --- a/.gitignore +++ b/.gitignore @@ -2,14 +2,11 @@ .*.swp # Ignore generated manpages -docs/man/.marker -docs/man/man1/*.1 -docs/man/man7/*.7 -docs/man/man*/*.html -docs/man/man*/*.xml -docs/man/man*/docbook-xsl.css -docs/man/man7/cdist-type__*.rst -docs/man/cdist-reference.rst +docs/src/.marker +docs/src/man1/*.1 +docs/src/man7/*.7 +docs/src/man7/cdist-type__*.rst +docs/src/cdist-reference.rst # Ignore cdist cache for version control /cache/ diff --git a/Makefile b/Makefile index 9d494f23..7885cf24 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ helper=./bin/build-helper -MANDIR=docs/man +DOCS_SRC_DIR=docs/src SPEECHDIR=docs/speeches TYPEDIR=cdist/conf/type @@ -36,13 +36,13 @@ CHANGELOG_FILE=docs/changelog PYTHON_VERSION=cdist/version.py -SPHINXM=make -C $(MANDIR) man -SPHINXH=make -C $(MANDIR) html +SPHINXM=make -C $(DOCS_SRC_DIR) man +SPHINXH=make -C $(DOCS_SRC_DIR) html ################################################################################ # Manpages # -MAN1DSTDIR=$(MANDIR)/man1 -MAN7DSTDIR=$(MANDIR)/man7 +MAN1DSTDIR=$(DOCS_SRC_DIR)/man1 +MAN7DSTDIR=$(DOCS_SRC_DIR)/man7 # Manpages #1: Types # Use shell / ls to get complete list - $(TYPEDIR)/*/man.rst does not work @@ -56,26 +56,26 @@ $(MAN7DSTDIR)/cdist-type%.rst: $(TYPEDIR)/%/man.rst ln -sf "../../../$^" $@ # Manpages #2: reference -MANREF=$(MAN7DSTDIR)/cdist-reference.rst -MANREFSH=$(MANDIR)/cdist-reference.rst.sh +DOCSREF=$(MAN7DSTDIR)/cdist-reference.rst +DOCSREFSH=$(DOCS_SRC_DIR)/cdist-reference.rst.sh -$(MANREF): $(MANREFSH) - $(MANREFSH) +$(DOCSREF): $(DOCSREFSH) + $(DOCSREFSH) # Manpages #3: generic part -mansphinxman: $(MANTYPES) $(MANREF) $(PYTHON_VERSION) +sphinxman: $(MANTYPES) $(DOCSREF) $(PYTHON_VERSION) $(SPHINXM) -mansphinxhtml: $(MANTYPES) $(MANREF) $(PYTHON_VERSION) +sphinxhtml: $(MANTYPES) $(DOCSREF) $(PYTHON_VERSION) $(SPHINXH) -man: mansphinxman mansphinxhtml +docs: sphinxman sphinxhtml # Manpages #5: release part MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) MANBUILDDIR=docs/dist/html -man-dist: man +docs-dist: man rm -rf "${MANWEBDIR}" mkdir -p "${MANWEBDIR}" # mkdir -p "${MANWEBDIR}/man1" "${MANWEBDIR}/man7" @@ -102,10 +102,10 @@ $(DOTMAN7DSTDIR)/cdist-type%.rst: $(DOTTYPEDIR)/%/man.rst ln -sf "$^" $@ # Manpages #3: generic part -dotmansphinxman: $(DOTMANTYPES) +dotsphinxman: $(DOTMANTYPES) $(SPHINXM) -dotman: dotmansphinxman +dotman: dotsphinxman ################################################################################ @@ -147,7 +147,7 @@ web-doc: web-dist: web-blog web-doc -web-pub: web-dist man-dist speeches-dist +web-pub: web-dist docs-dist speeches-dist cd "${WEBDIR}" && make pub web-release-all: man-latest-link @@ -212,12 +212,12 @@ release: # clean: - rm -f $(MANDIR)/cdist-reference.rst + rm -f $(DOCS_SRC_DIR)/cdist-reference.rst - find "$(MANDIR)" -mindepth 2 -type l \ + find "$(DOCS_SRC_DIR)" -mindepth 2 -type l \ | xargs rm -f - make -C $(MANDIR) clean + make -C $(DOCS_SRC_DIR) clean find * -name __pycache__ | xargs rm -rf diff --git a/bin/build-helper b/bin/build-helper index 31789a2e..8f228697 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -206,8 +206,8 @@ eof "$0" check-date "$0" check-unittest - # Generate man pages (indirect check if they build) - make man + # Generate documentation (man and html) + make docs # Generate speeches (indirect check if they build) make speeches diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 01d86a10..02e71586 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -241,8 +241,8 @@ eof "$0" check-date "$0" check-unittest - # Generate man pages (indirect check if they build) - make helper=${helper} WEBDIR=${WEBDIR} man + # Generate documentation (man and html) + make helper=${helper} WEBDIR=${WEBDIR} docs # Generate speeches (indirect check if they build) make helper=${helper} WEBDIR=${WEBDIR} speeches diff --git a/docs/man/Makefile b/docs/src/Makefile similarity index 100% rename from docs/man/Makefile rename to docs/src/Makefile diff --git a/docs/man/cdist-best-practice.rst b/docs/src/cdist-best-practice.rst similarity index 100% rename from docs/man/cdist-best-practice.rst rename to docs/src/cdist-best-practice.rst diff --git a/docs/man/cdist-bootstrap.rst b/docs/src/cdist-bootstrap.rst similarity index 100% rename from docs/man/cdist-bootstrap.rst rename to docs/src/cdist-bootstrap.rst diff --git a/docs/man/cdist-explorer.rst b/docs/src/cdist-explorer.rst similarity index 100% rename from docs/man/cdist-explorer.rst rename to docs/src/cdist-explorer.rst diff --git a/docs/man/cdist-features.rst b/docs/src/cdist-features.rst similarity index 100% rename from docs/man/cdist-features.rst rename to docs/src/cdist-features.rst diff --git a/docs/man/cdist-hacker.rst b/docs/src/cdist-hacker.rst similarity index 100% rename from docs/man/cdist-hacker.rst rename to docs/src/cdist-hacker.rst diff --git a/docs/man/cdist-install.rst b/docs/src/cdist-install.rst similarity index 100% rename from docs/man/cdist-install.rst rename to docs/src/cdist-install.rst diff --git a/docs/man/cdist-intro.rst b/docs/src/cdist-intro.rst similarity index 100% rename from docs/man/cdist-intro.rst rename to docs/src/cdist-intro.rst diff --git a/docs/man/cdist-logo.png b/docs/src/cdist-logo.png similarity index 100% rename from docs/man/cdist-logo.png rename to docs/src/cdist-logo.png diff --git a/docs/man/cdist-manifest.rst b/docs/src/cdist-manifest.rst similarity index 100% rename from docs/man/cdist-manifest.rst rename to docs/src/cdist-manifest.rst diff --git a/docs/man/cdist-messaging.rst b/docs/src/cdist-messaging.rst similarity index 100% rename from docs/man/cdist-messaging.rst rename to docs/src/cdist-messaging.rst diff --git a/docs/man/cdist-os.rst b/docs/src/cdist-os.rst similarity index 100% rename from docs/man/cdist-os.rst rename to docs/src/cdist-os.rst diff --git a/docs/man/cdist-quickstart.rst b/docs/src/cdist-quickstart.rst similarity index 100% rename from docs/man/cdist-quickstart.rst rename to docs/src/cdist-quickstart.rst diff --git a/docs/man/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh similarity index 100% rename from docs/man/cdist-reference.rst.sh rename to docs/src/cdist-reference.rst.sh diff --git a/docs/man/cdist-remote-exec-copy.rst b/docs/src/cdist-remote-exec-copy.rst similarity index 100% rename from docs/man/cdist-remote-exec-copy.rst rename to docs/src/cdist-remote-exec-copy.rst diff --git a/docs/man/cdist-stages.rst b/docs/src/cdist-stages.rst similarity index 100% rename from docs/man/cdist-stages.rst rename to docs/src/cdist-stages.rst diff --git a/docs/man/cdist-support.rst b/docs/src/cdist-support.rst similarity index 100% rename from docs/man/cdist-support.rst rename to docs/src/cdist-support.rst diff --git a/docs/man/cdist-troubleshooting.rst b/docs/src/cdist-troubleshooting.rst similarity index 100% rename from docs/man/cdist-troubleshooting.rst rename to docs/src/cdist-troubleshooting.rst diff --git a/docs/man/cdist-type.rst b/docs/src/cdist-type.rst similarity index 100% rename from docs/man/cdist-type.rst rename to docs/src/cdist-type.rst diff --git a/docs/man/cdist-types.rst b/docs/src/cdist-types.rst similarity index 100% rename from docs/man/cdist-types.rst rename to docs/src/cdist-types.rst diff --git a/docs/man/cdist-update.rst b/docs/src/cdist-update.rst similarity index 100% rename from docs/man/cdist-update.rst rename to docs/src/cdist-update.rst diff --git a/docs/man/cdist-why.rst b/docs/src/cdist-why.rst similarity index 100% rename from docs/man/cdist-why.rst rename to docs/src/cdist-why.rst diff --git a/docs/man/conf.py b/docs/src/conf.py similarity index 100% rename from docs/man/conf.py rename to docs/src/conf.py diff --git a/docs/man/index.rst b/docs/src/index.rst similarity index 100% rename from docs/man/index.rst rename to docs/src/index.rst diff --git a/docs/man/man1/cdist.rst b/docs/src/man1/cdist.rst similarity index 100% rename from docs/man/man1/cdist.rst rename to docs/src/man1/cdist.rst diff --git a/docs/man/man7/.gitignore b/docs/src/man7/.gitignore similarity index 100% rename from docs/man/man7/.gitignore rename to docs/src/man7/.gitignore From 0dfb4aee73aa353ae71606828eeaa7563a0b2421 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 30 Jun 2016 15:12:32 +0200 Subject: [PATCH 0175/1332] sphinx> ':manpage:' -> ':strong:' --- cdist/conf/type/__ccollect_source/man.rst | 2 +- cdist/conf/type/__config_file/man.rst | 2 +- cdist/conf/type/__consul_check/man.rst | 2 +- cdist/conf/type/__consul_service/man.rst | 2 +- cdist/conf/type/__consul_template_template/man.rst | 2 +- cdist/conf/type/__consul_watch_checks/man.rst | 2 +- cdist/conf/type/__consul_watch_event/man.rst | 2 +- cdist/conf/type/__consul_watch_key/man.rst | 2 +- cdist/conf/type/__consul_watch_keyprefix/man.rst | 2 +- cdist/conf/type/__consul_watch_nodes/man.rst | 2 +- cdist/conf/type/__consul_watch_service/man.rst | 2 +- cdist/conf/type/__consul_watch_services/man.rst | 2 +- cdist/conf/type/__cron/man.rst | 2 +- cdist/conf/type/__debconf_set_selections/man.rst | 2 +- cdist/conf/type/__dog_vdi/man.rst | 2 +- cdist/conf/type/__firewalld_rule/man.rst | 2 +- cdist/conf/type/__iptables_apply/man.rst | 2 +- cdist/conf/type/__iptables_rule/man.rst | 2 +- cdist/conf/type/__jail/man.rst | 2 +- cdist/conf/type/__jail_freebsd10/man.rst | 2 +- cdist/conf/type/__jail_freebsd9/man.rst | 2 +- cdist/conf/type/__line/man.rst | 2 +- cdist/conf/type/__locale/man.rst | 2 +- cdist/conf/type/__package_apt/man.rst | 2 +- cdist/conf/type/__package_emerge/man.rst | 2 +- cdist/conf/type/__package_emerge_dependencies/man.rst | 2 +- cdist/conf/type/__package_luarocks/man.rst | 2 +- cdist/conf/type/__package_opkg/man.rst | 2 +- cdist/conf/type/__package_pacman/man.rst | 2 +- cdist/conf/type/__package_pip/man.rst | 2 +- cdist/conf/type/__package_pkg_freebsd/man.rst | 2 +- cdist/conf/type/__package_pkg_openbsd/man.rst | 2 +- cdist/conf/type/__package_pkgng_freebsd/man.rst | 2 +- cdist/conf/type/__package_rubygem/man.rst | 2 +- cdist/conf/type/__package_yum/man.rst | 2 +- cdist/conf/type/__package_zypper/man.rst | 2 +- cdist/conf/type/__pacman_conf/man.rst | 2 +- cdist/conf/type/__pacman_conf_integrate/man.rst | 2 +- cdist/conf/type/__pf_apply/man.rst | 2 +- cdist/conf/type/__pf_ruleset/man.rst | 2 +- cdist/conf/type/__postfix_master/man.rst | 2 +- cdist/conf/type/__postfix_postconf/man.rst | 2 +- cdist/conf/type/__postgres_database/man.rst | 2 +- cdist/conf/type/__postgres_role/man.rst | 2 +- cdist/conf/type/__process/man.rst | 2 +- cdist/conf/type/__qemu_img/man.rst | 2 +- cdist/conf/type/__rsync/man.rst | 2 +- cdist/conf/type/__rvm/man.rst | 4 ++-- cdist/conf/type/__rvm_gem/man.rst | 4 ++-- cdist/conf/type/__rvm_gemset/man.rst | 4 ++-- cdist/conf/type/__rvm_ruby/man.rst | 4 ++-- cdist/conf/type/__ssh_authorized_key/man.rst | 2 +- cdist/conf/type/__ssh_authorized_keys/man.rst | 2 +- cdist/conf/type/__ssh_dot_ssh/man.rst | 2 +- cdist/conf/type/__staged_file/man.rst | 2 +- cdist/conf/type/__start_on_boot/man.rst | 2 +- cdist/conf/type/__update_alternatives/man.rst | 2 +- cdist/conf/type/__user/man.rst | 2 +- 58 files changed, 62 insertions(+), 62 deletions(-) diff --git a/cdist/conf/type/__ccollect_source/man.rst b/cdist/conf/type/__ccollect_source/man.rst index cdacd31c..a6723fa8 100644 --- a/cdist/conf/type/__ccollect_source/man.rst +++ b/cdist/conf/type/__ccollect_source/man.rst @@ -53,7 +53,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`ccollect`\ (1) +:strong:`ccollect`\ (1) AUTHORS diff --git a/cdist/conf/type/__config_file/man.rst b/cdist/conf/type/__config_file/man.rst index b9d58979..414a970b 100644 --- a/cdist/conf/type/__config_file/man.rst +++ b/cdist/conf/type/__config_file/man.rst @@ -48,7 +48,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__file`\ (7) +:strong:`cdist-type__file`\ (7) AUTHORS diff --git a/cdist/conf/type/__consul_check/man.rst b/cdist/conf/type/__consul_check/man.rst index c0d0b459..e371f861 100644 --- a/cdist/conf/type/__consul_check/man.rst +++ b/cdist/conf/type/__consul_check/man.rst @@ -62,7 +62,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_agent`\ (7) +:strong:`cdist-type__consul_agent`\ (7) AUTHORS diff --git a/cdist/conf/type/__consul_service/man.rst b/cdist/conf/type/__consul_service/man.rst index 75b06aa0..0c815402 100644 --- a/cdist/conf/type/__consul_service/man.rst +++ b/cdist/conf/type/__consul_service/man.rst @@ -66,7 +66,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_agent`\ (7) +:strong:`cdist-type__consul_agent`\ (7) AUTHORS diff --git a/cdist/conf/type/__consul_template_template/man.rst b/cdist/conf/type/__consul_template_template/man.rst index b54f759e..c1da282e 100644 --- a/cdist/conf/type/__consul_template_template/man.rst +++ b/cdist/conf/type/__consul_template_template/man.rst @@ -59,7 +59,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_template`\ (7), :manpage:`cdist-type__consul_template_config`\ (7) +:strong:`cdist-type__consul_template`\ (7), :strong:`cdist-type__consul_template_config`\ (7) AUTHORS diff --git a/cdist/conf/type/__consul_watch_checks/man.rst b/cdist/conf/type/__consul_watch_checks/man.rst index ec04b0b3..35c8c9ca 100644 --- a/cdist/conf/type/__consul_watch_checks/man.rst +++ b/cdist/conf/type/__consul_watch_checks/man.rst @@ -55,7 +55,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_agent`\ (7) +:strong:`cdist-type__consul_agent`\ (7) consul documentation at: . diff --git a/cdist/conf/type/__consul_watch_event/man.rst b/cdist/conf/type/__consul_watch_event/man.rst index 664a19a2..03c2f07e 100644 --- a/cdist/conf/type/__consul_watch_event/man.rst +++ b/cdist/conf/type/__consul_watch_event/man.rst @@ -48,7 +48,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_agent`\ (7) +:strong:`cdist-type__consul_agent`\ (7) consul documentation at: . diff --git a/cdist/conf/type/__consul_watch_key/man.rst b/cdist/conf/type/__consul_watch_key/man.rst index 0f90245c..efa6cb41 100644 --- a/cdist/conf/type/__consul_watch_key/man.rst +++ b/cdist/conf/type/__consul_watch_key/man.rst @@ -45,7 +45,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_agent`\ (7) +:strong:`cdist-type__consul_agent`\ (7) consul documentation at: . diff --git a/cdist/conf/type/__consul_watch_keyprefix/man.rst b/cdist/conf/type/__consul_watch_keyprefix/man.rst index 65fa16af..d884eb79 100644 --- a/cdist/conf/type/__consul_watch_keyprefix/man.rst +++ b/cdist/conf/type/__consul_watch_keyprefix/man.rst @@ -45,7 +45,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_agent`\ (7) +:strong:`cdist-type__consul_agent`\ (7) consul documentation at: . diff --git a/cdist/conf/type/__consul_watch_nodes/man.rst b/cdist/conf/type/__consul_watch_nodes/man.rst index 5a5bdbd2..52974c3c 100644 --- a/cdist/conf/type/__consul_watch_nodes/man.rst +++ b/cdist/conf/type/__consul_watch_nodes/man.rst @@ -41,7 +41,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_agent`\ (7) +:strong:`cdist-type__consul_agent`\ (7) consul documentation at: . diff --git a/cdist/conf/type/__consul_watch_service/man.rst b/cdist/conf/type/__consul_watch_service/man.rst index 38ee501a..f22ee568 100644 --- a/cdist/conf/type/__consul_watch_service/man.rst +++ b/cdist/conf/type/__consul_watch_service/man.rst @@ -65,7 +65,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_agent`\ (7) +:strong:`cdist-type__consul_agent`\ (7) consul documentation at: . diff --git a/cdist/conf/type/__consul_watch_services/man.rst b/cdist/conf/type/__consul_watch_services/man.rst index 41b115ae..c53caa04 100644 --- a/cdist/conf/type/__consul_watch_services/man.rst +++ b/cdist/conf/type/__consul_watch_services/man.rst @@ -41,7 +41,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__consul_agent`\ (7) +:strong:`cdist-type__consul_agent`\ (7) consul documentation at: . diff --git a/cdist/conf/type/__cron/man.rst b/cdist/conf/type/__cron/man.rst index 4b9cb83d..59f59e14 100644 --- a/cdist/conf/type/__cron/man.rst +++ b/cdist/conf/type/__cron/man.rst @@ -68,7 +68,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`crontab`\ (5) +:strong:`crontab`\ (5) AUTHORS diff --git a/cdist/conf/type/__debconf_set_selections/man.rst b/cdist/conf/type/__debconf_set_selections/man.rst index b7e5f901..3f7f05ae 100644 --- a/cdist/conf/type/__debconf_set_selections/man.rst +++ b/cdist/conf/type/__debconf_set_selections/man.rst @@ -37,7 +37,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`debconf-set-selections`\ (1), :manpage:`cdist-type__update_alternatives`\ (7) +:strong:`debconf-set-selections`\ (1), :strong:`cdist-type__update_alternatives`\ (7) AUTHORS diff --git a/cdist/conf/type/__dog_vdi/man.rst b/cdist/conf/type/__dog_vdi/man.rst index 65bea479..2d6f15b8 100644 --- a/cdist/conf/type/__dog_vdi/man.rst +++ b/cdist/conf/type/__dog_vdi/man.rst @@ -43,7 +43,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`qemu`\ (1), :manpage:`dog`\ (8) +:strong:`qemu`\ (1), :strong:`dog`\ (8) AUTHORS diff --git a/cdist/conf/type/__firewalld_rule/man.rst b/cdist/conf/type/__firewalld_rule/man.rst index 414eb7e9..5e8e25a7 100644 --- a/cdist/conf/type/__firewalld_rule/man.rst +++ b/cdist/conf/type/__firewalld_rule/man.rst @@ -65,7 +65,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__iptables_rule`\ (7), :manpage:`firewalld`\ (8) +:strong:`cdist-type__iptables_rule`\ (7), :strong:`firewalld`\ (8) AUTHORS diff --git a/cdist/conf/type/__iptables_apply/man.rst b/cdist/conf/type/__iptables_apply/man.rst index 48697f9c..6f9ab923 100644 --- a/cdist/conf/type/__iptables_apply/man.rst +++ b/cdist/conf/type/__iptables_apply/man.rst @@ -29,7 +29,7 @@ None (__iptables_apply is used by __iptables_rule) SEE ALSO -------- -:manpage:`cdist-type__iptables_rule`\ (7), :manpage:`iptables`\ (8) +:strong:`cdist-type__iptables_rule`\ (7), :strong:`iptables`\ (8) AUTHORS diff --git a/cdist/conf/type/__iptables_rule/man.rst b/cdist/conf/type/__iptables_rule/man.rst index fab6c47a..5256c711 100644 --- a/cdist/conf/type/__iptables_rule/man.rst +++ b/cdist/conf/type/__iptables_rule/man.rst @@ -50,7 +50,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__iptables_apply`\ (7), :manpage:`iptables`\ (8) +:strong:`cdist-type__iptables_apply`\ (7), :strong:`iptables`\ (8) AUTHORS diff --git a/cdist/conf/type/__jail/man.rst b/cdist/conf/type/__jail/man.rst index 756e7660..bd9826e4 100644 --- a/cdist/conf/type/__jail/man.rst +++ b/cdist/conf/type/__jail/man.rst @@ -108,7 +108,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`jail`\ (8) +:strong:`jail`\ (8) AUTHORS diff --git a/cdist/conf/type/__jail_freebsd10/man.rst b/cdist/conf/type/__jail_freebsd10/man.rst index 34dc2198..9efd7c2a 100644 --- a/cdist/conf/type/__jail_freebsd10/man.rst +++ b/cdist/conf/type/__jail_freebsd10/man.rst @@ -107,7 +107,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`jail`\ (8) +:strong:`jail`\ (8) AUTHORS diff --git a/cdist/conf/type/__jail_freebsd9/man.rst b/cdist/conf/type/__jail_freebsd9/man.rst index ca526cd0..fe32010d 100644 --- a/cdist/conf/type/__jail_freebsd9/man.rst +++ b/cdist/conf/type/__jail_freebsd9/man.rst @@ -108,7 +108,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`jail`\ (8) +:strong:`jail`\ (8) AUTHORS diff --git a/cdist/conf/type/__line/man.rst b/cdist/conf/type/__line/man.rst index 1f38a974..11840bac 100644 --- a/cdist/conf/type/__line/man.rst +++ b/cdist/conf/type/__line/man.rst @@ -61,7 +61,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`grep`\ (1) +:strong:`grep`\ (1) AUTHORS diff --git a/cdist/conf/type/__locale/man.rst b/cdist/conf/type/__locale/man.rst index 51ed38df..e46d14bd 100644 --- a/cdist/conf/type/__locale/man.rst +++ b/cdist/conf/type/__locale/man.rst @@ -34,7 +34,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`locale`\ (1), :manpage:`localedef`\ (1) +:strong:`locale`\ (1), :strong:`localedef`\ (1) AUTHORS diff --git a/cdist/conf/type/__package_apt/man.rst b/cdist/conf/type/__package_apt/man.rst index a841fc5b..45818636 100644 --- a/cdist/conf/type/__package_apt/man.rst +++ b/cdist/conf/type/__package_apt/man.rst @@ -46,7 +46,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_emerge/man.rst b/cdist/conf/type/__package_emerge/man.rst index ceb0f169..839b647e 100644 --- a/cdist/conf/type/__package_emerge/man.rst +++ b/cdist/conf/type/__package_emerge/man.rst @@ -47,7 +47,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7), :manpage:`cdist-type__package_emerge_dependencies`\ (7) +:strong:`cdist-type__package`\ (7), :strong:`cdist-type__package_emerge_dependencies`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_emerge_dependencies/man.rst b/cdist/conf/type/__package_emerge_dependencies/man.rst index 1a227853..11531b34 100644 --- a/cdist/conf/type/__package_emerge_dependencies/man.rst +++ b/cdist/conf/type/__package_emerge_dependencies/man.rst @@ -36,7 +36,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7), :manpage:`cdist-type__package_emerge`\ (7) +:strong:`cdist-type__package`\ (7), :strong:`cdist-type__package_emerge`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_luarocks/man.rst b/cdist/conf/type/__package_luarocks/man.rst index 399b07af..fd831aa5 100644 --- a/cdist/conf/type/__package_luarocks/man.rst +++ b/cdist/conf/type/__package_luarocks/man.rst @@ -39,7 +39,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_opkg/man.rst b/cdist/conf/type/__package_opkg/man.rst index 203b8a36..d7858ba2 100644 --- a/cdist/conf/type/__package_opkg/man.rst +++ b/cdist/conf/type/__package_opkg/man.rst @@ -39,7 +39,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pacman/man.rst b/cdist/conf/type/__package_pacman/man.rst index 44f36255..7b9bd1b4 100644 --- a/cdist/conf/type/__package_pacman/man.rst +++ b/cdist/conf/type/__package_pacman/man.rst @@ -42,7 +42,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pip/man.rst b/cdist/conf/type/__package_pip/man.rst index f1ba98d9..85d6d42b 100644 --- a/cdist/conf/type/__package_pip/man.rst +++ b/cdist/conf/type/__package_pip/man.rst @@ -49,7 +49,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pkg_freebsd/man.rst b/cdist/conf/type/__package_pkg_freebsd/man.rst index a2633bcb..4b210356 100644 --- a/cdist/conf/type/__package_pkg_freebsd/man.rst +++ b/cdist/conf/type/__package_pkg_freebsd/man.rst @@ -54,7 +54,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pkg_openbsd/man.rst b/cdist/conf/type/__package_pkg_openbsd/man.rst index e776956c..0814029f 100644 --- a/cdist/conf/type/__package_pkg_openbsd/man.rst +++ b/cdist/conf/type/__package_pkg_openbsd/man.rst @@ -54,7 +54,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_pkgng_freebsd/man.rst b/cdist/conf/type/__package_pkgng_freebsd/man.rst index 9fdd7c76..bdc268af 100644 --- a/cdist/conf/type/__package_pkgng_freebsd/man.rst +++ b/cdist/conf/type/__package_pkgng_freebsd/man.rst @@ -85,7 +85,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_rubygem/man.rst b/cdist/conf/type/__package_rubygem/man.rst index eb76a036..5bec9d2d 100644 --- a/cdist/conf/type/__package_rubygem/man.rst +++ b/cdist/conf/type/__package_rubygem/man.rst @@ -39,7 +39,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_yum/man.rst b/cdist/conf/type/__package_yum/man.rst index 544afbf2..581d3539 100644 --- a/cdist/conf/type/__package_yum/man.rst +++ b/cdist/conf/type/__package_yum/man.rst @@ -49,7 +49,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__package_zypper/man.rst b/cdist/conf/type/__package_zypper/man.rst index da8d1d81..cb9cb518 100644 --- a/cdist/conf/type/__package_zypper/man.rst +++ b/cdist/conf/type/__package_zypper/man.rst @@ -56,7 +56,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS diff --git a/cdist/conf/type/__pacman_conf/man.rst b/cdist/conf/type/__pacman_conf/man.rst index a61f2498..931f8812 100644 --- a/cdist/conf/type/__pacman_conf/man.rst +++ b/cdist/conf/type/__pacman_conf/man.rst @@ -59,7 +59,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`grep`\ (1) +:strong:`grep`\ (1) AUTHORS diff --git a/cdist/conf/type/__pacman_conf_integrate/man.rst b/cdist/conf/type/__pacman_conf_integrate/man.rst index 77d5c1c3..f36dca45 100644 --- a/cdist/conf/type/__pacman_conf_integrate/man.rst +++ b/cdist/conf/type/__pacman_conf_integrate/man.rst @@ -35,7 +35,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`grep`\ (1) +:strong:`grep`\ (1) AUTHORS diff --git a/cdist/conf/type/__pf_apply/man.rst b/cdist/conf/type/__pf_apply/man.rst index 2c7fd4fb..1b7f4e3b 100644 --- a/cdist/conf/type/__pf_apply/man.rst +++ b/cdist/conf/type/__pf_apply/man.rst @@ -39,7 +39,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`pf`\ (4), :manpage:`cdist-type__pf_ruleset`\ (7) +:strong:`pf`\ (4), :strong:`cdist-type__pf_ruleset`\ (7) AUTHORS diff --git a/cdist/conf/type/__pf_ruleset/man.rst b/cdist/conf/type/__pf_ruleset/man.rst index eb97e086..756a9e30 100644 --- a/cdist/conf/type/__pf_ruleset/man.rst +++ b/cdist/conf/type/__pf_ruleset/man.rst @@ -39,7 +39,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`pf`\ (4) +:strong:`pf`\ (4) AUTHORS diff --git a/cdist/conf/type/__postfix_master/man.rst b/cdist/conf/type/__postfix_master/man.rst index 27078070..b6e6fc94 100644 --- a/cdist/conf/type/__postfix_master/man.rst +++ b/cdist/conf/type/__postfix_master/man.rst @@ -68,7 +68,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`master`\ (5) +:strong:`master`\ (5) AUTHORS diff --git a/cdist/conf/type/__postfix_postconf/man.rst b/cdist/conf/type/__postfix_postconf/man.rst index 5773fcaf..5c2c2a0e 100644 --- a/cdist/conf/type/__postfix_postconf/man.rst +++ b/cdist/conf/type/__postfix_postconf/man.rst @@ -38,7 +38,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`postconf`\ (5) +:strong:`postconf`\ (5) AUTHORS diff --git a/cdist/conf/type/__postgres_database/man.rst b/cdist/conf/type/__postgres_database/man.rst index 69e1a67f..517c12a3 100644 --- a/cdist/conf/type/__postgres_database/man.rst +++ b/cdist/conf/type/__postgres_database/man.rst @@ -30,7 +30,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__postgres_role`\ (7) +:strong:`cdist-type__postgres_role`\ (7) AUTHORS diff --git a/cdist/conf/type/__postgres_role/man.rst b/cdist/conf/type/__postgres_role/man.rst index f9293be5..a2a0268a 100644 --- a/cdist/conf/type/__postgres_role/man.rst +++ b/cdist/conf/type/__postgres_role/man.rst @@ -48,7 +48,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__postgres_database`\ (7) +:strong:`cdist-type__postgres_database`\ (7) postgresql documentation at: . diff --git a/cdist/conf/type/__process/man.rst b/cdist/conf/type/__process/man.rst index 19f68ddc..0e4690b1 100644 --- a/cdist/conf/type/__process/man.rst +++ b/cdist/conf/type/__process/man.rst @@ -58,7 +58,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__start_on_boot`\ (7) +:strong:`cdist-type__start_on_boot`\ (7) AUTHORS diff --git a/cdist/conf/type/__qemu_img/man.rst b/cdist/conf/type/__qemu_img/man.rst index 7cb4a758..663e9162 100644 --- a/cdist/conf/type/__qemu_img/man.rst +++ b/cdist/conf/type/__qemu_img/man.rst @@ -37,7 +37,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`qemu-img`\ (1) +:strong:`qemu-img`\ (1) AUTHORS diff --git a/cdist/conf/type/__rsync/man.rst b/cdist/conf/type/__rsync/man.rst index 28e85ab2..295feceb 100644 --- a/cdist/conf/type/__rsync/man.rst +++ b/cdist/conf/type/__rsync/man.rst @@ -98,7 +98,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`rsync`\ (1) +:strong:`rsync`\ (1) AUTHORS diff --git a/cdist/conf/type/__rvm/man.rst b/cdist/conf/type/__rvm/man.rst index 412b651d..3a914304 100644 --- a/cdist/conf/type/__rvm/man.rst +++ b/cdist/conf/type/__rvm/man.rst @@ -31,8 +31,8 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__rvm_gem`\ (7), :manpage:`cdist-type__rvm_gemset`\ (7), -:manpage:`cdist-type__rvm_ruby`\ (7) +:strong:`cdist-type__rvm_gem`\ (7), :strong:`cdist-type__rvm_gemset`\ (7), +:strong:`cdist-type__rvm_ruby`\ (7) AUTHORS diff --git a/cdist/conf/type/__rvm_gem/man.rst b/cdist/conf/type/__rvm_gem/man.rst index a60fe843..5f3fba97 100644 --- a/cdist/conf/type/__rvm_gem/man.rst +++ b/cdist/conf/type/__rvm_gem/man.rst @@ -43,8 +43,8 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__rvm`\ (7), :manpage:`cdist-type__rvm_gemset`\ (7), -:manpage:`cdist-type__rvm_ruby`\ (7) +:strong:`cdist-type__rvm`\ (7), :strong:`cdist-type__rvm_gemset`\ (7), +:strong:`cdist-type__rvm_ruby`\ (7) AUTHORS diff --git a/cdist/conf/type/__rvm_gemset/man.rst b/cdist/conf/type/__rvm_gemset/man.rst index 4259ec92..fca4c36a 100644 --- a/cdist/conf/type/__rvm_gemset/man.rst +++ b/cdist/conf/type/__rvm_gemset/man.rst @@ -41,8 +41,8 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__rvm`\ (7), :manpage:`cdist-type__rvm_gem`\ (7), -:manpage:`cdist-type__rvm_ruby`\ (7) +:strong:`cdist-type__rvm`\ (7), :strong:`cdist-type__rvm_gem`\ (7), +:strong:`cdist-type__rvm_ruby`\ (7) AUTHORS diff --git a/cdist/conf/type/__rvm_ruby/man.rst b/cdist/conf/type/__rvm_ruby/man.rst index 18b6044b..f6e71e12 100644 --- a/cdist/conf/type/__rvm_ruby/man.rst +++ b/cdist/conf/type/__rvm_ruby/man.rst @@ -42,8 +42,8 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__rvm`\ (7), :manpage:`cdist-type__rvm_gem`\ (7), -:manpage:`cdist-type__rvm_gemset`\ (7) +:strong:`cdist-type__rvm`\ (7), :strong:`cdist-type__rvm_gem`\ (7), +:strong:`cdist-type__rvm_gemset`\ (7) AUTHORS diff --git a/cdist/conf/type/__ssh_authorized_key/man.rst b/cdist/conf/type/__ssh_authorized_key/man.rst index 3585717f..a65ebdd9 100644 --- a/cdist/conf/type/__ssh_authorized_key/man.rst +++ b/cdist/conf/type/__ssh_authorized_key/man.rst @@ -55,7 +55,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist__ssh_authorized_keys`\ (7), :manpage:`sshd`\ (8) +:strong:`cdist__ssh_authorized_keys`\ (7), :strong:`sshd`\ (8) AUTHORS diff --git a/cdist/conf/type/__ssh_authorized_keys/man.rst b/cdist/conf/type/__ssh_authorized_keys/man.rst index 6729660e..e6829883 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.rst +++ b/cdist/conf/type/__ssh_authorized_keys/man.rst @@ -105,7 +105,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`sshd`\ (8) +:strong:`sshd`\ (8) AUTHORS diff --git a/cdist/conf/type/__ssh_dot_ssh/man.rst b/cdist/conf/type/__ssh_dot_ssh/man.rst index 75adbde0..3084d60d 100644 --- a/cdist/conf/type/__ssh_dot_ssh/man.rst +++ b/cdist/conf/type/__ssh_dot_ssh/man.rst @@ -33,7 +33,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__ssh_authorized_keys`\ (7) +:strong:`cdist-type__ssh_authorized_keys`\ (7) AUTHORS diff --git a/cdist/conf/type/__staged_file/man.rst b/cdist/conf/type/__staged_file/man.rst index d11338af..3d8ee966 100644 --- a/cdist/conf/type/__staged_file/man.rst +++ b/cdist/conf/type/__staged_file/man.rst @@ -99,7 +99,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__file`\ (7) +:strong:`cdist-type__file`\ (7) AUTHORS diff --git a/cdist/conf/type/__start_on_boot/man.rst b/cdist/conf/type/__start_on_boot/man.rst index 70c3e8d4..4d4dd631 100644 --- a/cdist/conf/type/__start_on_boot/man.rst +++ b/cdist/conf/type/__start_on_boot/man.rst @@ -45,7 +45,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__process`\ (7) +:strong:`cdist-type__process`\ (7) AUTHORS diff --git a/cdist/conf/type/__update_alternatives/man.rst b/cdist/conf/type/__update_alternatives/man.rst index c2b8bf6d..2fff3cba 100644 --- a/cdist/conf/type/__update_alternatives/man.rst +++ b/cdist/conf/type/__update_alternatives/man.rst @@ -30,7 +30,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`cdist-type__debconf_set_selections`\ (7), :manpage:`update-alternatives`\ (8) +:strong:`cdist-type__debconf_set_selections`\ (7), :strong:`update-alternatives`\ (8) AUTHORS diff --git a/cdist/conf/type/__user/man.rst b/cdist/conf/type/__user/man.rst index 1ad17b5b..172bde7c 100644 --- a/cdist/conf/type/__user/man.rst +++ b/cdist/conf/type/__user/man.rst @@ -84,7 +84,7 @@ EXAMPLES SEE ALSO -------- -:manpage:`pw`\ (8), :manpage:`usermod`\ (8) +:strong:`pw`\ (8), :strong:`usermod`\ (8) AUTHORS From 0f8ec6ce3a06164a37112c57f9247df94d44354d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 30 Jun 2016 15:24:14 +0200 Subject: [PATCH 0176/1332] Update docs installation chapter. --- docs/src/cdist-install.rst | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst index f950a1ee..a94c12a3 100644 --- a/docs/src/cdist-install.rst +++ b/docs/src/cdist-install.rst @@ -68,19 +68,31 @@ If the main site is down, you can acquire cdist from one of the following sites: * git://github.com/telmich/cdist.git `github `_ * git://git.code.sf.net/p/cdist/code `sourceforge `_ -Building and using manpages -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Building and using documentation (man and html) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you want to build and use the manpages, run: +If you want to build and use the documentation, run: + +.. code-block:: sh + + make docs + +Documentation comes in two formats, man pages and full HTML +documentation. Documentation is built into distribution's +docs/dist directory. man pages are in docs/dist/man and +HTML documentation in docs/dist/html. + +If you want to use man pages, run: .. code-block:: sh - make man export MANPATH=$MANPATH:$(pwd -P)/docs/dist/man Or you can move manpages from docs/dist/man directory to some other directory and add it to MANPATH. +Full HTML documentation can be accessed at docs/dist/html/index.html. + You can also build manpages for types in your ~/.cdist directory: .. code-block:: sh @@ -94,17 +106,6 @@ some other custom .cdist directory, e.g. /opt/cdist then use: DOT_CDIST_PATH=/opt/cdist make dotman -Building and using HTML documentation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If you want to build and use HTML documentation, run: - -.. code-block:: sh - - make html - -Now you can access docs/dist/html/index.html. - Python package ~~~~~~~~~~~~~~ From 76563756eeb259559c821200257f5c9143948e2a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 30 Jun 2016 15:28:57 +0200 Subject: [PATCH 0177/1332] Update Nico's cdist main page with installation instructions. --- docs/web/cdist/install.mdwn | 143 ++++++++---------------------------- 1 file changed, 30 insertions(+), 113 deletions(-) diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index ce6ca877..b3724911 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -17,114 +17,6 @@ This is the machine you use to configure the target hosts. * /bin/sh: A posix like shell (for instance bash, dash, zsh) * SSH server -## Requirement Installation: Python >= 3.2 - -Ensure you have at least Python 3.2 or newer installed on -the **source host**. -You can check this by running **python -V**: - - % python -V - Python 3.3.0 - -### Archlinux - -Archlinux includes a recent python in the extra repository. -You can install it using - - pacman -S python - -### CentOS - -See the "From source" section - -### Debian - -For Debian **wheezy** or newer: - - aptitude install python3 - -On **squeeze** you can add following line in **/etc/apt/sources.list** - - deb http://ftp.debian.org/debian wheezy main - -And add pinning entry in **/etc/apt/preferences.d/wheezy**: - - Package: * - Pin: release n=wheezy - Pin-Priority: 1 - -Please be aware that both **openssh-server** and **openssh-client** might be -removed on **python3.2** installation. You surely want to reinstall them: - - apt-get install -t wheezy openssh-server openssh-client - -For older Debian versions, installing python 3.2 from source is required. - -If you want to build the cdist manpages: - - aptitude install --without-recommends asciidoc xsltproc - -### Fedora - -Fedora 15 and newer includes a recent python. -You can install it using - - yum install python3 - -### FreeBSD - -For the port: - - cd /usr/ports/lang/python32/ && make install clean - -For the package: - - pkg_add -r python32 - -You can also use any newer version, but at least python 3.2 is required. - -### Gentoo - -Gentoo only provides python 3.2 in testing packages (http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=3&chap=3). -If you want to ensure nothing breaks you must set back the python version to what was default before. - - emerge -av =python-3.2.2 --autounmask-write - emerge -av =python-3.2.2 - eselect python list - eselect python list set python3.2 - -### Max OS X - -You can choose between Homebrew and Macports, either way works: - -[Homebrew](http://mxcl.github.com/homebrew/) variant: - - brew install python3 - -[Macports](http://www.macports.org/install.php) variant: - - port install python32 - ln -s /opt/local/bin/python3.2 /opt/local/bin/python3 - -### Redhat - -See the "From source" section - -### From Source - -For those operating systems not yet supporting Python 3.2: - - pyversion=3.2.3 - wget http://www.python.org/ftp/python/$pyversion/Python-${pyversion}.tar.bz2 - tar xvfj Python-${pyversion}.tar.bz2 - cd Python-${pyversion} - ./configure - make - sudo make install - -This installs python 3.2 to /usr/local/bin. -Ensure this directory is in your PATH environment variable. - ## Install cdist You can install cdist either from git or as a python package. @@ -141,11 +33,6 @@ To install cdist, execute the following commands: cd cdist export PATH=$PATH:$(pwd -P)/bin -If you want to build and use the manpages, run: - - make man - export MANPATH=$MANPATH:$(pwd -P)/doc/man - #### Available versions in git * The active development takes place in the **master** branch @@ -169,6 +56,36 @@ If the main site is down, you can acquire cdist from one of the following sites: * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code)) +#### Building and using documentation (man and html) + +If you want to build and use the documentation, run: + + make docs + +Documentation comes in two formats, man pages and full HTML +documentation. Documentation is built into distribution's +docs/dist directory. man pages are in docs/dist/man and +HTML documentation in docs/dist/html. + +If you want to use man pages, run: + + export MANPATH=$MANPATH:$(pwd -P)/docs/dist/man + +Or you can move manpages from docs/dist/man directory to some +other directory and add it to MANPATH. + +Full HTML documentation can be accessed at docs/dist/html/index.html. + +You can also build manpages for types in your ~/.cdist directory: + + make dotman + +Built manpages are now in docs/dist/man directory. If you have +some other custom .cdist directory, e.g. /opt/cdist then use: + + DOT_CDIST_PATH=/opt/cdist make dotman + + ### Python Package Cdist is available as a python package at From 72345f551620019f13f1b5710e82dd145f73263c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 30 Jun 2016 20:31:01 +0200 Subject: [PATCH 0178/1332] Make union of existing and new requirements instead of conflict error. --- cdist/emulator.py | 60 +++++++++++++++++++++------------ cdist/test/emulator/__init__.py | 43 ++++++++++++++++++++--- 2 files changed, 77 insertions(+), 26 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index f5a9f645..d526bf77 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -201,6 +201,34 @@ class Emulator(object): except EnvironmentError as e: raise cdist.Error('Failed to read from stdin: %s' % e) + + def record_requirement(self, requirement): + """record requirement and return recorded requirement""" + + # Raises an error, if object cannot be created + try: + cdist_object = self.cdist_object.object_from_name(requirement) + except core.cdist_type.NoSuchTypeError as e: + self.log.error(("%s requires object %s, but type %s does not" + " exist. Defined at %s" % (self.cdist_object.name, + requirement, e.name, self.object_source))) + raise + except core.cdist_object.MissingObjectIdError as e: + self.log.error(("%s requires object %s without object id." + " Defined at %s" % (self.cdist_object.name, requirement, + self.object_source))) + raise + + self.log.debug("Recording requirement: %s", requirement) + + # Save the sanitised version, not the user supplied one + # (__file//bar => __file/bar) + # This ensures pattern matching is done against sanitised list + self.cdist_object.requirements.append(cdist_object.name) + + return cdist_object.name + + def record_requirements(self): """record requirements""" @@ -228,24 +256,8 @@ class Emulator(object): for requirement in requirements.split(" "): # Ignore empty fields - probably the only field anyway if len(requirement) == 0: continue - - # Raises an error, if object cannot be created - try: - cdist_object = self.cdist_object.object_from_name(requirement) - except core.cdist_type.NoSuchTypeError as e: - self.log.error("%s requires object %s, but type %s does not exist. Defined at %s" % (self.cdist_object.name, requirement, e.name, self.object_source)) - raise - except core.cdist_object.MissingObjectIdError as e: - self.log.error("%s requires object %s without object id. Defined at %s" % (self.cdist_object.name, requirement, self.object_source)) - raise - - self.log.debug("Recording requirement: %s", requirement) - - # Save the sanitised version, not the user supplied one - # (__file//bar => __file/bar) - # This ensures pattern matching is done against sanitised list - self.cdist_object.requirements.append(cdist_object.name) - reqs.add(cdist_object.name) + req = self.record_requirement(requirement) + reqs.add(req) if self._existing_reqs is not None: # if object exists then compare existing and new requirements self.log.debug("OBJ: {} {}".format(self.cdist_type, self.object_id)) @@ -253,15 +265,19 @@ class Emulator(object): self.log.debug("REQS: {}".format(reqs)) if self._existing_reqs != reqs: - errmsg = ("Object {} already exists with conflicting " - "requirements:\n{}: {}\n{}: {}".format( + dbgmsg = ("Object {} already exists with different " + "requirements:\n{}: {}\n{}: {}. Merging sets.".format( self.cdist_object.name, " ".join(self.cdist_object.source), self._existing_reqs, self.object_source, reqs)) - self.log.error(errmsg) - raise cdist.Error(errmsg) + self.log.debug(dbgmsg) + all_reqs = reqs | self._existing_reqs + self.log.debug("All requirements: {}".format(all_reqs)) + for x in all_reqs: + if not x in self.cdist_object.requirements: + self.record_requirement(x) def record_auto_requirements(self): diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index b91c1e8f..ee6c3cea 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -155,7 +155,7 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): def tearDown(self): shutil.rmtree(self.temp_dir) - def test_object_conflicting_requirements_req_none(self): + def test_object_different_requirements_req_none(self): argv = ['__directory', 'spam'] emu = emulator.Emulator(argv, env=self.env) emu.run() @@ -167,9 +167,14 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): if 'require' in self.env: del self.env['require'] emu = emulator.Emulator(argv, env=self.env) - self.assertRaises(cdist.Error, emu.run) + emu.run() - def test_object_conflicting_requirements_none_req(self): + cdist_type = core.CdistType(self.local.type_path, '__file') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'eggs') + reqs = set(('__directory/spam',)) + self.assertEqual(reqs, set(cdist_object.requirements)) + + def test_object_different_requirements_none_req(self): argv = ['__directory', 'spam'] emu = emulator.Emulator(argv, env=self.env) emu.run() @@ -181,7 +186,37 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): argv = ['__file', 'eggs'] self.env['require'] = '__directory/spam' emu = emulator.Emulator(argv, env=self.env) - self.assertRaises(cdist.Error, emu.run) + emu.run() + + cdist_type = core.CdistType(self.local.type_path, '__file') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'eggs') + reqs = set(('__directory/spam',)) + self.assertEqual(reqs, set(cdist_object.requirements)) + + def test_object_different_requirements(self): + argv = ['__directory', 'spam'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__directory', 'spameggs'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + + argv = ['__file', 'eggs'] + if 'require' in self.env: + del self.env['require'] + self.env['require'] = '__directory/spam' + emu = emulator.Emulator(argv, env=self.env) + emu.run() + + argv = ['__file', 'eggs'] + self.env['require'] = '__directory/spameggs' + emu = emulator.Emulator(argv, env=self.env) + emu.run() + + cdist_type = core.CdistType(self.local.type_path, '__file') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'eggs') + reqs = set(('__directory/spam', '__directory/spameggs',)) + self.assertEqual(reqs, set(cdist_object.requirements)) class AutoRequireEmulatorTestCase(test.CdistTestCase): From 92d96c14b936502a3fdb2c53ece8a5250e076c21 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 4 Jul 2016 10:11:11 +0200 Subject: [PATCH 0179/1332] Undo reqs conflict detection, continue appending new reqs. --- cdist/emulator.py | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index d526bf77..0e4a41c4 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -77,9 +77,6 @@ class Emulator(object): self.type_name = os.path.basename(argv[0]) self.cdist_type = core.CdistType(self.type_base_path, self.type_name) - # if set then object already exists and this var holds existing - # requirements - self._existing_reqs = None self.__init_log() @@ -155,7 +152,6 @@ class Emulator(object): if self.cdist_object.exists and not 'CDIST_OVERRIDE' in self.env: # make existing requirements a set, so we can compare it # later with new requirements - self._existing_reqs = set(self.cdist_object.requirements) if self.cdist_object.parameters != self.parameters: errmsg = ("Object %s already exists with conflicting " "parameters:\n%s: %s\n%s: %s" % (self.cdist_object.name, @@ -249,35 +245,13 @@ class Emulator(object): # if no second last line, we are on the first type, so do not set a requirement pass - reqs = set() if "require" in self.env: requirements = self.env['require'] self.log.debug("reqs = " + requirements) for requirement in requirements.split(" "): # Ignore empty fields - probably the only field anyway if len(requirement) == 0: continue - req = self.record_requirement(requirement) - reqs.add(req) - if self._existing_reqs is not None: - # if object exists then compare existing and new requirements - self.log.debug("OBJ: {} {}".format(self.cdist_type, self.object_id)) - self.log.debug("EXISTING REQS: {}".format(self._existing_reqs)) - self.log.debug("REQS: {}".format(reqs)) - - if self._existing_reqs != reqs: - dbgmsg = ("Object {} already exists with different " - "requirements:\n{}: {}\n{}: {}. Merging sets.".format( - self.cdist_object.name, - " ".join(self.cdist_object.source), - self._existing_reqs, - self.object_source, - reqs)) - self.log.debug(dbgmsg) - all_reqs = reqs | self._existing_reqs - self.log.debug("All requirements: {}".format(all_reqs)) - for x in all_reqs: - if not x in self.cdist_object.requirements: - self.record_requirement(x) + self.record_requirement(requirement) def record_auto_requirements(self): From 43ef5ec1ae664d5b51ec3ed61fb83564ace65b28 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 4 Jul 2016 10:14:19 +0200 Subject: [PATCH 0180/1332] Remove conflicting reqs changelog. --- docs/changelog | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 8e701bdd..f1aead98 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,6 @@ Changelog next: * Documentation: Restructure and fix and improve docs and manpages (Darko Poljak) * Core: Add files directory for static files (Darko Poljak) - * Core: Fix conflicting requirements (Darko Poljak) * Custom: Add bash and zsh completions (Darko Poljak) * Core: Improve error reporting for local and remote run command (Darko Poljak) * New type: __jail_freebsd9: Handle jail management on FreeBSD <= 9.X (Jake Guffey) From 4dac520d9875865186cb0cbcdebc3e17579e9e1d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 4 Jul 2016 12:21:01 +0200 Subject: [PATCH 0181/1332] Implement make targets: man, html, docs. --- Makefile | 11 ++++------- docs/src/cdist-install.rst | 21 +++++++++++++++++---- docs/src/man1/cdist.rst | 4 ---- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 7885cf24..e1abde88 100644 --- a/Makefile +++ b/Makefile @@ -63,13 +63,13 @@ $(DOCSREF): $(DOCSREFSH) $(DOCSREFSH) # Manpages #3: generic part -sphinxman: $(MANTYPES) $(DOCSREF) $(PYTHON_VERSION) +man: $(MANTYPES) $(DOCSREF) $(PYTHON_VERSION) $(SPHINXM) -sphinxhtml: $(MANTYPES) $(DOCSREF) $(PYTHON_VERSION) +html: $(MANTYPES) $(DOCSREF) $(PYTHON_VERSION) $(SPHINXH) -docs: sphinxman sphinxhtml +docs: man html # Manpages #5: release part MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) @@ -102,12 +102,9 @@ $(DOTMAN7DSTDIR)/cdist-type%.rst: $(DOTTYPEDIR)/%/man.rst ln -sf "$^" $@ # Manpages #3: generic part -dotsphinxman: $(DOTMANTYPES) +dotman: $(DOTMANTYPES) $(SPHINXM) -dotman: dotsphinxman - - ################################################################################ # Speeches # diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst index a94c12a3..38db1a4e 100644 --- a/docs/src/cdist-install.rst +++ b/docs/src/cdist-install.rst @@ -12,7 +12,7 @@ This is the machine you use to configure the target hosts. * /bin/sh: A posix like shell (for instance bash, dash, zsh) * Python >= 3.2 * SSH client - * sphinx (for building html docs and/or the manpages) + * sphinx (for building html docs and/or the man pages) Target Hosts ~~~~~~~~~~~~ @@ -88,18 +88,31 @@ If you want to use man pages, run: export MANPATH=$MANPATH:$(pwd -P)/docs/dist/man -Or you can move manpages from docs/dist/man directory to some +Or you can move man pages from docs/dist/man directory to some other directory and add it to MANPATH. Full HTML documentation can be accessed at docs/dist/html/index.html. -You can also build manpages for types in your ~/.cdist directory: +You can also build only man pages or only html documentation, for +only man pages run: + +.. code-block:: sh + + make man + +for only html documentation run: + +.. code-block:: sh + + make html + +You can also build man pages for types in your ~/.cdist directory: .. code-block:: sh make dotman -Built manpages are now in docs/dist/man directory. If you have +Built man pages are now in docs/dist/man directory. If you have some other custom .cdist directory, e.g. /opt/cdist then use: .. code-block:: sh diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index efc1a201..5b821d46 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -56,10 +56,6 @@ CONFIG ------ Configure one or more hosts -.. option:: -h, --help - - Show the help screen - .. option:: -c CONF_DIR, --conf-dir CONF_DIR Add a configuration directory. Can be specified multiple times. From e76d06b382aa3e8a8ea0791453fff3135ef061f6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 4 Jul 2016 16:56:07 +0200 Subject: [PATCH 0182/1332] Fix docs-dist target. --- Makefile | 6 +++--- docs/web/cdist/documentation.mdwn | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index e1abde88..05c8004e 100644 --- a/Makefile +++ b/Makefile @@ -73,15 +73,15 @@ docs: man html # Manpages #5: release part MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) -MANBUILDDIR=docs/dist/html +HTMLBUILDDIR=docs/dist/html -docs-dist: man +docs-dist: html rm -rf "${MANWEBDIR}" mkdir -p "${MANWEBDIR}" # mkdir -p "${MANWEBDIR}/man1" "${MANWEBDIR}/man7" # cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${MANWEBDIR}/man1 # cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${MANWEBDIR}/man7 - cp -R ${MANBUILDDIR}/* ${MANWEBDIR} + cp -R ${HTMLBUILDDIR}/* ${MANWEBDIR} cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" || true man-latest-link: web-pub diff --git a/docs/web/cdist/documentation.mdwn b/docs/web/cdist/documentation.mdwn index db25b566..56c2798e 100644 --- a/docs/web/cdist/documentation.mdwn +++ b/docs/web/cdist/documentation.mdwn @@ -1,7 +1,7 @@ [[!meta title="Documentation"]] -You can browse the latest -[latest version of the manpages](/software/cdist/man/latest) or +You can browse the +[latest version of the documentation](/software/cdist/man/latest) or have a look at [all versions](/software/cdist/man). You can also view [speeches about cdist](/software/cdist/speeches). From 64efa0459971f3270203b49d989c35abf1f4197a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 5 Jul 2016 20:44:24 +0200 Subject: [PATCH 0183/1332] pep8 --- cdist/__init__.py | 11 ++- cdist/config.py | 119 ++++++++++++++++------------ cdist/core/__init__.py | 14 ++-- cdist/core/cdist_object.py | 82 ++++++++++++------- cdist/core/cdist_type.py | 38 ++++++--- cdist/core/code.py | 43 ++++++---- cdist/core/explorer.py | 55 ++++++++----- cdist/core/manifest.py | 34 +++++--- cdist/emulator.py | 119 +++++++++++++++++----------- cdist/exec/local.py | 46 +++++++---- cdist/exec/remote.py | 17 ++-- cdist/exec/util.py | 12 ++- cdist/log.py | 1 + cdist/message.py | 7 +- cdist/shell.py | 10 ++- cdist/sphinxext/manpage.py | 10 ++- cdist/test/__init__.py | 4 +- cdist/test/banner/__init__.py | 3 +- cdist/test/cdist_object/__init__.py | 114 +++++++++++++++++--------- cdist/test/cdist_type/__init__.py | 36 ++++++--- cdist/test/code/__init__.py | 46 +++++++---- cdist/test/config/__init__.py | 41 +++++----- cdist/test/emulator/__init__.py | 68 +++++++++++----- cdist/test/exec/local.py | 51 +++++++----- cdist/test/exec/remote.py | 49 ++++++++---- cdist/test/explorer/__init__.py | 51 ++++++++---- cdist/test/manifest/__init__.py | 20 +++-- cdist/test/message/__init__.py | 6 +- cdist/util/fsproperty.py | 15 ++-- 29 files changed, 714 insertions(+), 408 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index e789499c..b7436b5a 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -44,25 +44,30 @@ BANNER = """ REMOTE_COPY = "scp -o User=root" REMOTE_EXEC = "ssh -o User=root" + class Error(Exception): """Base exception class for this project""" pass + class UnresolvableRequirementsError(cdist.Error): """Resolving requirements failed""" pass + class CdistObjectError(Error): """Something went wrong with an object""" - + def __init__(self, cdist_object, message): self.name = cdist_object.name self.source = " ".join(cdist_object.source) self.message = message - def __str__(self): - return '%s: %s (defined at %s)' % (self.name, self.message, self.source) + return '%s: %s (defined at %s)' % (self.name, + self.message, + self.source) + def file_to_list(filename): """Return list from \n seperated file""" diff --git a/cdist/config.py b/cdist/config.py index f5e62ce1..5ebeab14 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -35,19 +35,21 @@ import cdist.exec.remote from cdist import core + class Config(object): """Cdist main class to hold arbitrary data""" def __init__(self, local, remote, dry_run=False): - self.local = local - self.remote = remote - self.log = logging.getLogger(self.local.target_host) - self.dry_run = dry_run + self.local = local + self.remote = remote + self.log = logging.getLogger(self.local.target_host) + self.dry_run = dry_run - self.explorer = core.Explorer(self.local.target_host, self.local, self.remote) + self.explorer = core.Explorer(self.local.target_host, self.local, + self.remote) self.manifest = core.Manifest(self.local.target_host, self.local) - self.code = core.Code(self.local.target_host, self.local, self.remote) + self.code = core.Code(self.local.target_host, self.local, self.remote) def _init_files_dirs(self): """Prepare files and directories for the run""" @@ -65,7 +67,7 @@ class Config(object): try: for host in fileinput.input(files=(source)): # remove leading and trailing whitespace - yield host.strip() + yield host.strip() except (IOError, OSError) as e: raise cdist.Error("Error reading hosts from \'{}\'".format( source)) @@ -74,7 +76,6 @@ class Config(object): for host in source: yield host - @classmethod def commandline(cls, args): """Configure remote system""" @@ -84,27 +85,29 @@ class Config(object): log = logging.getLogger("cdist") if args.manifest == '-' and args.hostfile == '-': - raise cdist.Error(("Cannot read both, manifest and host file, " - "from stdin")) + raise cdist.Error(("Cannot read both, manifest and host file, " + "from stdin")) # if no host source is specified then read hosts from stdin if not (args.hostfile or args.host): args.hostfile = '-' - + initial_manifest_tempfile = None if args.manifest == '-': # read initial manifest from stdin import tempfile try: - handle, initial_manifest_temp_path = tempfile.mkstemp(prefix='cdist.stdin.') + handle, initial_manifest_temp_path = tempfile.mkstemp( + prefix='cdist.stdin.') with os.fdopen(handle, 'w') as fd: fd.write(sys.stdin.read()) except (IOError, OSError) as e: - raise cdist.Error("Creating tempfile for stdin data failed: %s" % e) - + raise cdist.Error(("Creating tempfile for stdin data " + "failed: %s" % e)) + args.manifest = initial_manifest_temp_path import atexit atexit.register(lambda: os.remove(initial_manifest_temp_path)) - + process = {} failed_hosts = [] time_start = time.time() @@ -115,37 +118,38 @@ class Config(object): hostcnt += 1 if args.parallel: log.debug("Creating child process for %s", host) - process[host] = multiprocessing.Process(target=cls.onehost, args=(host, args, True)) + process[host] = multiprocessing.Process( + target=cls.onehost, args=(host, args, True)) process[host].start() else: try: cls.onehost(host, args, parallel=False) except cdist.Error as e: failed_hosts.append(host) - + # Catch errors in parallel mode when joining if args.parallel: for host in process.keys(): log.debug("Joining process %s", host) process[host].join() - + if not process[host].exitcode == 0: failed_hosts.append(host) - + time_end = time.time() log.info("Total processing time for %s host(s): %s", hostcnt, - (time_end - time_start)) - + (time_end - time_start)) + if len(failed_hosts) > 0: - raise cdist.Error("Failed to configure the following hosts: " + - " ".join(failed_hosts)) - + raise cdist.Error("Failed to configure the following hosts: " + + " ".join(failed_hosts)) + @classmethod def onehost(cls, host, args, parallel): """Configure ONE system""" log = logging.getLogger(host) - + try: local = cdist.exec.local.Local( target_host=host, @@ -157,10 +161,10 @@ class Config(object): target_host=host, remote_exec=args.remote_exec, remote_copy=args.remote_copy) - + c = cls(local, remote, dry_run=args.dry_run) c.run() - + except cdist.Error as e: log.error(e) if parallel: @@ -168,7 +172,7 @@ class Config(object): sys.exit(1) else: raise - + except KeyboardInterrupt: # Ignore in parallel mode, we are existing anyway if parallel: @@ -188,49 +192,50 @@ class Config(object): self.iterate_until_finished() self.local.save_cache() - self.log.info("Finished successful run in %s seconds", time.time() - start_time) - + self.log.info("Finished successful run in %s seconds", + time.time() - start_time) def object_list(self): """Short name for object list retrieval""" - for cdist_object in core.CdistObject.list_objects(self.local.object_path, - self.local.type_path, - self.local.object_marker_name): + for cdist_object in core.CdistObject.list_objects( + self.local.object_path, self.local.type_path, + self.local.object_marker_name): if cdist_object.cdist_type.is_install: - self.log.debug("Running in config mode, ignoring install object: {0}".format(cdist_object)) + self.log.debug(("Running in config mode, ignoring install " + "object: {0}").format(cdist_object)) else: yield cdist_object - def iterate_once(self): """ - Iterate over the objects once - helper method for + Iterate over the objects once - helper method for iterate_until_finished """ - objects_changed = False + objects_changed = False for cdist_object in self.object_list(): if cdist_object.requirements_unfinished(cdist_object.requirements): """We cannot do anything for this poor object""" continue - + if cdist_object.state == core.CdistObject.STATE_UNDEF: """Prepare the virgin object""" - + self.object_prepare(cdist_object) objects_changed = True - + if cdist_object.requirements_unfinished(cdist_object.autorequire): - """The previous step created objects we depend on - wait for them""" + """The previous step created objects we depend on - + wait for them + """ continue - + if cdist_object.state == core.CdistObject.STATE_PREPARED: self.object_run(cdist_object) objects_changed = True return objects_changed - def iterate_until_finished(self): """ Go through all objects and solve them @@ -256,22 +261,32 @@ class Config(object): requirement_names = [] autorequire_names = [] - for requirement in cdist_object.requirements_unfinished(cdist_object.requirements): + for requirement in cdist_object.requirements_unfinished( + cdist_object.requirements): requirement_names.append(requirement.name) - for requirement in cdist_object.requirements_unfinished(cdist_object.autorequire): + for requirement in cdist_object.requirements_unfinished( + cdist_object.autorequire): autorequire_names.append(requirement.name) requirements = "\n ".join(requirement_names) - autorequire = "\n ".join(autorequire_names) - info_string.append("%s requires:\n %s\n%s autorequires:\n %s" % (cdist_object.name, requirements, cdist_object.name, autorequire)) + autorequire = "\n ".join(autorequire_names) + info_string.append(("%s requires:\n" + " %s\n" + "%s ""autorequires:\n" + " %s" % ( + cdist_object.name, + requirements, cdist_object.name, + autorequire))) - raise cdist.UnresolvableRequirementsError("The requirements of the following objects could not be resolved:\n%s" % - ("\n".join(info_string))) + raise cdist.UnresolvableRequirementsError( + ("The requirements of the following objects could not be " + "resolved:\n%s") % ("\n".join(info_string))) def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" - self.log.info("Running manifest and explorers for " + cdist_object.name) + self.log.info( + "Running manifest and explorers for " + cdist_object.name) self.explorer.run_type_explorers(cdist_object) self.manifest.run_type_manifest(cdist_object) cdist_object.state = core.CdistObject.STATE_PREPARED @@ -281,7 +296,8 @@ class Config(object): self.log.debug("Trying to run object %s" % (cdist_object.name)) if cdist_object.state == core.CdistObject.STATE_DONE: - raise cdist.Error("Attempting to run an already finished object: %s", cdist_object) + raise cdist.Error(("Attempting to run an already finished " + "object: %s"), cdist_object) cdist_type = cdist_object.cdist_type @@ -304,7 +320,6 @@ class Config(object): else: self.log.info("Skipping code execution due to DRY RUN") - # Mark this object as done self.log.debug("Finishing run of " + cdist_object.name) cdist_object.state = core.CdistObject.STATE_DONE diff --git a/cdist/core/__init__.py b/cdist/core/__init__.py index d773fc01..41e00a3a 100644 --- a/cdist/core/__init__.py +++ b/cdist/core/__init__.py @@ -20,10 +20,10 @@ # # -from cdist.core.cdist_type import CdistType -from cdist.core.cdist_type import NoSuchTypeError -from cdist.core.cdist_object import CdistObject -from cdist.core.cdist_object import IllegalObjectIdError -from cdist.core.explorer import Explorer -from cdist.core.manifest import Manifest -from cdist.core.code import Code +from cdist.core.cdist_type import CdistType +from cdist.core.cdist_type import NoSuchTypeError +from cdist.core.cdist_object import CdistObject +from cdist.core.cdist_object import IllegalObjectIdError +from cdist.core.explorer import Explorer +from cdist.core.manifest import Manifest +from cdist.core.code import Code diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 8c6ee9c9..262db8bf 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -32,6 +32,7 @@ from cdist.util import fsproperty log = logging.getLogger(__name__) + class IllegalObjectIdError(cdist.Error): def __init__(self, object_id, message=None): self.object_id = object_id @@ -40,14 +41,17 @@ class IllegalObjectIdError(cdist.Error): def __str__(self): return '%s: %s' % (self.message, self.object_id) + class MissingObjectIdError(cdist.Error): def __init__(self, type_name): self.type_name = type_name - self.message = "Type %s requires object id (is not a singleton type)" % self.type_name + self.message = ("Type %s requires object id (is not a " + "singleton type)") % self.type_name def __str__(self): return '%s' % (self.message) + class CdistObject(object): """Represents a cdist object. @@ -64,7 +68,7 @@ class CdistObject(object): STATE_DONE = "done" def __init__(self, cdist_type, base_path, object_marker, object_id): - self.cdist_type = cdist_type # instance of Type + self.cdist_type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id @@ -74,7 +78,8 @@ class CdistObject(object): self.sanitise_object_id() self.name = self.join_name(self.cdist_type.name, self.object_id) - self.path = os.path.join(self.cdist_type.path, self.object_id, self.object_marker) + self.path = os.path.join(self.cdist_type.path, self.object_id, + self.object_marker) self.absolute_path = os.path.join(self.base_path, self.path) self.code_local_path = os.path.join(self.path, "code-local") @@ -84,12 +89,13 @@ class CdistObject(object): @classmethod def list_objects(cls, object_base_path, type_base_path, object_marker): """Return a list of object instances""" - for object_name in cls.list_object_names(object_base_path, object_marker): + for object_name in cls.list_object_names( + object_base_path, object_marker): type_name, object_id = cls.split_name(object_name) yield cls(cdist.core.CdistType(type_base_path, type_name), - base_path=object_base_path, - object_marker=object_marker, - object_id=object_id) + base_path=object_base_path, + object_marker=object_marker, + object_id=object_id) @classmethod def list_object_names(cls, object_base_path, object_marker): @@ -125,26 +131,34 @@ class CdistObject(object): def validate_object_id(self): if self.cdist_type.is_singleton and self.object_id: - raise IllegalObjectIdError('singleton objects can\'t have a object_id') + raise IllegalObjectIdError(('singleton objects can\'t have an ' + 'object_id')) - """Validate the given object_id and raise IllegalObjectIdError if it's not valid. + """Validate the given object_id and raise IllegalObjectIdError + if it's not valid. """ if self.object_id: if self.object_marker in self.object_id.split(os.sep): - raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % self.object_marker) + raise IllegalObjectIdError( + self.object_id, ('object_id may not contain ' + '\'%s\'') % self.object_marker) if '//' in self.object_id: - raise IllegalObjectIdError(self.object_id, 'object_id may not contain //') + raise IllegalObjectIdError( + self.object_id, 'object_id may not contain //') if self.object_id == '.': - raise IllegalObjectIdError(self.object_id, 'object_id may not be a .') + raise IllegalObjectIdError( + self.object_id, 'object_id may not be a .') # If no object_id and type is not singleton => error out if not self.object_id and not self.cdist_type.is_singleton: raise MissingObjectIdError(self.cdist_type.name) - # Does not work: AttributeError: 'CdistObject' object has no attribute 'parameter_path' + # Does not work: + # AttributeError: + # 'CdistObject' object has no attribute 'parameter_path' - #"Type %s is not a singleton type - missing object id (parameters: %s)" % - # (self.cdist_type.name, self.parameters)) + # "Type %s is not a singleton type - missing object id + # (parameters: %s)" % (self.cdist_type.name, self.parameters)) def object_from_name(self, object_name): """Convenience method for creating an object instance from an object name. @@ -152,7 +166,8 @@ class CdistObject(object): Mainly intended to create objects when resolving requirements. e.g: - .object_from_name('__other/object') -> + .object_from_name('__other/object') -> + """ @@ -164,7 +179,8 @@ class CdistObject(object): cdist_type = self.cdist_type.__class__(type_path, type_name) - return self.__class__(cdist_type, base_path, object_marker, object_id=object_id) + return self.__class__(cdist_type, base_path, object_marker, + object_id=object_id) def __repr__(self): return '' % self.name @@ -172,7 +188,7 @@ class CdistObject(object): def __eq__(self, other): """define equality as 'name is the same'""" return self.name == other.name - + def __hash__(self): return hash(self.name) @@ -205,14 +221,22 @@ class CdistObject(object): # return relative path return os.path.join(self.path, "explorer") - requirements = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'require')) - autorequire = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, 'autorequire')) - parameters = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.base_path, obj.parameter_path)) - explorers = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.base_path, obj.explorer_path)) - state = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.absolute_path, "state")) - source = fsproperty.FileListProperty(lambda obj: os.path.join(obj.absolute_path, "source")) - code_local = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.base_path, obj.code_local_path)) - code_remote = fsproperty.FileStringProperty(lambda obj: os.path.join(obj.base_path, obj.code_remote_path)) + requirements = fsproperty.FileListProperty( + lambda obj: os.path.join(obj.absolute_path, 'require')) + autorequire = fsproperty.FileListProperty( + lambda obj: os.path.join(obj.absolute_path, 'autorequire')) + parameters = fsproperty.DirectoryDictProperty( + lambda obj: os.path.join(obj.base_path, obj.parameter_path)) + explorers = fsproperty.DirectoryDictProperty( + lambda obj: os.path.join(obj.base_path, obj.explorer_path)) + state = fsproperty.FileStringProperty( + lambda obj: os.path.join(obj.absolute_path, "state")) + source = fsproperty.FileListProperty( + lambda obj: os.path.join(obj.absolute_path, "source")) + code_local = fsproperty.FileStringProperty( + lambda obj: os.path.join(obj.base_path, obj.code_local_path)) + code_remote = fsproperty.FileStringProperty( + lambda obj: os.path.join(obj.base_path, obj.code_remote_path)) @property def exists(self): @@ -224,10 +248,12 @@ class CdistObject(object): """ try: os.makedirs(self.absolute_path, exist_ok=allow_overwrite) - absolute_parameter_path = os.path.join(self.base_path, self.parameter_path) + absolute_parameter_path = os.path.join(self.base_path, + self.parameter_path) os.makedirs(absolute_parameter_path, exist_ok=allow_overwrite) except EnvironmentError as error: - raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) + raise cdist.Error(('Error creating directories for cdist object: ' + '%s: %s') % (self, error)) def requirements_unfinished(self, requirements): """Return state whether requirements are satisfied""" diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index d5b4ea3e..a548f365 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -24,6 +24,7 @@ import os import cdist + class NoSuchTypeError(cdist.Error): def __init__(self, name, type_path, type_absolute_path): self.name = name @@ -31,7 +32,8 @@ class NoSuchTypeError(cdist.Error): self.type_absolute_path = type_absolute_path def __str__(self): - return "Type '%s' does not exist at %s" % (self.type_path, self.type_absolute_path) + return "Type '%s' does not exist at %s" % ( + self.type_path, self.type_absolute_path) class CdistType(object): @@ -75,13 +77,13 @@ class CdistType(object): """Return a list of type names""" return os.listdir(base_path) - _instances = {} + def __new__(cls, *args, **kwargs): """only one instance of each named type may exist""" # name is second argument name = args[1] - if not name in cls._instances: + if name not in cls._instances: instance = super(CdistType, cls).__new__(cls) cls._instances[name] = instance # return instance so __init__ is called @@ -103,7 +105,8 @@ class CdistType(object): @property def is_install(self): - """Check whether a type is used for installation (if not: for configuration)""" + """Check whether a type is used for installation + (if not: for configuration)""" return os.path.isfile(os.path.join(self.absolute_path, "install")) @property @@ -111,7 +114,8 @@ class CdistType(object): """Return a list of available explorers""" if not self.__explorers: try: - self.__explorers = os.listdir(os.path.join(self.absolute_path, "explorer")) + self.__explorers = os.listdir(os.path.join(self.absolute_path, + "explorer")) except EnvironmentError: # error ignored self.__explorers = [] @@ -123,7 +127,9 @@ class CdistType(object): if not self.__required_parameters: parameters = [] try: - with open(os.path.join(self.absolute_path, "parameter", "required")) as fd: + with open(os.path.join(self.absolute_path, + "parameter", + "required")) as fd: for line in fd: parameters.append(line.strip()) except EnvironmentError: @@ -139,7 +145,9 @@ class CdistType(object): if not self.__required_multiple_parameters: parameters = [] try: - with open(os.path.join(self.absolute_path, "parameter", "required_multiple")) as fd: + with open(os.path.join(self.absolute_path, + "parameter", + "required_multiple")) as fd: for line in fd: parameters.append(line.strip()) except EnvironmentError: @@ -155,7 +163,9 @@ class CdistType(object): if not self.__optional_parameters: parameters = [] try: - with open(os.path.join(self.absolute_path, "parameter", "optional")) as fd: + with open(os.path.join(self.absolute_path, + "parameter", + "optional")) as fd: for line in fd: parameters.append(line.strip()) except EnvironmentError: @@ -171,7 +181,9 @@ class CdistType(object): if not self.__optional_multiple_parameters: parameters = [] try: - with open(os.path.join(self.absolute_path, "parameter", "optional_multiple")) as fd: + with open(os.path.join(self.absolute_path, + "parameter", + "optional_multiple")) as fd: for line in fd: parameters.append(line.strip()) except EnvironmentError: @@ -187,7 +199,9 @@ class CdistType(object): if not self.__boolean_parameters: parameters = [] try: - with open(os.path.join(self.absolute_path, "parameter", "boolean")) as fd: + with open(os.path.join(self.absolute_path, + "parameter", + "boolean")) as fd: for line in fd: parameters.append(line.strip()) except EnvironmentError: @@ -202,7 +216,9 @@ class CdistType(object): if not self.__parameter_defaults: defaults = {} try: - defaults_dir = os.path.join(self.absolute_path, "parameter", "default") + defaults_dir = os.path.join(self.absolute_path, + "parameter", + "default") for name in os.listdir(defaults_dir): try: with open(os.path.join(defaults_dir, name)) as fd: diff --git a/cdist/core/code.py b/cdist/core/code.py index 64517532..8e3cd63e 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -37,15 +37,17 @@ common: PATH: prepend directory with type emulator symlinks == local.bin_path __target_host: the target host we are working on __cdist_manifest: full qualified path of the manifest == script - __cdist_type_base_path: full qualified path to the directory where types are defined for use in type emulator - == local.type_path + __cdist_type_base_path: full qualified path to the directory where + types are defined for use in type emulator + == local.type_path gencode-local script: full qualified path to a types gencode-local env: __target_host: the target host we are working on - __global: full qualified path to the global output dir == local.out_path + __global: full qualified path to the global + output dir == local.out_path __object: full qualified path to the object's dir __object_id: the objects id __object_fq: full qualified object id, iow: $type.name + / + object_id @@ -59,7 +61,8 @@ gencode-remote env: __target_host: the target host we are working on - __global: full qualified path to the global output dir == local.out_path + __global: full qualified path to the global + output dir == local.out_path __object: full qualified path to the object's dir __object_id: the objects id __object_fq: full qualified object id, iow: $type.name + / + object_id @@ -98,7 +101,8 @@ class Code(object): def _run_gencode(self, cdist_object, which): cdist_type = cdist_object.cdist_type - script = os.path.join(self.local.type_path, getattr(cdist_type, 'gencode_%s_path' % which)) + script = os.path.join(self.local.type_path, + getattr(cdist_type, 'gencode_%s_path' % which)) if os.path.isfile(script): env = os.environ.copy() env.update(self.env) @@ -108,8 +112,9 @@ class Code(object): '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, }) - message_prefix=cdist_object.name - return self.local.run_script(script, env=env, return_output=True, message_prefix=message_prefix) + message_prefix = cdist_object.name + return self.local.run_script(script, env=env, return_output=True, + message_prefix=message_prefix) def run_gencode_local(self, cdist_object): """Run the gencode-local script for the given cdist object.""" @@ -120,21 +125,26 @@ class Code(object): return self._run_gencode(cdist_object, 'remote') def transfer_code_remote(self, cdist_object): - """Transfer the code_remote script for the given object to the remote side.""" - source = os.path.join(self.local.object_path, cdist_object.code_remote_path) - destination = os.path.join(self.remote.object_path, cdist_object.code_remote_path) + """Transfer the code_remote script for the given object to the + remote side.""" + source = os.path.join(self.local.object_path, + cdist_object.code_remote_path) + destination = os.path.join(self.remote.object_path, + cdist_object.code_remote_path) # FIXME: BUG: do not create destination, but top level of destination! self.remote.mkdir(destination) self.remote.transfer(source, destination) def _run_code(self, cdist_object, which, env=None): which_exec = getattr(self, which) - script = os.path.join(which_exec.object_path, getattr(cdist_object, 'code_%s_path' % which)) + script = os.path.join(which_exec.object_path, + getattr(cdist_object, 'code_%s_path' % which)) return which_exec.run_script(script, env=env) def run_code_local(self, cdist_object): """Run the code-local script for the given cdist object.""" - # Put some env vars, to allow read only access to the parameters over $__object + # Put some env vars, to allow read only access to the parameters + # over $__object env = os.environ.copy() env.update(self.env) env.update({ @@ -144,10 +154,13 @@ class Code(object): return self._run_code(cdist_object, 'local', env=env) def run_code_remote(self, cdist_object): - """Run the code-remote script for the given cdist object on the remote side.""" - # Put some env vars, to allow read only access to the parameters over $__object which is already on the remote side + """Run the code-remote script for the given cdist object on the + remote side.""" + # Put some env vars, to allow read only access to the parameters + # over $__object which is already on the remote side env = { - '__object': os.path.join(self.remote.object_path, cdist_object.path), + '__object': os.path.join(self.remote.object_path, + cdist_object.path), '__object_id': cdist_object.object_id, } return self._run_code(cdist_object, 'remote', env=env) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 41851bd6..345f45ff 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -31,7 +31,8 @@ common: runs only remotely, needs local and remote to construct paths env: - __explorer: full qualified path to other global explorers on remote side + __explorer: full qualified path to other global explorers on + remote side -> remote.global_explorer_path a global explorer is: @@ -52,7 +53,8 @@ type explorer is: __object: full qualified path to the object's remote dir __object_id: the objects id __object_fq: full qualified object id, iow: $type.name + / + object_id - __type_explorer: full qualified path to the other type explorers on remote side + __type_explorer: full qualified path to the other type explorers on + remote side creates: nothing, returns output @@ -76,7 +78,7 @@ class Explorer(object): } self._type_explorers_transferred = [] - ### global + # global def list_global_explorer_names(self): """Return a list of global explorer names.""" @@ -98,15 +100,17 @@ class Explorer(object): def transfer_global_explorers(self): """Transfer the global explorers to the remote side.""" self.remote.mkdir(self.remote.global_explorer_path) - self.remote.transfer(self.local.global_explorer_path, self.remote.global_explorer_path) - self.remote.run(["chmod", "0700", "%s/*" % (self.remote.global_explorer_path)]) + self.remote.transfer(self.local.global_explorer_path, + self.remote.global_explorer_path) + self.remote.run(["chmod", "0700", + "%s/*" % (self.remote.global_explorer_path)]) def run_global_explorer(self, explorer): """Run the given global explorer and return it's output.""" script = os.path.join(self.remote.global_explorer_path, explorer) return self.remote.run_script(script, env=self.env, return_output=True) - ### type + # type def list_type_explorer_names(self, cdist_type): """Return a list of explorer names for the given type.""" @@ -121,37 +125,48 @@ class Explorer(object): in the object. """ - self.log.debug("Transfering type explorers for type: %s", cdist_object.cdist_type) + self.log.debug("Transfering type explorers for type: %s", + cdist_object.cdist_type) self.transfer_type_explorers(cdist_object.cdist_type) - self.log.debug("Transfering object parameters for object: %s", cdist_object.name) + self.log.debug("Transfering object parameters for object: %s", + cdist_object.name) self.transfer_object_parameters(cdist_object) for explorer in self.list_type_explorer_names(cdist_object.cdist_type): output = self.run_type_explorer(explorer, cdist_object) - self.log.debug("Running type explorer '%s' for object '%s'", explorer, cdist_object.name) + self.log.debug("Running type explorer '%s' for object '%s'", + explorer, cdist_object.name) cdist_object.explorers[explorer] = output def run_type_explorer(self, explorer, cdist_object): - """Run the given type explorer for the given object and return it's output.""" + """Run the given type explorer for the given object and return + it's output.""" cdist_type = cdist_object.cdist_type env = self.env.copy() env.update({ - '__object': os.path.join(self.remote.object_path, cdist_object.path), + '__object': os.path.join(self.remote.object_path, + cdist_object.path), '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, '__object_fq': cdist_object.path, - '__type_explorer': os.path.join(self.remote.type_path, cdist_type.explorer_path) + '__type_explorer': os.path.join(self.remote.type_path, + cdist_type.explorer_path) }) - script = os.path.join(self.remote.type_path, cdist_type.explorer_path, explorer) + script = os.path.join(self.remote.type_path, cdist_type.explorer_path, + explorer) return self.remote.run_script(script, env=env, return_output=True) def transfer_type_explorers(self, cdist_type): - """Transfer the type explorers for the given type to the remote side.""" + """Transfer the type explorers for the given type to the + remote side.""" if cdist_type.explorers: if cdist_type.name in self._type_explorers_transferred: - self.log.debug("Skipping retransfer of type explorers for: %s", cdist_type) + self.log.debug("Skipping retransfer of type explorers for: %s", + cdist_type) else: - source = os.path.join(self.local.type_path, cdist_type.explorer_path) - destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) + source = os.path.join(self.local.type_path, + cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, + cdist_type.explorer_path) self.remote.mkdir(destination) self.remote.transfer(source, destination) self.remote.run(["chmod", "0700", "%s/*" % (destination)]) @@ -160,7 +175,9 @@ class Explorer(object): def transfer_object_parameters(self, cdist_object): """Transfer the parameters for the given object to the remote side.""" if cdist_object.parameters: - source = os.path.join(self.local.object_path, cdist_object.parameter_path) - destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) + source = os.path.join(self.local.object_path, + cdist_object.parameter_path) + destination = os.path.join(self.remote.object_path, + cdist_object.parameter_path) self.remote.mkdir(destination) self.remote.transfer(source, destination) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 3b71a215..ac322101 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -32,9 +32,11 @@ common: env: PATH: prepend directory with type emulator symlinks == local.bin_path __target_host: the target host we are working on - __global: full qualified path to the global output dir == local.out_path + __global: full qualified path to the global + output dir == local.out_path __cdist_manifest: full qualified path of the manifest == script - __cdist_type_base_path: full qualified path to the directory where types are defined for use in type emulator + __cdist_type_base_path: full qualified path to the directory where + types are defined for use in type emulator == local.type_path __files: full qualified path to the files dir @@ -58,6 +60,7 @@ type manifeste is: creates: new objects through type emulator ''' + class NoInitialManifestError(cdist.Error): """ Display missing initial manifest: @@ -72,7 +75,9 @@ class NoInitialManifestError(cdist.Error): if user_supplied: if os.path.islink(manifest_path): - self.message = "%s: %s -> %s" % (msg_header, manifest_path, os.path.realpath(manifest_path)) + self.message = "%s: %s -> %s" % ( + msg_header, manifest_path, + os.path.realpath(manifest_path)) else: self.message = "%s: %s" % (msg_header, manifest_path) else: @@ -94,14 +99,15 @@ class Manifest(object): self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), - '__cdist_type_base_path': self.local.type_path, # for use in type emulator + # for use in type emulator + '__cdist_type_base_path': self.local.type_path, '__global': self.local.base_path, '__target_host': self.target_host, '__files': self.local.files_path, } - if self.log.getEffectiveLevel() == logging.DEBUG: - self.env.update({'__cdist_debug': "yes" }) + if self.log.getEffectiveLevel() == logging.DEBUG: + self.env.update({'__cdist_debug': "yes"}) def env_initial_manifest(self, initial_manifest): env = os.environ.copy() @@ -124,11 +130,14 @@ class Manifest(object): if not os.path.isfile(initial_manifest): raise NoInitialManifestError(initial_manifest, user_supplied) - message_prefix="initialmanifest" - self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest), message_prefix=message_prefix) + message_prefix = "initialmanifest" + self.local.run_script(initial_manifest, + env=self.env_initial_manifest(initial_manifest), + message_prefix=message_prefix) def env_type_manifest(self, cdist_object): - type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) + type_manifest = os.path.join(self.local.type_path, + cdist_object.cdist_type.manifest_path) env = os.environ.copy() env.update(self.env) env.update({ @@ -143,7 +152,10 @@ class Manifest(object): return env def run_type_manifest(self, cdist_object): - type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) + type_manifest = os.path.join(self.local.type_path, + cdist_object.cdist_type.manifest_path) message_prefix = cdist_object.name if os.path.isfile(type_manifest): - self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object), message_prefix=message_prefix) + self.local.run_script(type_manifest, + env=self.env_type_manifest(cdist_object), + message_prefix=message_prefix) diff --git a/cdist/emulator.py b/cdist/emulator.py index 0e4a41c4..58ab7389 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -29,10 +29,12 @@ import sys import cdist from cdist import core + class MissingRequiredEnvironmentVariableError(cdist.Error): def __init__(self, name): self.name = name - self.message = "Emulator requires the environment variable %s to be setup" % self.name + self.message = ("Emulator requires the environment variable %s to be " + "setup" % self.name) def __str__(self): return self.message @@ -41,7 +43,7 @@ class MissingRequiredEnvironmentVariableError(cdist.Error): class DefaultList(list): """Helper class to allow default values for optional_multiple parameters. - @see https://groups.google.com/forum/#!msg/comp.lang.python/sAUvkJEDpRc/RnRymrzJVDYJ + @see https://groups.google.com/forum/#!msg/comp.lang.python/sAUvkJEDpRc/RnRymrzJVDYJ """ def __copy__(self): return [] @@ -54,20 +56,20 @@ class DefaultList(list): class Emulator(object): def __init__(self, argv, stdin=sys.stdin.buffer, env=os.environ): - self.argv = argv - self.stdin = stdin - self.env = env + self.argv = argv + self.stdin = stdin + self.env = env - self.object_id = '' + self.object_id = '' try: - self.global_path = self.env['__global'] - self.target_host = self.env['__target_host'] + self.global_path = self.env['__global'] + self.target_host = self.env['__target_host'] # Internal variables - self.object_source = self.env['__cdist_manifest'] + self.object_source = self.env['__cdist_manifest'] self.type_base_path = self.env['__cdist_type_base_path'] - self.object_marker = self.env['__cdist_object_marker'] + self.object_marker = self.env['__cdist_object_marker'] except KeyError as e: raise MissingRequiredEnvironmentVariableError(e.args[0]) @@ -75,8 +77,8 @@ class Emulator(object): self.object_base_path = os.path.join(self.global_path, "object") self.typeorder_path = os.path.join(self.global_path, "typeorder") - self.type_name = os.path.basename(argv[0]) - self.cdist_type = core.CdistType(self.type_base_path, self.type_name) + self.type_name = os.path.basename(argv[0]) + self.cdist_type = core.CdistType(self.type_base_path, self.type_name) self.__init_log() @@ -88,7 +90,8 @@ class Emulator(object): self.save_stdin() self.record_requirements() self.record_auto_requirements() - self.log.debug("Finished %s %s" % (self.cdist_object.path, self.parameters)) + self.log.debug("Finished %s %s" % ( + self.cdist_object.path, self.parameters)) def __init_log(self): """Setup logging facility""" @@ -98,30 +101,38 @@ class Emulator(object): else: logging.root.setLevel(logging.INFO) - self.log = logging.getLogger(self.target_host) + self.log = logging.getLogger(self.target_host) def commandline(self): """Parse command line""" - parser = argparse.ArgumentParser(add_help=False, argument_default=argparse.SUPPRESS) + parser = argparse.ArgumentParser(add_help=False, + argument_default=argparse.SUPPRESS) for parameter in self.cdist_type.required_parameters: argument = "--" + parameter - parser.add_argument(argument, dest=parameter, action='store', required=True) + parser.add_argument(argument, dest=parameter, action='store', + required=True) for parameter in self.cdist_type.required_multiple_parameters: argument = "--" + parameter - parser.add_argument(argument, dest=parameter, action='append', required=True) + parser.add_argument(argument, dest=parameter, action='append', + required=True) for parameter in self.cdist_type.optional_parameters: argument = "--" + parameter - parser.add_argument(argument, dest=parameter, action='store', required=False, - default=self.cdist_type.parameter_defaults.get(parameter, None)) + default = self.cdist_type.parameter_defaults.get(parameter, None) + parser.add_argument(argument, dest=parameter, action='store', + required=False, default=default) for parameter in self.cdist_type.optional_multiple_parameters: argument = "--" + parameter - parser.add_argument(argument, dest=parameter, action='append', required=False, - default=DefaultList.create(self.cdist_type.parameter_defaults.get(parameter, None))) + default = DefaultList.create( + self.cdist_type.parameter_defaults.get( + parameter, None)) + parser.add_argument(argument, dest=parameter, action='append', + required=False, default=default) for parameter in self.cdist_type.boolean_parameters: argument = "--" + parameter - parser.add_argument(argument, dest=parameter, action='store_const', const='') + parser.add_argument(argument, dest=parameter, + action='store_const', const='') # If not singleton support one positional parameter if not self.cdist_type.is_singleton: @@ -140,30 +151,33 @@ class Emulator(object): del self.args.object_id # Instantiate the cdist object we are defining - self.cdist_object = core.CdistObject(self.cdist_type, - self.object_base_path, self.object_marker, self.object_id) + self.cdist_object = core.CdistObject( + self.cdist_type, self.object_base_path, self.object_marker, + self.object_id) # Create object with given parameters self.parameters = {} - for key,value in vars(self.args).items(): + for key, value in vars(self.args).items(): if value is not None: self.parameters[key] = value - if self.cdist_object.exists and not 'CDIST_OVERRIDE' in self.env: + if self.cdist_object.exists and 'CDIST_OVERRIDE' not in self.env: # make existing requirements a set, so we can compare it # later with new requirements if self.cdist_object.parameters != self.parameters: errmsg = ("Object %s already exists with conflicting " - "parameters:\n%s: %s\n%s: %s" % (self.cdist_object.name, - " ".join(self.cdist_object.source), - self.cdist_object.parameters, - self.object_source, - self.parameters)) + "parameters:\n%s: %s\n%s: %s" % ( + self.cdist_object.name, + " ".join(self.cdist_object.source), + self.cdist_object.parameters, + self.object_source, + self.parameters)) self.log.error(errmsg) raise cdist.Error(errmsg) else: if self.cdist_object.exists: - self.log.debug('Object %s override forced with CDIST_OVERRIDE',self.cdist_object.name) + self.log.debug(('Object %s override forced with ' + 'CDIST_OVERRIDE'), self.cdist_object.name) self.cdist_object.create(True) else: self.cdist_object.create() @@ -176,6 +190,7 @@ class Emulator(object): self.cdist_object.source.append(self.object_source) chunk_size = 65536 + def _read_stdin(self): return self.stdin.read(self.chunk_size) @@ -197,7 +212,6 @@ class Emulator(object): except EnvironmentError as e: raise cdist.Error('Failed to read from stdin: %s' % e) - def record_requirement(self, requirement): """record requirement and return recorded requirement""" @@ -206,13 +220,15 @@ class Emulator(object): cdist_object = self.cdist_object.object_from_name(requirement) except core.cdist_type.NoSuchTypeError as e: self.log.error(("%s requires object %s, but type %s does not" - " exist. Defined at %s" % (self.cdist_object.name, - requirement, e.name, self.object_source))) + " exist. Defined at %s" % ( + self.cdist_object.name, + requirement, e.name, self.object_source))) raise except core.cdist_object.MissingObjectIdError as e: self.log.error(("%s requires object %s without object id." - " Defined at %s" % (self.cdist_object.name, requirement, - self.object_source))) + " Defined at %s" % (self.cdist_object.name, + requirement, + self.object_source))) raise self.log.debug("Recording requirement: %s", requirement) @@ -224,12 +240,13 @@ class Emulator(object): return cdist_object.name - def record_requirements(self): """record requirements""" - # Inject the predecessor, but not if its an override (this would leed to an circular dependency) - if "CDIST_ORDER_DEPENDENCY" in self.env and not 'CDIST_OVERRIDE' in self.env: + # Inject the predecessor, but not if its an override + # (this would leed to an circular dependency) + if ("CDIST_ORDER_DEPENDENCY" in self.env and + 'CDIST_OVERRIDE' not in self.env): # load object name created bevor this one from typeorder file ... with open(self.typeorder_path, 'r') as typecreationfile: typecreationorder = typecreationfile.readlines() @@ -240,9 +257,12 @@ class Emulator(object): self.env['require'] += " " + lastcreatedtype else: self.env['require'] = lastcreatedtype - self.log.debug("Injecting require for CDIST_ORDER_DEPENDENCY: %s for %s", lastcreatedtype, self.cdist_object.name) + self.log.debug(("Injecting require for " + "CDIST_ORDER_DEPENDENCY: %s for %s"), + lastcreatedtype, self.cdist_object.name) except IndexError: - # if no second last line, we are on the first type, so do not set a requirement + # if no second last line, we are on the first type, + # so do not set a requirement pass if "require" in self.env: @@ -250,22 +270,25 @@ class Emulator(object): self.log.debug("reqs = " + requirements) for requirement in requirements.split(" "): # Ignore empty fields - probably the only field anyway - if len(requirement) == 0: continue + if len(requirement) == 0: + continue self.record_requirement(requirement) - def record_auto_requirements(self): - """An object shall automatically depend on all objects that it defined in it's type manifest. + """An object shall automatically depend on all objects that it + defined in it's type manifest. """ - # __object_name is the name of the object whose type manifest is currently executed + # __object_name is the name of the object whose type manifest is + # currently executed __object_name = self.env.get('__object_name', None) if __object_name: # The object whose type manifest is currently run parent = self.cdist_object.object_from_name(__object_name) # The object currently being defined current_object = self.cdist_object - # As parent defined current_object it shall automatically depend on it. + # As parent defined current_object it shall automatically + # depend on it. # But only if the user hasn't said otherwise. # Must prevent circular dependencies. - if not parent.name in current_object.requirements: + if parent.name not in current_object.requirements: parent.autorequire.append(current_object.name) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 5a0a8644..48067543 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -35,7 +35,8 @@ import cdist.message from cdist import core import cdist.exec.util as exec_util -CONF_SUBDIRS_LINKED = [ "explorer", "files", "manifest", "type" ] +CONF_SUBDIRS_LINKED = ["explorer", "files", "manifest", "type", ] + class Local(object): """Execute commands locally. @@ -82,7 +83,8 @@ class Local(object): @property def dist_conf_dir(self): - return os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")) + return os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), + "conf")) @property def home_dir(self): @@ -109,7 +111,8 @@ class Local(object): # Depending on out_path self.bin_path = os.path.join(self.base_path, "bin") self.conf_path = os.path.join(self.base_path, "conf") - self.global_explorer_out_path = os.path.join(self.base_path, "explorer") + self.global_explorer_out_path = os.path.join(self.base_path, + "explorer") self.object_path = os.path.join(self.base_path, "object") self.messages_path = os.path.join(self.base_path, "messages") self.files_path = os.path.join(self.conf_path, "files") @@ -118,7 +121,7 @@ class Local(object): self.global_explorer_path = os.path.join(self.conf_path, "explorer") self.manifest_path = os.path.join(self.conf_path, "manifest") self.initial_manifest = (self.custom_initial_manifest or - os.path.join(self.manifest_path, "init")) + os.path.join(self.manifest_path, "init")) self.type_path = os.path.join(self.conf_path, "type") @@ -164,8 +167,8 @@ class Local(object): with open(self.object_marker_file, 'w') as fd: fd.write("%s\n" % self.object_marker_name) - self.log.debug("Object marker %s saved in %s" % (self.object_marker_name, self.object_marker_file)) - + self.log.debug("Object marker %s saved in %s" % ( + self.object_marker_name, self.object_marker_file)) def _init_cache_dir(self, cache_dir): if cache_dir: @@ -174,7 +177,8 @@ class Local(object): if self.home_dir: self.cache_path = os.path.join(self.home_dir, "cache") else: - raise cdist.Error("No homedir setup and no cache dir location given") + raise cdist.Error( + "No homedir setup and no cache dir location given") def rmdir(self, path): """Remove directory on the local side.""" @@ -192,7 +196,8 @@ class Local(object): """ self.log.debug("Local run: %s", command) - assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command + assert isinstance(command, (list, tuple)), ( + "list or tuple argument expected, got: %s" % command) if env is None: env = os.environ.copy() @@ -220,16 +225,17 @@ class Local(object): if message_prefix: message.merge_messages() - def run_script(self, script, env=None, return_output=False, message_prefix=None): + def run_script(self, script, env=None, return_output=False, + message_prefix=None): """Run the given script with the given environment. Return the output as a string. """ - command = [ os.environ.get('CDIST_LOCAL_SHELL',"/bin/sh") , "-e"] + command = [os.environ.get('CDIST_LOCAL_SHELL', "/bin/sh"), "-e"] command.append(script) - return self.run(command=command, env=env, return_output=return_output, message_prefix=message_prefix) - + return self.run(command=command, env=env, return_output=return_output, + message_prefix=message_prefix) def save_cache(self): destination = os.path.join(self.cache_path, self.hostdir) @@ -239,7 +245,8 @@ class Local(object): if os.path.exists(destination): shutil.rmtree(destination) except PermissionError as e: - raise cdist.Error("Cannot delete old cache %s: %s" % (destination, e)) + raise cdist.Error( + "Cannot delete old cache %s: %s" % (destination, e)) shutil.move(self.base_path, destination) @@ -265,18 +272,21 @@ class Local(object): for entry in os.listdir(current_dir): rel_entry_path = os.path.join(sub_dir, entry) - src = os.path.abspath(os.path.join(conf_dir, sub_dir, entry)) + src = os.path.abspath(os.path.join(conf_dir, + sub_dir, + entry)) dst = os.path.join(self.conf_path, sub_dir, entry) # Already exists? remove and link if os.path.exists(dst): os.unlink(dst) - + self.log.debug("Linking %s to %s ..." % (src, dst)) try: os.symlink(src, dst) except OSError as e: - raise cdist.Error("Linking %s %s to %s failed: %s" % (sub_dir, src, dst, e.__str__())) + raise cdist.Error("Linking %s %s to %s failed: %s" % ( + sub_dir, src, dst, e.__str__())) def _link_types_for_emulator(self): """Link emulator to types""" @@ -288,4 +298,6 @@ class Local(object): try: os.symlink(src, dst) except OSError as e: - raise cdist.Error("Linking emulator from %s to %s failed: %s" % (src, dst, e.__str__())) + raise cdist.Error( + "Linking emulator from %s to %s failed: %s" % ( + src, dst, e.__str__())) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 0331f402..ff388e1d 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -30,6 +30,7 @@ import cdist.exec.util as exec_util import cdist + class DecodeError(cdist.Error): def __init__(self, command): self.command = command @@ -75,7 +76,6 @@ class Remote(object): os.environ['__remote_copy'] = self._copy os.environ['__remote_exec'] = self._exec - def create_files_dirs(self): self.rmdir(self.base_path) self.mkdir(self.base_path) @@ -101,11 +101,13 @@ class Remote(object): for f in glob.glob1(source, '*'): command = self._copy.split() path = os.path.join(source, f) - command.extend([path, '{0}:{1}'.format(self.target_host, destination)]) + command.extend([path, '{0}:{1}'.format( + self.target_host, destination)]) self._run_command(command) else: command = self._copy.split() - command.extend([source, '{0}:{1}'.format(self.target_host, destination)]) + command.extend([source, '{0}:{1}'.format( + self.target_host, destination)]) self._run_command(command) def run_script(self, script, env=None, return_output=False): @@ -114,7 +116,7 @@ class Remote(object): """ - command = [ os.environ.get('CDIST_REMOTE_SHELL',"/bin/sh") , "-e"] + command = [os.environ.get('CDIST_REMOTE_SHELL', "/bin/sh"), "-e"] command.append(script) return self.run(command, env, return_output) @@ -148,8 +150,8 @@ class Remote(object): # /bin/csh will execute this script in the right way. if env: remote_env = [" export %s=%s;" % item for item in env.items()] - string_cmd = ("/bin/sh -c '" + " ".join(remote_env) - + " ".join(command) + "'") + string_cmd = ("/bin/sh -c '" + " ".join(remote_env) + + " ".join(command) + "'") cmd.append(string_cmd) else: cmd.extend(command) @@ -160,7 +162,8 @@ class Remote(object): Return the output as a string. """ - assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command + assert isinstance(command, (list, tuple)), ( + "list or tuple argument expected, got: %s" % command) # export target_host for use in __remote_{exec,copy} scripts os_environ = os.environ.copy() diff --git a/cdist/exec/util.py b/cdist/exec/util.py index 15430f13..a1bca296 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -27,6 +27,7 @@ import cdist STDERR_UNSUPPORTED = 'Not supported in this python version' + def call_get_output(command, env=None): """Run the given command with the given environment. Return the tuple of stdout and stderr output as a byte strings. @@ -40,14 +41,16 @@ def call_get_output(command, env=None): else: return (call_get_stdout(command, env), STDERR_UNSUPPORTED) + def handle_called_process_error(err, command): if sys.version_info >= (3, 5): errout = err.stderr else: errout = STDERR_UNSUPPORTED - raise cdist.Error("Command failed: " + " ".join(command) - + " with returncode: {} and stdout: {}, stderr: {}".format( - err.returncode, err.output, errout)) + raise cdist.Error("Command failed: " + " ".join(command) + + " with returncode: {} and stdout: {}, stderr: {}".format( + err.returncode, err.output, errout)) + def call_get_stdout(command, env=None): """Run the given command with the given environment. @@ -63,6 +66,7 @@ def call_get_stdout(command, env=None): return output + def call_get_out_err(command, env=None): """Run the given command with the given environment. Return the tuple of stdout and stderr output as a byte strings. @@ -72,7 +76,7 @@ def call_get_out_err(command, env=None): with TemporaryFile() as fout, TemporaryFile() as ferr: subprocess.check_call(command, env=env, - stdout=fout, stderr=ferr) + stdout=fout, stderr=ferr) fout.seek(0) ferr.seek(0) output = (fout.read(), ferr.read()) diff --git a/cdist/log.py b/cdist/log.py index 8c3aac79..2341c282 100644 --- a/cdist/log.py +++ b/cdist/log.py @@ -22,6 +22,7 @@ import logging + class Log(logging.Logger): def __init__(self, name): diff --git a/cdist/message.py b/cdist/message.py index f9b0c313..98a6e8cf 100644 --- a/cdist/message.py +++ b/cdist/message.py @@ -37,8 +37,9 @@ class Message(object): self.prefix = prefix self.global_messages = messages - in_fd, self.messages_in = tempfile.mkstemp(suffix='.cdist_message_in') - out_fd, self.messages_out = tempfile.mkstemp(suffix='.cdist_message_out') + in_fd, self.messages_in = tempfile.mkstemp(suffix='.cdist_message_in') + out_fd, self.messages_out = tempfile.mkstemp( + suffix='.cdist_message_out') os.close(in_fd) os.close(out_fd) @@ -48,7 +49,7 @@ class Message(object): @property def env(self): env = {} - env['__messages_in'] = self.messages_in + env['__messages_in'] = self.messages_in env['__messages_out'] = self.messages_out return env diff --git a/cdist/shell.py b/cdist/shell.py index 83b2acf7..60faa2f8 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -31,8 +31,9 @@ import cdist.config log = logging.getLogger(__name__) + class Shell(object): - + def __init__(self, shell=None): self.shell = shell @@ -45,16 +46,17 @@ class Shell(object): """Select shell to execute, if not specified by user""" if not self.shell: - self.shell = os.environ.get('SHELL',"/bin/sh") + self.shell = os.environ.get('SHELL', "/bin/sh") def _init_files_dirs(self): self.local.create_files_dirs() def _init_environment(self): self.env = os.environ.copy() - additional_env = { + additional_env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), - '__cdist_type_base_path': self.local.type_path, # for use in type emulator + # for use in type emulator + '__cdist_type_base_path': self.local.type_path, '__cdist_manifest': "cdist shell", '__global': self.local.base_path, '__target_host': self.target_host, diff --git a/cdist/sphinxext/manpage.py b/cdist/sphinxext/manpage.py index 433f6a1b..97b41f03 100644 --- a/cdist/sphinxext/manpage.py +++ b/cdist/sphinxext/manpage.py @@ -14,12 +14,13 @@ from sphinx import addnodes but leaves everything to actual reStructuredText file content. """ + class ManualPageTranslator(sphinx.writers.manpage.ManualPageTranslator): - def header(self): - tmpl = (".TH \"%(title_upper)s\" \"%(manual_section)s\"" - " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n") - return tmpl % self._docinfo + def header(self): + tmpl = (".TH \"%(title_upper)s\" \"%(manual_section)s\"" + " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n") + return tmpl % self._docinfo class ManualPageWriter(sphinx.writers.manpage.ManualPageWriter): @@ -76,5 +77,6 @@ class ManualPageBuilder(sphinx.builders.manpage.ManualPageBuilder): docwriter.write(largetree, destination) self.info() + def setup(app): app.add_builder(ManualPageBuilder) diff --git a/cdist/test/__init__.py b/cdist/test/__init__.py index ab767699..d9630f53 100644 --- a/cdist/test/__init__.py +++ b/cdist/test/__init__.py @@ -28,7 +28,9 @@ cdist_base_path = os.path.abspath( cdist_exec_path = os.path.join(cdist_base_path, "scripts/cdist") -global_fixtures_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "fixtures")) +global_fixtures_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), + "fixtures")) + class CdistTestCase(unittest.TestCase): diff --git a/cdist/test/banner/__init__.py b/cdist/test/banner/__init__.py index 4b0ab6ac..957b7b12 100644 --- a/cdist/test/banner/__init__.py +++ b/cdist/test/banner/__init__.py @@ -27,6 +27,7 @@ import unittest import cdist import cdist.banner + class Banner(unittest.TestCase): def setUp(self): self.banner = cdist.BANNER + "\n" @@ -38,5 +39,5 @@ class Banner(unittest.TestCase): sys.stdout = output cdist.banner.banner(None) - + self.assertEqual(output.getvalue(), self.banner) diff --git a/cdist/test/cdist_object/__init__.py b/cdist/test/cdist_object/__init__.py index 9c075acb..d03c0642 100644 --- a/cdist/test/cdist_object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -57,29 +57,37 @@ class ObjectClassTestCase(test.CdistTestCase): self.expected_objects = [] for cdist_object_name in expected_object_names: cdist_type, cdist_object_id = cdist_object_name.split("/", 1) - cdist_object = core.CdistObject(core.CdistType(type_base_path, cdist_type), self.object_base_path, - OBJECT_MARKER_NAME, cdist_object_id) + cdist_object = core.CdistObject(core.CdistType(type_base_path, + cdist_type), + self.object_base_path, + OBJECT_MARKER_NAME, + cdist_object_id) cdist_object.create() self.expected_objects.append(cdist_object) - + def tearDown(self): shutil.rmtree(self.tempdir) def test_list_object_names(self): - found_object_names = sorted(list(core.CdistObject.list_object_names(self.object_base_path, OBJECT_MARKER_NAME))) - self.assertEqual(found_object_names, expected_object_names) + found_object_names = sorted(list(core.CdistObject.list_object_names( + self.object_base_path, OBJECT_MARKER_NAME))) + self.assertEqual(found_object_names, expected_object_names) def test_list_type_names(self): - type_names = list(cdist.core.CdistObject.list_type_names(self.object_base_path)) - self.assertEqual(sorted(type_names), ['__first', '__second', '__third']) + type_names = list(cdist.core.CdistObject.list_type_names( + self.object_base_path)) + self.assertEqual(sorted(type_names), + ['__first', '__second', '__third']) def test_list_objects(self): - found_objects = sorted(list(core.CdistObject.list_objects(self.object_base_path, type_base_path, OBJECT_MARKER_NAME))) + found_objects = sorted(list(core.CdistObject.list_objects( + self.object_base_path, type_base_path, OBJECT_MARKER_NAME))) self.assertEqual(found_objects, self.expected_objects) def test_create_singleton(self): """Check whether creating an object without id (singleton) works""" - singleton = self.expected_objects[0].object_from_name("__test_singleton") + singleton = self.expected_objects[0].object_from_name( + "__test_singleton") # came here - everything fine def test_create_singleton_not_singleton_type(self): @@ -88,6 +96,7 @@ class ObjectClassTestCase(test.CdistTestCase): with self.assertRaises(cdist.core.cdist_object.MissingObjectIdError): self.expected_objects[0].object_from_name("__first") + class ObjectIdTestCase(test.CdistTestCase): def setUp(self): @@ -97,11 +106,14 @@ class ObjectIdTestCase(test.CdistTestCase): self.expected_objects = [] for cdist_object_name in expected_object_names: cdist_type, cdist_object_id = cdist_object_name.split("/", 1) - cdist_object = core.CdistObject(core.CdistType(type_base_path, cdist_type), self.object_base_path, - OBJECT_MARKER_NAME, cdist_object_id) + cdist_object = core.CdistObject(core.CdistType(type_base_path, + cdist_type), + self.object_base_path, + OBJECT_MARKER_NAME, + cdist_object_id) cdist_object.create() self.expected_objects.append(cdist_object) - + def tearDown(self): shutil.rmtree(self.tempdir) @@ -109,31 +121,39 @@ class ObjectIdTestCase(test.CdistTestCase): cdist_type = core.CdistType(type_base_path, '__third') illegal_object_id = '/object_id//may/not/contain/double/slash' with self.assertRaises(core.IllegalObjectIdError): - core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) + core.CdistObject(cdist_type, self.object_base_path, + OBJECT_MARKER_NAME, illegal_object_id) def test_object_id_contains_object_marker(self): cdist_type = core.CdistType(type_base_path, '__third') - illegal_object_id = 'object_id/may/not/contain/%s/anywhere' % OBJECT_MARKER_NAME + illegal_object_id = ( + 'object_id/may/not/contain/%s/anywhere' % OBJECT_MARKER_NAME) with self.assertRaises(core.IllegalObjectIdError): - core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) + core.CdistObject(cdist_type, self.object_base_path, + OBJECT_MARKER_NAME, illegal_object_id) def test_object_id_contains_object_marker_string(self): cdist_type = core.CdistType(type_base_path, '__third') - illegal_object_id = 'object_id/may/contain_%s_in_filename' % OBJECT_MARKER_NAME - core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) + illegal_object_id = ( + 'object_id/may/contain_%s_in_filename' % OBJECT_MARKER_NAME) + core.CdistObject(cdist_type, self.object_base_path, + OBJECT_MARKER_NAME, illegal_object_id) # if we get here, the test passed def test_object_id_contains_only_dot(self): cdist_type = core.CdistType(type_base_path, '__third') illegal_object_id = '.' with self.assertRaises(core.IllegalObjectIdError): - core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) + core.CdistObject(cdist_type, self.object_base_path, + OBJECT_MARKER_NAME, illegal_object_id) def test_object_id_on_singleton_type(self): cdist_type = core.CdistType(type_base_path, '__test_singleton') illegal_object_id = 'object_id' with self.assertRaises(core.IllegalObjectIdError): - core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) + core.CdistObject(cdist_type, self.object_base_path, + OBJECT_MARKER_NAME, illegal_object_id) + class ObjectTestCase(test.CdistTestCase): @@ -142,13 +162,14 @@ class ObjectTestCase(test.CdistTestCase): self.object_base_path = self.tempdir self.cdist_type = core.CdistType(type_base_path, '__third') - self.cdist_object = core.CdistObject(self.cdist_type, self.object_base_path, OBJECT_MARKER_NAME, 'moon') + self.cdist_object = core.CdistObject(self.cdist_type, + self.object_base_path, + OBJECT_MARKER_NAME, 'moon') self.cdist_object.create() self.cdist_object.parameters['planet'] = 'Saturn' self.cdist_object.parameters['name'] = 'Prometheus' - def tearDown(self): self.cdist_object.prepared = False self.cdist_object.ran = False @@ -166,22 +187,29 @@ class ObjectTestCase(test.CdistTestCase): self.assertEqual(self.cdist_object.object_id, 'moon') def test_path(self): - self.assertEqual(self.cdist_object.path, "__third/moon/%s" % OBJECT_MARKER_NAME) + self.assertEqual(self.cdist_object.path, + "__third/moon/%s" % OBJECT_MARKER_NAME) def test_absolute_path(self): - self.assertEqual(self.cdist_object.absolute_path, os.path.join(self.object_base_path, "__third/moon/%s" % OBJECT_MARKER_NAME)) + self.assertEqual(self.cdist_object.absolute_path, + os.path.join(self.object_base_path, + "__third/moon/%s" % OBJECT_MARKER_NAME)) def test_code_local_path(self): - self.assertEqual(self.cdist_object.code_local_path, "__third/moon/%s/code-local" % OBJECT_MARKER_NAME) + self.assertEqual(self.cdist_object.code_local_path, + "__third/moon/%s/code-local" % OBJECT_MARKER_NAME) def test_code_remote_path(self): - self.assertEqual(self.cdist_object.code_remote_path, "__third/moon/%s/code-remote" % OBJECT_MARKER_NAME) + self.assertEqual(self.cdist_object.code_remote_path, + "__third/moon/%s/code-remote" % OBJECT_MARKER_NAME) def test_parameter_path(self): - self.assertEqual(self.cdist_object.parameter_path, "__third/moon/%s/parameter" % OBJECT_MARKER_NAME) + self.assertEqual(self.cdist_object.parameter_path, + "__third/moon/%s/parameter" % OBJECT_MARKER_NAME) def test_explorer_path(self): - self.assertEqual(self.cdist_object.explorer_path, "__third/moon/%s/explorer" % OBJECT_MARKER_NAME) + self.assertEqual(self.cdist_object.explorer_path, + "__third/moon/%s/explorer" % OBJECT_MARKER_NAME) def test_parameters(self): expected_parameters = {'planet': 'Saturn', 'name': 'Prometheus'} @@ -190,32 +218,39 @@ class ObjectTestCase(test.CdistTestCase): def test_explorers(self): self.assertEqual(self.cdist_object.explorers, {}) - # FIXME: actually testing fsproperty.DirectoryDictProperty here, move to their own test case + # FIXME: actually testing fsproperty.DirectoryDictProperty here, + # move to their own test case def test_explorers_assign_dict(self): expected = {'first': 'foo', 'second': 'bar'} # when set, written to file self.cdist_object.explorers = expected - object_explorer_path = os.path.join(self.cdist_object.base_path, self.cdist_object.explorer_path) + object_explorer_path = os.path.join(self.cdist_object.base_path, + self.cdist_object.explorer_path) self.assertTrue(os.path.isdir(object_explorer_path)) # when accessed, read from file self.assertEqual(self.cdist_object.explorers, expected) # remove dynamically created folder self.cdist_object.explorers = {} - os.rmdir(os.path.join(self.cdist_object.base_path, self.cdist_object.explorer_path)) + os.rmdir(os.path.join(self.cdist_object.base_path, + self.cdist_object.explorer_path)) - # FIXME: actually testing fsproperty.DirectoryDictProperty here, move to their own test case + # FIXME: actually testing fsproperty.DirectoryDictProperty here, + # move to their own test case def test_explorers_assign_key_value(self): expected = {'first': 'foo', 'second': 'bar'} - object_explorer_path = os.path.join(self.cdist_object.base_path, self.cdist_object.explorer_path) - for key,value in expected.items(): + object_explorer_path = os.path.join(self.cdist_object.base_path, + self.cdist_object.explorer_path) + for key, value in expected.items(): # when set, written to file self.cdist_object.explorers[key] = value - self.assertTrue(os.path.isfile(os.path.join(object_explorer_path, key))) + self.assertTrue(os.path.isfile(os.path.join(object_explorer_path, + key))) # when accessed, read from file self.assertEqual(self.cdist_object.explorers, expected) # remove dynamically created folder self.cdist_object.explorers = {} - os.rmdir(os.path.join(self.cdist_object.base_path, self.cdist_object.explorer_path)) + os.rmdir(os.path.join(self.cdist_object.base_path, + self.cdist_object.explorer_path)) def test_requirements(self): expected = [] @@ -226,15 +261,18 @@ class ObjectTestCase(test.CdistTestCase): def test_state_prepared(self): self.cdist_object.state = core.CdistObject.STATE_PREPARED - self.assertEqual(self.cdist_object.state, core.CdistObject.STATE_PREPARED) + self.assertEqual(self.cdist_object.state, + core.CdistObject.STATE_PREPARED) def test_state_running(self): self.cdist_object.state = core.CdistObject.STATE_RUNNING - self.assertEqual(self.cdist_object.state, core.CdistObject.STATE_RUNNING) + self.assertEqual(self.cdist_object.state, + core.CdistObject.STATE_RUNNING) def test_state_done(self): self.cdist_object.state = core.CdistObject.STATE_DONE - self.assertEqual(self.cdist_object.state, core.CdistObject.STATE_DONE) + self.assertEqual(self.cdist_object.state, + core.CdistObject.STATE_DONE) def test_source(self): self.assertEqual(list(self.cdist_object.source), []) diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index ccbf6742..feb5fa15 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -34,7 +34,8 @@ class TypeTestCase(test.CdistTestCase): def test_list_type_names(self): base_path = op.join(fixtures, 'list_types') type_names = core.CdistType.list_type_names(base_path) - self.assertEqual(sorted(type_names), ['__first', '__second', '__third']) + self.assertEqual(sorted(type_names), + ['__first', '__second', '__third']) def test_list_types(self): base_path = op.join(fixtures, 'list_types') @@ -54,7 +55,8 @@ class TypeTestCase(test.CdistTestCase): def test_nonexistent_type(self): base_path = fixtures - self.assertRaises(core.NoSuchTypeError, core.CdistType, base_path, '__i-dont-exist') + self.assertRaises(core.NoSuchTypeError, core.CdistType, base_path, + '__i-dont-exist') def test_name(self): base_path = fixtures @@ -74,27 +76,32 @@ class TypeTestCase(test.CdistTestCase): def test_absolute_path(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__name_path') - self.assertEqual(cdist_type.absolute_path, os.path.join(base_path, '__name_path')) + self.assertEqual(cdist_type.absolute_path, + os.path.join(base_path, '__name_path')) def test_manifest_path(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__name_path') - self.assertEqual(cdist_type.manifest_path, os.path.join('__name_path', 'manifest')) + self.assertEqual(cdist_type.manifest_path, + os.path.join('__name_path', 'manifest')) def test_explorer_path(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__name_path') - self.assertEqual(cdist_type.explorer_path, os.path.join('__name_path', 'explorer')) + self.assertEqual(cdist_type.explorer_path, + os.path.join('__name_path', 'explorer')) def test_gencode_local_path(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__name_path') - self.assertEqual(cdist_type.gencode_local_path, os.path.join('__name_path', 'gencode-local')) + self.assertEqual(cdist_type.gencode_local_path, + os.path.join('__name_path', 'gencode-local')) def test_gencode_remote_path(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__name_path') - self.assertEqual(cdist_type.gencode_remote_path, os.path.join('__name_path', 'gencode-remote')) + self.assertEqual(cdist_type.gencode_remote_path, + os.path.join('__name_path', 'gencode-remote')) def test_singleton_is_singleton(self): base_path = fixtures @@ -119,17 +126,20 @@ class TypeTestCase(test.CdistTestCase): def test_with_required_parameters(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__with_required_parameters') - self.assertEqual(cdist_type.required_parameters, ['required1', 'required2']) + self.assertEqual(cdist_type.required_parameters, + ['required1', 'required2']) def test_without_required_parameters(self): base_path = fixtures - cdist_type = core.CdistType(base_path, '__without_required_parameters') + cdist_type = core.CdistType(base_path, + '__without_required_parameters') self.assertEqual(cdist_type.required_parameters, []) def test_with_optional_parameters(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__with_optional_parameters') - self.assertEqual(cdist_type.optional_parameters, ['optional1', 'optional2']) + self.assertEqual(cdist_type.optional_parameters, + ['optional1', 'optional2']) def test_without_optional_parameters(self): base_path = fixtures @@ -139,7 +149,8 @@ class TypeTestCase(test.CdistTestCase): def test_with_boolean_parameters(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__with_boolean_parameters') - self.assertEqual(cdist_type.boolean_parameters, ['boolean1', 'boolean2']) + self.assertEqual(cdist_type.boolean_parameters, + ['boolean1', 'boolean2']) def test_without_boolean_parameters(self): base_path = fixtures @@ -158,5 +169,4 @@ class TypeTestCase(test.CdistTestCase): cdist_type = core.CdistType(base_path, '__directory_in_default') self.assertEqual( list(sorted(cdist_type.parameter_defaults.keys())), - ['bar', 'foo'] - ) + ['bar', 'foo']) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 811d3a33..7ec9e3c4 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -36,15 +36,16 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') conf_dir = op.join(fixtures, 'conf') + class CodeTestCase(test.CdistTestCase): def setUp(self): self.local_dir = self.mkdtemp() self.local = local.Local( - target_host=self.target_host, - base_path = self.local_dir, - exec_path = cdist.test.cdist_exec_path, + target_host=self.target_host, + base_path=self.local_dir, + exec_path=cdist.test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -52,16 +53,19 @@ class CodeTestCase(test.CdistTestCase): remote_exec = self.remote_exec remote_copy = self.remote_copy self.remote = remote.Remote( - target_host=self.target_host, - remote_exec=remote_exec, + target_host=self.target_host, + remote_exec=remote_exec, remote_copy=remote_copy, base_path=self.remote_dir) self.remote.create_files_dirs() self.code = code.Code(self.target_host, self.local, self.remote) - self.cdist_type = core.CdistType(self.local.type_path, '__dump_environment') - self.cdist_object = core.CdistObject(self.cdist_type, self.local.object_path, 'whatever', self.local.object_marker_name) + self.cdist_type = core.CdistType(self.local.type_path, + '__dump_environment') + self.cdist_object = core.CdistObject( + self.cdist_type, self.local.object_path, 'whatever', + self.local.object_marker_name) self.cdist_object.create() def tearDown(self): @@ -73,14 +77,16 @@ class CodeTestCase(test.CdistTestCase): output_dict = {} for line in output_string.split('\n'): if line: - junk,value = line.split(': ') + junk, value = line.split(': ') key = junk.split(' ')[1] output_dict[key] = value self.assertEqual(output_dict['__target_host'], self.local.target_host) self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) - self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) - self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) + self.assertEqual(output_dict['__object'], + self.cdist_object.absolute_path) + self.assertEqual(output_dict['__object_id'], + self.cdist_object.object_id) self.assertEqual(output_dict['__object_name'], self.cdist_object.name) self.assertEqual(output_dict['__files'], self.local.files_path) @@ -89,29 +95,35 @@ class CodeTestCase(test.CdistTestCase): output_dict = {} for line in output_string.split('\n'): if line: - junk,value = line.split(': ') + junk, value = line.split(': ') key = junk.split(' ')[1] output_dict[key] = value self.assertEqual(output_dict['__target_host'], self.local.target_host) self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) - self.assertEqual(output_dict['__object'], self.cdist_object.absolute_path) - self.assertEqual(output_dict['__object_id'], self.cdist_object.object_id) + self.assertEqual(output_dict['__object'], + self.cdist_object.absolute_path) + self.assertEqual(output_dict['__object_id'], + self.cdist_object.object_id) self.assertEqual(output_dict['__object_name'], self.cdist_object.name) self.assertEqual(output_dict['__files'], self.local.files_path) def test_transfer_code_remote(self): - self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) + self.cdist_object.code_remote = self.code.run_gencode_remote( + self.cdist_object) self.code.transfer_code_remote(self.cdist_object) - destination = os.path.join(self.remote.object_path, self.cdist_object.code_remote_path) + destination = os.path.join(self.remote.object_path, + self.cdist_object.code_remote_path) self.assertTrue(os.path.isfile(destination)) def test_run_code_local(self): - self.cdist_object.code_local = self.code.run_gencode_local(self.cdist_object) + self.cdist_object.code_local = self.code.run_gencode_local( + self.cdist_object) self.code.run_code_local(self.cdist_object) def test_run_code_remote_environment(self): - self.cdist_object.code_remote = self.code.run_gencode_remote(self.cdist_object) + self.cdist_object.code_remote = self.code.run_gencode_remote( + self.cdist_object) self.code.transfer_code_remote(self.cdist_object) self.code.run_code_remote(self.cdist_object) diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index a36567de..3fd415fd 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -44,6 +44,7 @@ expected_object_names = sorted([ '__second/on-the', '__third/moon']) + class ConfigRunTestCase(test.CdistTestCase): def setUp(self): @@ -65,8 +66,11 @@ class ConfigRunTestCase(test.CdistTestCase): self.objects = [] for cdist_object_name in expected_object_names: cdist_type, cdist_object_id = cdist_object_name.split("/", 1) - cdist_object = core.CdistObject(core.CdistType(type_base_path, cdist_type), self.object_base_path, - self.local.object_marker_name, cdist_object_id) + cdist_object = core.CdistObject(core.CdistType(type_base_path, + cdist_type), + self.object_base_path, + self.local.object_marker_name, + cdist_object_id) cdist_object.create() self.objects.append(cdist_object) @@ -81,8 +85,8 @@ class ConfigRunTestCase(test.CdistTestCase): remote_exec=self.remote_exec, base_path=self.remote_dir) - self.local.object_path = self.object_base_path - self.local.type_path = type_base_path + self.local.object_path = self.object_base_path + self.local.type_path = type_base_path self.config = cdist.config.Config(self.local, self.remote) @@ -95,14 +99,14 @@ class ConfigRunTestCase(test.CdistTestCase): shutil.rmtree(self.temp_dir) def test_dependency_resolution(self): - first = self.object_index['__first/man'] - second = self.object_index['__second/on-the'] - third = self.object_index['__third/moon'] + first = self.object_index['__first/man'] + second = self.object_index['__second/on-the'] + third = self.object_index['__third/moon'] first.requirements = [second.name] second.requirements = [third.name] - # First run: + # First run: # solves first and maybe second (depending on the order in the set) self.config.iterate_once() self.assertTrue(third.state == third.STATE_DONE) @@ -110,11 +114,11 @@ class ConfigRunTestCase(test.CdistTestCase): self.config.iterate_once() self.assertTrue(second.state == second.STATE_DONE) - try: self.config.iterate_once() except cdist.Error: - # Allow failing, because the third run may or may not be unecessary already, + # Allow failing, because the third run may or may not be + # unecessary already, # depending on the order of the objects pass self.assertTrue(first.state == first.STATE_DONE) @@ -123,8 +127,8 @@ class ConfigRunTestCase(test.CdistTestCase): """Ensure an exception is thrown for unresolvable depedencies""" # Create to objects depending on each other - no solution possible - first = self.object_index['__first/man'] - second = self.object_index['__second/on-the'] + first = self.object_index['__first/man'] + second = self.object_index['__second/on-the'] first.requirements = [second.name] second.requirements = [first.name] @@ -153,21 +157,22 @@ class ConfigRunTestCase(test.CdistTestCase): with self.assertRaises(cdist.core.cdist_object.MissingObjectIdError): self.config.iterate_until_finished() - def test_dryrun(self): """Test if the dryrun option is working like expected""" drylocal = cdist.exec.local.Local( target_host=self.target_host, base_path=self.local_dir, - #exec_path can not derivated from sys.argv in case of unittest ... - exec_path=os.path.abspath(os.path.join(my_dir,'../../../scripts/cdist')), - initial_manifest=os.path.join(fixtures, 'manifest/dryrun_manifest'), - add_conf_dirs=[ fixtures ] ) + # exec_path can not derivated from sys.argv in case of unittest + exec_path=os.path.abspath(os.path.join( + my_dir, '../../../scripts/cdist')), + initial_manifest=os.path.join(fixtures, + 'manifest/dryrun_manifest'), + add_conf_dirs=[fixtures]) dryrun = cdist.config.Config(drylocal, self.remote, dry_run=True) dryrun.run() # if we are here, dryrun works like expected - + # Currently the resolving code will simply detect that this object does # not exist. It should probably check if the type is a singleton as well diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index ee6c3cea..69ca0fd9 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -40,6 +40,7 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') conf_dir = op.join(fixtures, 'conf') + class EmulatorTestCase(test.CdistTestCase): def setUp(self): @@ -68,7 +69,8 @@ class EmulatorTestCase(test.CdistTestCase): def test_nonexistent_type_exec(self): argv = ['__does-not-exist'] - self.assertRaises(core.cdist_type.NoSuchTypeError, emulator.Emulator, argv, env=self.env) + self.assertRaises(core.cdist_type.NoSuchTypeError, emulator.Emulator, + argv, env=self.env) def test_nonexistent_type_requirement(self): argv = ['__file', '/tmp/foobar'] @@ -78,7 +80,8 @@ class EmulatorTestCase(test.CdistTestCase): def test_illegal_object_id_requirement(self): argv = ['__file', '/tmp/foobar'] - self.env['require'] = "__file/bad/id/with/%s/inside" % self.local.object_marker_name + self.env['require'] = ( + "__file/bad/id/with/%s/inside") % self.local.object_marker_name emu = emulator.Emulator(argv, env=self.env) self.assertRaises(core.IllegalObjectIdError, emu.run) @@ -123,16 +126,21 @@ class EmulatorTestCase(test.CdistTestCase): emu.run() # now load the objects and verify the require parameter of the objects cdist_type = core.CdistType(self.local.type_path, '__planet') - erde_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'erde') - mars_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'mars') + erde_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, 'erde') + mars_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, 'mars') cdist_type = core.CdistType(self.local.type_path, '__file') - file_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, '/tmp/cdisttest') + file_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + '/tmp/cdisttest') # now test the recorded requirements self.assertTrue(len(erde_object.requirements) == 0) self.assertEqual(list(mars_object.requirements), ['__planet/erde']) self.assertEqual(list(file_object.requirements), ['__planet/mars']) # if we get here all is fine + class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): def setUp(self): @@ -170,7 +178,8 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, '__file') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'eggs') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, 'eggs') reqs = set(('__directory/spam',)) self.assertEqual(reqs, set(cdist_object.requirements)) @@ -189,7 +198,8 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, '__file') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'eggs') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, 'eggs') reqs = set(('__directory/spam',)) self.assertEqual(reqs, set(cdist_object.requirements)) @@ -214,7 +224,8 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, '__file') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'eggs') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, 'eggs') reqs = set(('__directory/spam', '__directory/spameggs',)) self.assertEqual(reqs, set(cdist_object.requirements)) @@ -240,11 +251,13 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): initial_manifest = os.path.join(self.local.manifest_path, "init") self.manifest.run_initial_manifest(initial_manifest) cdist_type = core.CdistType(self.local.type_path, '__saturn') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, '') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, '') self.manifest.run_type_manifest(cdist_object) expected = ['__planet/Saturn', '__moon/Prometheus'] self.assertEqual(sorted(cdist_object.autorequire), sorted(expected)) + class OverrideTestCase(test.CdistTestCase): def setUp(self): @@ -271,7 +284,7 @@ class OverrideTestCase(test.CdistTestCase): argv = ['__file', '/tmp/foobar'] emu = emulator.Emulator(argv, env=self.env) emu.run() - argv = ['__file', '/tmp/foobar','--mode','404'] + argv = ['__file', '/tmp/foobar', '--mode', '404'] emu = emulator.Emulator(argv, env=self.env) self.assertRaises(cdist.Error, emu.run) @@ -279,7 +292,7 @@ class OverrideTestCase(test.CdistTestCase): argv = ['__file', '/tmp/foobar'] emu = emulator.Emulator(argv, env=self.env) emu.run() - argv = ['__file', '/tmp/foobar','--mode','404'] + argv = ['__file', '/tmp/foobar', '--mode', '404'] self.env['CDIST_OVERRIDE'] = 'on' emu = emulator.Emulator(argv, env=self.env) emu.run() @@ -308,13 +321,17 @@ class ArgumentsTestCase(test.CdistTestCase): shutil.rmtree(self.temp_dir) def test_arguments_with_dashes(self): - argv = ['__arguments_with_dashes', 'some-id', '--with-dash', 'some value'] + argv = ['__arguments_with_dashes', 'some-id', '--with-dash', + 'some value'] os.environ.update(self.env) emu = emulator.Emulator(argv) emu.run() - cdist_type = core.CdistType(self.local.type_path, '__arguments_with_dashes') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'some-id') + cdist_type = core.CdistType(self.local.type_path, + '__arguments_with_dashes') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + 'some-id') self.assertTrue('with-dash' in cdist_object.parameters) def test_boolean(self): @@ -326,7 +343,9 @@ class ArgumentsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + object_id) self.assertTrue('boolean1' in cdist_object.parameters) self.assertFalse('boolean2' in cdist_object.parameters) # empty file -> True @@ -338,13 +357,16 @@ class ArgumentsTestCase(test.CdistTestCase): type_name = '__arguments_required' object_id = 'some-id' value = 'some value' - argv = [type_name, object_id, '--required1', value, '--required2', value] + argv = [type_name, object_id, '--required1', value, + '--required2', value] os.environ.update(self.env) emu = emulator.Emulator(argv) emu.run() cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + object_id) self.assertTrue('required1' in cdist_object.parameters) self.assertTrue('required2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['required1'], value) @@ -370,7 +392,9 @@ class ArgumentsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + object_id) self.assertTrue('optional1' in cdist_object.parameters) self.assertFalse('optional2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['optional1'], value) @@ -385,7 +409,9 @@ class ArgumentsTestCase(test.CdistTestCase): emu.run() cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + object_id) self.assertTrue('optional1' in cdist_object.parameters) self.assertFalse('optional2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['optional1'], value) @@ -437,7 +463,9 @@ class StdinTestCase(test.CdistTestCase): ###################################################################### # Create path where stdin should reside at cdist_type = core.CdistType(self.local.type_path, type_name) - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, object_id) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + object_id) stdin_out_path = os.path.join(cdist_object.absolute_path, 'stdin') ###################################################################### diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index 12a0d47b..2cd8b6db 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -39,6 +39,7 @@ conf_dir = op.join(fixtures, "conf") bin_true = "true" bin_false = "false" + class LocalTestCase(test.CdistTestCase): def setUp(self): @@ -59,43 +60,52 @@ class LocalTestCase(test.CdistTestCase): def tearDown(self): shutil.rmtree(self.temp_dir) - ### test api + # test api def test_cache_path(self): - self.assertEqual(self.local.cache_path, os.path.join(self.home_dir, "cache")) + self.assertEqual(self.local.cache_path, + os.path.join(self.home_dir, "cache")) def test_conf_path(self): - self.assertEqual(self.local.conf_path, os.path.join(self.out_path, "conf")) + self.assertEqual(self.local.conf_path, + os.path.join(self.out_path, "conf")) def test_out_path(self): self.assertEqual(self.local.base_path, self.out_path) def test_bin_path(self): - self.assertEqual(self.local.bin_path, os.path.join(self.out_path, "bin")) + self.assertEqual(self.local.bin_path, + os.path.join(self.out_path, "bin")) def test_global_explorer_out_path(self): - self.assertEqual(self.local.global_explorer_out_path, os.path.join(self.out_path, "explorer")) + self.assertEqual(self.local.global_explorer_out_path, + os.path.join(self.out_path, "explorer")) def test_object_path(self): - self.assertEqual(self.local.object_path, os.path.join(self.out_path, "object")) + self.assertEqual(self.local.object_path, + os.path.join(self.out_path, "object")) - ### /test api + # /test api - ### test internal implementation + # test internal implementation def test_global_explorer_path(self): - self.assertEqual(self.local.global_explorer_path, os.path.join(self.out_path, "conf", "explorer")) + self.assertEqual(self.local.global_explorer_path, + os.path.join(self.out_path, "conf", "explorer")) def test_manifest_path(self): - self.assertEqual(self.local.manifest_path, os.path.join(self.out_path, "conf", "manifest")) + self.assertEqual(self.local.manifest_path, + os.path.join(self.out_path, "conf", "manifest")) def test_type_path(self): - self.assertEqual(self.local.type_path, os.path.join(self.out_path, "conf", "type")) + self.assertEqual(self.local.type_path, + os.path.join(self.out_path, "conf", "type")) def test_dist_conf_dir_linking(self): - """Ensure that links are correctly created for types included in distribution""" + """Ensure that links are correctly created for types included + in distribution""" - test_type="__file" + test_type = "__file" link_test_local = local.Local( target_host='localhost', @@ -110,9 +120,10 @@ class LocalTestCase(test.CdistTestCase): self.assertTrue(os.path.isdir(our_type_dir)) def test_added_conf_dir_linking(self): - """Ensure that links are correctly created for types in added conf directories""" + """Ensure that links are correctly created for types in added conf + directories""" - test_type="__cdist_test_type" + test_type = "__cdist_test_type" link_test_local = local.Local( target_host='localhost', @@ -128,9 +139,10 @@ class LocalTestCase(test.CdistTestCase): self.assertTrue(os.path.isdir(our_type_dir)) def test_conf_dir_from_path_linking(self): - """Ensure that links are correctly created for types in conf directories which are defined in CDIST_PATH""" + """Ensure that links are correctly created for types in conf + directories which are defined in CDIST_PATH""" - test_type="__cdist_test_type" + test_type = "__cdist_test_type" os.environ['CDIST_PATH'] = conf_dir @@ -146,7 +158,7 @@ class LocalTestCase(test.CdistTestCase): self.assertTrue(os.path.isdir(our_type_dir)) - ### other tests + # other tests def test_run_success(self): self.local.run([bin_true]) @@ -170,7 +182,8 @@ class LocalTestCase(test.CdistTestCase): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", "echo foobar"]) - self.assertEqual(self.local.run_script(script, return_output=True), "foobar\n") + self.assertEqual(self.local.run_script(script, return_output=True), + "foobar\n") def test_mkdir(self): temp_dir = self.mkdtemp(dir=self.temp_dir) diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 89e9dbc8..318e4c7b 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -39,26 +39,32 @@ class RemoteTestCase(test.CdistTestCase): user = getpass.getuser() remote_exec = "ssh -o User=%s -q" % user remote_copy = "scp -o User=%s -q" % user - self.remote = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) + self.remote = remote.Remote(self.target_host, base_path=self.base_path, + remote_exec=remote_exec, + remote_copy=remote_copy) def tearDown(self): shutil.rmtree(self.temp_dir) - ### test api + # test api def test_conf_path(self): - self.assertEqual(self.remote.conf_path, os.path.join(self.base_path, "conf")) + self.assertEqual(self.remote.conf_path, + os.path.join(self.base_path, "conf")) def test_object_path(self): - self.assertEqual(self.remote.object_path, os.path.join(self.base_path, "object")) + self.assertEqual(self.remote.object_path, + os.path.join(self.base_path, "object")) def test_type_path(self): - self.assertEqual(self.remote.type_path, os.path.join(self.base_path, "conf", "type")) + self.assertEqual(self.remote.type_path, + os.path.join(self.base_path, "conf", "type")) def test_global_explorer_path(self): - self.assertEqual(self.remote.global_explorer_path, os.path.join(self.base_path, "conf", "explorer")) + self.assertEqual(self.remote.global_explorer_path, + os.path.join(self.base_path, "conf", "explorer")) - ### /test api + # /test api def test_run_success(self): self.remote.run(['/bin/true']) @@ -76,13 +82,15 @@ class RemoteTestCase(test.CdistTestCase): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", "/bin/false"]) - self.assertRaises(remote.RemoteScriptError, self.remote.run_script, script) + self.assertRaises(remote.RemoteScriptError, self.remote.run_script, + script) def test_run_script_get_output(self): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", "echo foobar"]) - self.assertEqual(self.remote.run_script(script, return_output=True), "foobar\n") + self.assertEqual(self.remote.run_script(script, return_output=True), + "foobar\n") def test_mkdir(self): temp_dir = self.mkdtemp(dir=self.temp_dir) @@ -125,8 +133,10 @@ class RemoteTestCase(test.CdistTestCase): os.chmod(remote_exec_path, 0o755) remote_exec = remote_exec_path remote_copy = "echo" - r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) - self.assertEqual(r.run('/bin/true', return_output=True), "%s\n" % self.target_host) + r = remote.Remote(self.target_host, base_path=self.base_path, + remote_exec=remote_exec, remote_copy=remote_copy) + self.assertEqual(r.run('/bin/true', return_output=True), + "%s\n" % self.target_host) def test_run_script_target_host_in_env(self): handle, remote_exec_path = self.mkstemp(dir=self.temp_dir) @@ -135,16 +145,21 @@ class RemoteTestCase(test.CdistTestCase): os.chmod(remote_exec_path, 0o755) remote_exec = remote_exec_path remote_copy = "echo" - r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) + r = remote.Remote(self.target_host, base_path=self.base_path, + remote_exec=remote_exec, remote_copy=remote_copy) handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", "/bin/true"]) - self.assertEqual(r.run_script(script, return_output=True), "%s\n" % self.target_host) + self.assertEqual(r.run_script(script, return_output=True), + "%s\n" % self.target_host) def test_run_script_with_env_target_host_in_env(self): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", 'if [ "$__object" ]; then echo $__object; else echo no_env; fi\n']) + fd.writelines([ + "#!/bin/sh\n", + ('if [ "$__object" ]; then echo $__object; ' + 'else echo no_env; fi\n')]) os.chmod(script, 0o755) handle, remote_exec_path = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, 'w') as fd: @@ -152,7 +167,8 @@ class RemoteTestCase(test.CdistTestCase): os.chmod(remote_exec_path, 0o755) remote_exec = remote_exec_path remote_copy = "echo" - r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) + r = remote.Remote(self.target_host, base_path=self.base_path, + remote_exec=remote_exec, remote_copy=remote_copy) output = r.run_script(script, return_output=True) self.assertEqual(output, "no_env\n") @@ -164,7 +180,8 @@ class RemoteTestCase(test.CdistTestCase): env = { '__object': 'test_object', } - r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) + r = remote.Remote(self.target_host, base_path=self.base_path, + remote_exec=remote_exec, remote_copy=remote_copy) output = r.run_script(script, env=env, return_output=True) self.assertEqual(output, "test_object\n") diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 335d0e32..2ca50b7c 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -36,12 +36,13 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') conf_dir = op.join(fixtures, "conf") + class ExplorerClassTestCase(test.CdistTestCase): def setUp(self): - self.temp_dir = self.mkdtemp() - self.local_path = os.path.join(self.temp_dir, "local") - self.remote_base_path = os.path.join(self.temp_dir, "remote") + self.temp_dir = self.mkdtemp() + self.local_path = os.path.join(self.temp_dir, "local") + self.remote_base_path = os.path.join(self.temp_dir, "remote") os.makedirs(self.remote_base_path) self.local = local.Local( @@ -54,15 +55,15 @@ class ExplorerClassTestCase(test.CdistTestCase): self.local.create_files_dirs() self.remote = remote.Remote( - target_host=self.target_host, + target_host=self.target_host, remote_exec=self.remote_exec, remote_copy=self.remote_copy, base_path=self.remote_base_path) self.remote.create_files_dirs() self.explorer = explorer.Explorer( - self.target_host, - self.local, + self.target_host, + self.local, self.remote) def tearDown(self): @@ -79,7 +80,8 @@ class ExplorerClassTestCase(test.CdistTestCase): self.explorer.transfer_global_explorers() source = self.local.global_explorer_path destination = self.remote.global_explorer_path - self.assertEqual(sorted(os.listdir(source)), sorted(os.listdir(destination))) + self.assertEqual(sorted(os.listdir(source)), + sorted(os.listdir(destination))) def test_run_global_explorer(self): """Checkt that running ONE global explorer works""" @@ -101,14 +103,16 @@ class ExplorerClassTestCase(test.CdistTestCase): def test_list_type_explorer_names(self): cdist_type = core.CdistType(self.local.type_path, '__test_type') expected = cdist_type.explorers - self.assertEqual(self.explorer.list_type_explorer_names(cdist_type), expected) + self.assertEqual(self.explorer.list_type_explorer_names(cdist_type), + expected) def test_transfer_type_explorers(self): """Test if transferring type explorers works""" cdist_type = core.CdistType(self.local.type_path, '__test_type') self.explorer.transfer_type_explorers(cdist_type) source = os.path.join(self.local.type_path, cdist_type.explorer_path) - destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, + cdist_type.explorer_path) self.assertEqual(os.listdir(source), os.listdir(destination)) def test_transfer_type_explorers_only_once(self): @@ -116,7 +120,8 @@ class ExplorerClassTestCase(test.CdistTestCase): # first transfer self.explorer.transfer_type_explorers(cdist_type) source = os.path.join(self.local.type_path, cdist_type.explorer_path) - destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, + cdist_type.explorer_path) self.assertEqual(os.listdir(source), os.listdir(destination)) # nuke destination folder content, but recreate directory shutil.rmtree(destination) @@ -127,24 +132,36 @@ class ExplorerClassTestCase(test.CdistTestCase): def test_transfer_object_parameters(self): cdist_type = core.CdistType(self.local.type_path, '__test_type') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + 'whatever') cdist_object.create() - cdist_object.parameters = {'first': 'first value', 'second': 'second value'} + cdist_object.parameters = { + 'first': 'first value', + 'second': 'second value' + } self.explorer.transfer_object_parameters(cdist_object) - source = os.path.join(self.local.object_path, cdist_object.parameter_path) - destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) - self.assertEqual(sorted(os.listdir(source)), sorted(os.listdir(destination))) + source = os.path.join(self.local.object_path, + cdist_object.parameter_path) + destination = os.path.join(self.remote.object_path, + cdist_object.parameter_path) + self.assertEqual(sorted(os.listdir(source)), + sorted(os.listdir(destination))) def test_run_type_explorer(self): cdist_type = core.CdistType(self.local.type_path, '__test_type') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + 'whatever') self.explorer.transfer_type_explorers(cdist_type) output = self.explorer.run_type_explorer('world', cdist_object) self.assertEqual(output, 'hello\n') def test_run_type_explorers(self): cdist_type = core.CdistType(self.local.type_path, '__test_type') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + 'whatever') cdist_object.create() self.explorer.run_type_explorers(cdist_object) self.assertEqual(cdist_object.explorers, {'world': 'hello'}) diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index f9eb8b8a..84c69ce1 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -40,6 +40,7 @@ my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') conf_dir = op.join(fixtures, 'conf') + class ManifestTestCase(test.CdistTestCase): def setUp(self): @@ -51,7 +52,7 @@ class ManifestTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, base_path=out_path, - exec_path = cdist.test.cdist_exec_path, + exec_path=cdist.test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -63,7 +64,8 @@ class ManifestTestCase(test.CdistTestCase): shutil.rmtree(self.temp_dir) def test_initial_manifest_environment(self): - initial_manifest = os.path.join(self.local.manifest_path, "dump_environment") + initial_manifest = os.path.join(self.local.manifest_path, + "dump_environment") handle, output_file = self.mkstemp(dir=self.temp_dir) os.close(handle) os.environ['__cdist_test_out'] = output_file @@ -74,18 +76,21 @@ class ManifestTestCase(test.CdistTestCase): output_dict = {} for line in output_string.split('\n'): if line: - key,value = line.split(': ') + key, value = line.split(': ') output_dict[key] = value self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) self.assertEqual(output_dict['__target_host'], self.local.target_host) self.assertEqual(output_dict['__global'], self.local.base_path) - self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) + self.assertEqual(output_dict['__cdist_type_base_path'], + self.local.type_path) self.assertEqual(output_dict['__manifest'], self.local.manifest_path) self.assertEqual(output_dict['__files'], self.local.files_path) def test_type_manifest_environment(self): cdist_type = core.CdistType(self.local.type_path, '__dump_environment') - cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'whatever') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + 'whatever') handle, output_file = self.mkstemp(dir=self.temp_dir) os.close(handle) os.environ['__cdist_test_out'] = output_file @@ -96,12 +101,13 @@ class ManifestTestCase(test.CdistTestCase): output_dict = {} for line in output_string.split('\n'): if line: - key,value = line.split(': ') + key, value = line.split(': ') output_dict[key] = value self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) self.assertEqual(output_dict['__target_host'], self.local.target_host) self.assertEqual(output_dict['__global'], self.local.base_path) - self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) + self.assertEqual(output_dict['__cdist_type_base_path'], + self.local.type_path) self.assertEqual(output_dict['__type'], cdist_type.absolute_path) self.assertEqual(output_dict['__object'], cdist_object.absolute_path) self.assertEqual(output_dict['__object_id'], cdist_object.object_id) diff --git a/cdist/test/message/__init__.py b/cdist/test/message/__init__.py index 653847f1..61cd5d97 100644 --- a/cdist/test/message/__init__.py +++ b/cdist/test/message/__init__.py @@ -25,14 +25,15 @@ import tempfile from cdist import test import cdist.message + class MessageTestCase(test.CdistTestCase): def setUp(self): - self.prefix="cdist-test" + self.prefix = "cdist-test" self.content = "A very short story" self.tempfile = tempfile.mkstemp()[1] self.message = cdist.message.Message(prefix=self.prefix, - messages=self.tempfile) + messages=self.tempfile) def tearDown(self): os.remove(self.tempfile) @@ -48,7 +49,6 @@ class MessageTestCase(test.CdistTestCase): self.assertIn('__messages_in', env) self.assertIn('__messages_out', env) - def test_copy_content(self): """ Ensure content copying is working diff --git a/cdist/util/fsproperty.py b/cdist/util/fsproperty.py index 98de09f8..e458fd9e 100644 --- a/cdist/util/fsproperty.py +++ b/cdist/util/fsproperty.py @@ -136,7 +136,7 @@ class DirectoryDict(collections.MutableMapping): with open(os.path.join(self.path, key), "w") as fd: if (not hasattr(value, 'strip') and (hasattr(value, '__getitem__') or - hasattr(value, '__iter__'))): + hasattr(value, '__iter__'))): # if it looks like a sequence and quacks like a sequence, # it is a sequence for v in value: @@ -175,14 +175,19 @@ class FileBasedProperty(object): """ :param path: string or callable - Abstract super class. Subclass and set the class member attribute_class accordingly. + Abstract super class. Subclass and set the class member + attribute_class accordingly. Usage with a sublcass: class Foo(object): - # note that the actual DirectoryDict is stored as __parameters on the instance - parameters = DirectoryDictProperty(lambda instance: os.path.join(instance.absolute_path, 'parameter')) - # note that the actual DirectoryDict is stored as __other_dict on the instance + # note that the actual DirectoryDict is stored as __parameters + # on the instance + parameters = DirectoryDictProperty( + lambda instance: os.path.join(instance.absolute_path, + 'parameter')) + # note that the actual DirectoryDict is stored as __other_dict + # on the instance other_dict = DirectoryDictProperty('/tmp/other_dict') def __init__(self): From 759c491ef0245daacd9471b5f42ddcfa7686a916 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 6 Jul 2016 07:50:23 +0200 Subject: [PATCH 0184/1332] Update changelog for pep8. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index f1aead98..aea94be2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Core: pep8 (Darko Poljak) * Documentation: Restructure and fix and improve docs and manpages (Darko Poljak) * Core: Add files directory for static files (Darko Poljak) * Custom: Add bash and zsh completions (Darko Poljak) From 22abe43e854d68e94bde346b7c3e0b4c281cbc25 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 6 Jul 2016 08:25:31 +0200 Subject: [PATCH 0185/1332] Make better msg for exec/util unsupported stderr output. --- cdist/exec/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/util.py b/cdist/exec/util.py index 15430f13..81264c73 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -25,7 +25,7 @@ from tempfile import TemporaryFile import cdist -STDERR_UNSUPPORTED = 'Not supported in this python version' +STDERR_UNSUPPORTED = '' def call_get_output(command, env=None): """Run the given command with the given environment. From 348867ff6a84958a2388799fa702396c16c2ae9f Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Wed, 6 Jul 2016 10:15:34 +0200 Subject: [PATCH 0186/1332] Correctly set hostname in preos --- cdist/preos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/preos.py b/cdist/preos.py index b61318ed..8a17974e 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -63,7 +63,7 @@ eof # fix the bloody 'stdin: is not a tty' problem __line /root/.profile --line 'mesg n' --state absent -__hostname preos +__hostname --name preos """ class PreOSExistsError(cdist.Error): From 78d7d91e42dc7bcbc882eaf735fe48e3714c7f6d Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Wed, 6 Jul 2016 10:30:13 +0200 Subject: [PATCH 0187/1332] Install lsb-release in preos Several types use the lsb_release command to determine the distribution, if this command is missing unexpected things will happen. --- cdist/preos.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/preos.py b/cdist/preos.py index 8a17974e..df5be1fa 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -38,6 +38,7 @@ DEFAULT_MANIFEST = """ for pkg in \ file \ linux-image-amd64 \ + lsb-release \ openssh-server curl \ syslinux grub2 \ gdisk util-linux lvm2 mdadm \ From 0e114c37ac1756d916a393822a8744eba5d55eb0 Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Wed, 6 Jul 2016 10:47:28 +0200 Subject: [PATCH 0188/1332] Always use current stable release for preos --- cdist/preos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/preos.py b/cdist/preos.py index df5be1fa..8eced936 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -86,7 +86,7 @@ class PreOS(object): self.arch = arch self.command = "debootstrap" - self.suite = "wheezy" + self.suite = "stable" self.options = [ "--include=openssh-server", "--arch=%s" % self.arch ] From e79610f23c585017da411eea0a5d76b9876eacc4 Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Wed, 6 Jul 2016 11:22:15 +0200 Subject: [PATCH 0189/1332] Don't try to use hostnamectl when systemd isn't running --- cdist/conf/type/__hostname/explorer/has_hostnamectl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__hostname/explorer/has_hostnamectl b/cdist/conf/type/__hostname/explorer/has_hostnamectl index 9040023d..7e8a57fd 100755 --- a/cdist/conf/type/__hostname/explorer/has_hostnamectl +++ b/cdist/conf/type/__hostname/explorer/has_hostnamectl @@ -18,7 +18,12 @@ # along with cdist. If not, see . # # -# Check whether system has hostnamectl +# Check whether system has hostnamectl and it's usable, i.e. don't +# try to use it when systemd isn't running yet. # -command -v hostnamectl || true +if command -v hostnamectl >/dev/null && hostnamectl status >/dev/null 2>&1; then + echo "yes" +else + true +fi From 16cb3a5ff11bae3f0f99e477bcfe202599a21119 Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Wed, 6 Jul 2016 14:57:59 +0200 Subject: [PATCH 0190/1332] Update PXE setup for Debian 8 --- cdist/preos.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cdist/preos.py b/cdist/preos.py index 8eced936..c21dc00a 100644 --- a/cdist/preos.py +++ b/cdist/preos.py @@ -40,7 +40,7 @@ for pkg in \ linux-image-amd64 \ lsb-release \ openssh-server curl \ - syslinux grub2 \ + pxelinux syslinux-common grub2 \ gdisk util-linux lvm2 mdadm \ btrfs-tools e2fsprogs jfsutils reiser4progs xfsprogs; do __package $pkg --state present @@ -90,7 +90,7 @@ class PreOS(object): self.options = [ "--include=openssh-server", "--arch=%s" % self.arch ] - self.pxelinux = "/usr/lib/syslinux/pxelinux.0" + self.pxelinux = "/usr/lib/PXELINUX/pxelinux.0" self.pxelinux_cfg = """ DEFAULT preos LABEL preos @@ -178,11 +178,18 @@ cp -L "$src" "$real_dst" def create_pxelinux(self): dst = os.path.join(self.out_dir, "pxelinux.0") - src = "%s/usr/lib/syslinux/pxelinux.0" % self.target_dir + src = "%s/usr/lib/PXELINUX/pxelinux.0" % self.target_dir log.info("Creating pxelinux.0 ...") shutil.copyfile(src, dst, follow_symlinks=True) + def create_ldlinux(self): + dst = os.path.join(self.out_dir, "ldlinux.c32") + src = "%s/usr/lib/syslinux/modules/bios/ldlinux.c32" % self.target_dir + + log.info("Creating ldlinux.c32 ...") + shutil.copyfile(src, dst, follow_symlinks=True) + def create_pxeconfig(self): configdir = os.path.join(self.out_dir, "pxelinux.cfg") configfile = os.path.join(configdir, "default") @@ -219,6 +226,7 @@ cp -L "$src" "$real_dst" self.create_initramfs() self.create_pxeconfig() self.create_pxelinux() + self.create_ldlinux() def setup_initial_manifest(self, user_initial_manifest, replace_manifest): From a6643f0d7fe2583dd2a6332f63689e5504ab7a20 Mon Sep 17 00:00:00 2001 From: Stu Zhao Date: Wed, 6 Jul 2016 18:39:27 -0400 Subject: [PATCH 0191/1332] Explore machine type for virtualbox guest --- cdist/conf/explorer/machine_type | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cdist/conf/explorer/machine_type b/cdist/conf/explorer/machine_type index c0541ad5..eb3c9d36 100755 --- a/cdist/conf/explorer/machine_type +++ b/cdist/conf/explorer/machine_type @@ -48,11 +48,12 @@ if [ -r /proc/cpuinfo ]; then if grep -q -i 'vmware' /sys/class/dmi/id/product_name; then echo "virtual_by_vmware" exit - else - if grep -q -i 'bochs' /sys/class/dmi/id/product_name; then - echo "virtual_by_kvm" - exit - fi + elif grep -q -i 'bochs' /sys/class/dmi/id/product_name; then + echo "virtual_by_kvm" + exit + elif grep -q -i 'virtualbox' /sys/class/dmi/id/product_name; then + echo "virtual_by_virtualbox" + exit fi fi fi From 17c03950d95431913a5fcd05ab70f62c6fef8b5e Mon Sep 17 00:00:00 2001 From: Stu Zhao Date: Wed, 6 Jul 2016 23:11:49 -0400 Subject: [PATCH 0192/1332] Update changelog for commit a6643f0 --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index aea94be2..a5b1a6c3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,7 @@ next: * Explorer __machine_type: add openvz and lxc * Explorer __os __os_version: add scientific * Type various: add scientific + * Explorer __machine_type: add virtualbox (Stu Zhao) 4.1.0: 2016-05-27 * Documentation: Migrate to reStructuredText format and sphinx (Darko Poljak) From 07ef7cf2a0bf7bb601ac0d7ba0e4fbbe8ac8faf1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Jul 2016 07:53:21 +0200 Subject: [PATCH 0193/1332] Update building on FreeBSD. --- bin/build-helper.freebsd | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 01d86a10..da8170e1 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -260,7 +260,15 @@ eof fi # Publish git changes - make helper=${helper} WEBDIR=${WEBDIR} pub + case "$run_as" in + freebsd) + # if we are not Nico :) then just push, no mirror + git push + ;; + *) + make helper=${helper} WEBDIR=${WEBDIR} pub + ;; + esac # publish man, speeches, website if [ "$masterbranch" = yes ]; then From 13d315d718af95c5371b3a6f0a5485fb5bd1e499 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 7 Jul 2016 14:38:36 +0200 Subject: [PATCH 0194/1332] do not assume target_host is anything that can be used as a directory name Signed-off-by: Steven Armstrong --- cdist/exec/local.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index c0554831..64593235 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -29,6 +29,7 @@ import subprocess import shutil import logging import tempfile +import hashlib import cdist import cdist.message @@ -55,8 +56,10 @@ class Local(object): base_path_parent = base_path else: base_path_parent = tempfile.mkdtemp() - import atexit - atexit.register(lambda: shutil.rmtree(base_path_parent)) + # TODO: the below atexit hook nukes any debug info we would have + # if cdist exits with error. + #import atexit + #atexit.register(lambda: shutil.rmtree(base_path_parent)) self.hostdir = self._hostdir() self.base_path = os.path.join(base_path_parent, self.hostdir) @@ -89,11 +92,9 @@ class Local(object): return None def _hostdir(self): - if os.path.isabs(self.target_host): - hostdir = self.target_host[1:] - else: - hostdir = self.target_host - return hostdir + # Do not assume target_host is anything that can be used as a directory name. + # Instead use a hash, which is know to work as directory name. + return hashlib.md5(self.target_host.encode('utf-8')).hexdigest() def _init_log(self): self.log = logging.getLogger(self.target_host) @@ -227,7 +228,7 @@ class Local(object): def save_cache(self): - destination = os.path.join(self.cache_path, self.hostdir) + destination = os.path.join(self.cache_path, self.target_host) self.log.debug("Saving " + self.base_path + " to " + destination) try: From 356e4b89f860e2595eaef65a2e033df9bc7a0bc7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 10 Jul 2016 11:09:09 +0200 Subject: [PATCH 0195/1332] pep8 for setup and sphinx conf py files. --- docs/src/conf.py | 122 ++++++++++++++++++++++++----------------------- setup.py | 27 ++++++----- 2 files changed, 77 insertions(+), 72 deletions(-) diff --git a/docs/src/conf.py b/docs/src/conf.py index 334cfd51..dee11095 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -15,17 +15,20 @@ import sys import os +import cdist.version +import sphinx_rtd_theme # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../"))) +# sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join( + os.path.dirname(os.path.realpath(__file__)), "../../"))) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -43,22 +46,21 @@ templates_path = ['_templates'] source_suffix = ['.rst'] # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'cdist' -#copyright = '2016, Darko Poljak' -#author = 'Darko Poljak' +# copyright = '2016, Darko Poljak' +# author = 'Darko Poljak' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -import cdist.version version = cdist.version.VERSION # The full version, including alpha/beta/rc tags. release = version @@ -72,9 +74,9 @@ language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -83,27 +85,27 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +# keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -113,33 +115,33 @@ todo_include_todos = False # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. # " v documentation" by default. -#html_title = 'cdist-docs v0.0.1' +# html_title = 'cdist-docs v0.0.1' # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (relative to this directory) to use as a favicon of -# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# the docs. This file should be a Windows icon file (.ico) +# being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -149,84 +151,84 @@ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. -#html_extra_path = [] +# html_extra_path = [] # If not None, a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. # The empty string is equivalent to '%b %d, %Y'. -#html_last_updated_fmt = None +# html_last_updated_fmt = None # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None -#html_file_suffix = "" +# html_file_suffix = None +# html_file_suffix = "" # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh' -#html_search_language = 'en' +# html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # 'ja' uses this config value. # 'zh' user can custom change `jieba` dictionary path. -#html_search_options = {'type': 'default'} +# html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. -#html_search_scorer = 'scorer.js' +# html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'cdistdoc' # -- Options for LaTeX output --------------------------------------------- -latex_elements = { +# latex_elements = { # The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', +# 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', +# 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. -#'preamble': '', +# 'preamble': '', # Latex figure (float) alignment -#'figure_align': 'htbp', -} +# 'figure_align': 'htbp', +# } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, @@ -238,23 +240,23 @@ latex_documents = [ # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output --------------------------------------- @@ -272,20 +274,20 @@ for mandir, section in mandirs: froot, fext = os.path.splitext(fname) if fext == '.rst': man_page = (os.path.join('man' + str(section), froot), - froot, '', [], section) + froot, '', [], section) man_pages.append(man_page) -#man_pages = [ +# man_pages = [ # ('cdist-type', 'cdist-type', 'cdist-type documentation', # [author], 1), # ('man7/cdist-type__file', 'cdist-type__file', # '', [], 1), # ('cdist-type__directory', 'cdist-type__directory', # 'cdist-type__directory documentation', [author], 1), -#] +# ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------- @@ -300,13 +302,13 @@ texinfo_documents = [ ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +# texinfo_no_detailmenu = False diff --git a/setup.py b/setup.py index c484a269..f29a8998 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,7 @@ import cdist import os import re + def data_finder(data_dir): entries = [] for name in os.listdir(data_dir): @@ -29,17 +30,18 @@ os.chdir("cdist") package_data = data_finder("conf") os.chdir(cur) + setup( - name = "cdist", - packages = ["cdist", "cdist.core", "cdist.exec", "cdist.util" ], + name="cdist", + packages=["cdist", "cdist.core", "cdist.exec", "cdist.util", ], package_data={'cdist': package_data}, - scripts = ["scripts/cdist"], - version = cdist.version.VERSION, - description = "A Usable Configuration Management System", - author = "Nico Schottelius", - author_email = "nico-cdist-pypi@schottelius.org", - url = "http://www.nico.schottelius.org/software/cdist/", - classifiers = [ + scripts=["scripts/cdist"], + version=cdist.version.VERSION, + description="A Usable Configuration Management System", + author="Nico Schottelius", + author_email="nico-cdist-pypi@schottelius.org", + url="http://www.nico.schottelius.org/software/cdist/", + classifiers=[ "Development Status :: 6 - Mature", "Environment :: Console", "Intended Audience :: System Administrators", @@ -57,10 +59,11 @@ setup( "Topic :: System :: Software Distribution", "Topic :: Utilities" ], - long_description = ''' + long_description=''' cdist is a usable configuration management system. - It adheres to the KISS principle and is being used in small up to enterprise grade environments. - cdist is an alternative to other configuration management systems like + It adheres to the KISS principle and is being used in small up to + enterprise grade environments. + cdist is an alternative to other configuration management systems like cfengine, bcfg2, chef and puppet. ''' ) From 81fbf487021b58853cb5520cecc0a6a4482cb46b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 10 Jul 2016 11:21:52 +0200 Subject: [PATCH 0196/1332] Add pep8 check target to build-helper. --- bin/build-helper | 23 +++++++++++++++++++++++ bin/build-helper.freebsd | 23 +++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/bin/build-helper b/bin/build-helper index 8f228697..b2d3b66e 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -166,6 +166,7 @@ eof # First check everything is sane "$0" check-date "$0" check-unittest + "$0" pep8 # Generate version file to be included in packaging "$0" version @@ -268,6 +269,28 @@ eof fi ;; + pep8) + pep8 ${basedir} | less + echo "Please review pep8 report." + while true + do + echo "Continue (yes/no)?" + any= + read any + case "$any" in + yes) + break + ;; + no) + exit 1 + ;; + *) + echo "Please answer with 'yes' or 'no' explicitly." + ;; + esac + done + ;; + version-branch) "$0" changelog-version | cut -d. -f '1,2' ;; diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 5d0f92a2..4c30575a 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -201,6 +201,7 @@ eof # First check everything is sane "$0" check-date "$0" check-unittest + "$0" pep8 # Generate version file to be included in packaging "$0" version @@ -328,6 +329,28 @@ eof fi ;; + pep8) + pep8 ${basedir} | less + echo "Please review pep8 report." + while true + do + echo "Continue (yes/no)?" + any= + read any + case "$any" in + yes) + break + ;; + no) + exit 1 + ;; + *) + echo "Please answer with 'yes' or 'no' explicitly." + ;; + esac + done + ;; + version-branch) "$0" changelog-version | cut -d. -f '1,2' ;; From 17de2d9b7994d56eecdb179e897ad68c4dcb0ee5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 10 Jul 2016 21:17:42 +0200 Subject: [PATCH 0197/1332] Make signed github releases. --- bin/build-helper | 70 +++++++++++++++++++++++++++++++++++++++- bin/build-helper.freebsd | 70 +++++++++++++++++++++++++++++++++++++++- docs/changelog | 1 + 3 files changed, 139 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index b2d3b66e..b370d5af 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -153,7 +153,70 @@ eof fi printf "Enter tag description for ${target_version}: " read tagmessage - git tag "$target_version" -m "$$tagmessage" + + # setup for signed tags: + # gpg --fulL-gen-key + # gpg --list-secret-keys --keyid-format LONG + # git config --local user.signingkey + # for exporting pub key: + # gpg --armor --export > pubkey.asc + # gpg --output pubkey.gpg --export + # show tag with signature + # git show + # verify tag signature + # git tag -v + # + # gpg verify signature + # gpg --verify + # gpg --no-default-keyring --keyring --verify + # + + git tag -s "$target_version" -m "$tagmessage" + git push --tags + ;; + + sign-git-tag) + if [ $# -lt 3 ] + then + printf "usage: $0 sign-git-tag TAG AUTHTOKEN\n" + exit 1 + fi + tag="$2" + if ! git rev-parse -q --verify "${tag}" >/dev/null 2>&1 + printf "Tag \"${tag}\" not found.\n" + exit 1 + fi + token="$3" + archivename="cdist-${tag}.tar.gz" + git archive --prefix="cdist-${tag}" -o "${archivename}" "${tag}" \ + || exit 1 + gpg --armor --detach-sign "${archivename}" || exit 1 + + # make github release + curl -H "Authorization: token ${token}" \ + --request POST \ + --data "{ \"tag_name\":\"${tag}\", \ + \"target_commitish\":\"master\", \ + \"name\": \"${tag}\", \ + \"body\":\"${tag}\", \ + \"draft\":false, \ + \"prerelease\": false}" \ + "https://api.github.com/repos/ungleich/cdist/releases" || exit 1 + + # get release ID + repoid=$(curl "https://api.github.com/repos/ungleich/cdist/releases/tags/${tag}" \ + || python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ + || exit 1 + + curl -H "Authorization: token ${token}" \ + -H "Accept: application/vnd.github.manifold-preview" \ + -H "Content-Type: application/pgp-signature" \ + --data-binary @${archivename}.asc \ + "https://uploads.github.com/repos/ungleich/cdist/releases/${repoid}/assets?name=${archivename}.asc" \ + || exit 1 + + # remove generated files (archive and asc) + rm -f "${archivename}" "${archivename}.asc" ;; release) @@ -219,6 +282,11 @@ eof # Tag the current commit "$0" release-git-tag + # sign git tag + printf "Enter github authentication token: " + read token + "$0" sign-git-tag "${target_version}" "${token}" + # Also merge back the version branch if [ "$masterbranch" = yes ]; then git checkout master diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 4c30575a..a1e9221e 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -188,7 +188,70 @@ eof fi printf "Enter tag description for ${target_version}: " read tagmessage - git tag "$target_version" -m "$$tagmessage" + + # setup for signed tags: + # gpg --fulL-gen-key + # gpg --list-secret-keys --keyid-format LONG + # git config --local user.signingkey + # for exporting pub key: + # gpg --armor --export > pubkey.asc + # gpg --output pubkey.gpg --export + # show tag with signature + # git show + # verify tag signature + # git tag -v + # + # gpg verify signature + # gpg --verify + # gpg --no-default-keyring --keyring --verify + # + + git tag -s "$target_version" -m "$tagmessage" + git push --tags + ;; + + sign-git-tag) + if [ $# -lt 3 ] + then + printf "usage: $0 sign-git-tag TAG TOKEN\n" + exit 1 + fi + tag="$2" + if ! git rev-parse -q --verify "${tag}" >/dev/null 2>&1 + printf "Tag \"${tag}\" not found.\n" + exit 1 + fi + token="$3" + archivename="cdist-${tag}.tar.gz" + git archive --prefix="cdist-${tag}" -o "${archivename}" "${tag}" \ + || exit 1 + gpg --armor --detach-sign "${archivename}" || exit 1 + + # make github release + curl -H "Authorization: token ${token}" \ + --request POST \ + --data "{ \"tag_name\":\"${tag}\", \ + \"target_commitish\":\"master\", \ + \"name\": \"${tag}\", \ + \"body\":\"${tag}\", \ + \"draft\":false, \ + \"prerelease\": false}" \ + "https://api.github.com/repos/ungleich/cdist/releases" || exit 1 + + # get release ID + repoid=$(curl "https://api.github.com/repos/ungleich/cdist/releases/tags/${tag}" \ + || python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ + || exit 1 + + curl -H "Authorization: token ${token}" \ + -H "Accept: application/vnd.github.manifold-preview" \ + -H "Content-Type: application/pgp-signature" \ + --data-binary @${archivename}.asc \ + "https://uploads.github.com/repos/ungleich/cdist/releases/${repoid}/assets?name=${archivename}.asc" \ + || exit 1 + + # remove generated files (archive and asc) + rm -f "${archivename}" "${archivename}.asc" ;; release) @@ -254,6 +317,11 @@ eof # Tag the current commit "$0" release-git-tag + # sign git tag + printf "Enter github authentication token: " + read token + "$0" sign-git-tag "${target_version}" "${token}" + # Also merge back the version branch if [ "$masterbranch" = yes ]; then git checkout master diff --git a/docs/changelog b/docs/changelog index a5b1a6c3..61574133 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Build: Make github signed release (Darko Poljak) * Core: pep8 (Darko Poljak) * Documentation: Restructure and fix and improve docs and manpages (Darko Poljak) * Core: Add files directory for static files (Darko Poljak) From 3b91ace4ea0069fcd1f424295379a43300c588ec Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 10 Jul 2016 21:28:30 +0200 Subject: [PATCH 0198/1332] Additionaly improve hostdir fix. --- cdist/exec/local.py | 13 ++++++++----- docs/changelog | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index cc905751..6d7ccc57 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -62,9 +62,11 @@ class Local(object): base_path_parent = tempfile.mkdtemp() # TODO: the below atexit hook nukes any debug info we would have # if cdist exits with error. - #import atexit - #atexit.register(lambda: shutil.rmtree(base_path_parent)) + # import atexit + # atexit.register(lambda: shutil.rmtree(base_path_parent)) self.hostdir = self._hostdir() + self.log.debug("Calculated temp dir for target \"{}\" is " + "\"{}\"".format(self.target_host, self.hostdir)) self.base_path = os.path.join(base_path_parent, self.hostdir) self._init_log() @@ -97,8 +99,9 @@ class Local(object): return None def _hostdir(self): - # Do not assume target_host is anything that can be used as a directory name. - # Instead use a hash, which is know to work as directory name. + # Do not assume target_host is anything that can be used as a + # directory name. + # Instead use a hash, which is known to work as directory name. return hashlib.md5(self.target_host.encode('utf-8')).hexdigest() def _init_log(self): @@ -239,7 +242,7 @@ class Local(object): message_prefix=message_prefix) def save_cache(self): - destination = os.path.join(self.cache_path, self.target_host) + destination = os.path.join(self.cache_path, self.hostdir) self.log.debug("Saving " + self.base_path + " to " + destination) try: diff --git a/docs/changelog b/docs/changelog index a5b1a6c3..a07a90bc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Core: Fix hostdir: use hash instead of target host (Steven Armstrong) * Core: pep8 (Darko Poljak) * Documentation: Restructure and fix and improve docs and manpages (Darko Poljak) * Core: Add files directory for static files (Darko Poljak) From 120b11e96b36047990c79a65b396fe074fd301eb Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 10 Jul 2016 21:43:09 +0200 Subject: [PATCH 0199/1332] Fix log init error. --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 6d7ccc57..e1d7af1c 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -54,6 +54,7 @@ class Local(object): add_conf_dirs=None): self.target_host = target_host + self._init_log() # FIXME: stopped: create base that does not require moving later if base_path: @@ -69,7 +70,6 @@ class Local(object): "\"{}\"".format(self.target_host, self.hostdir)) self.base_path = os.path.join(base_path_parent, self.hostdir) - self._init_log() self._init_permissions() self.mkdir(self.base_path) From 92868500980c7edca6981d1d6ed7d4497d3c247e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 10 Jul 2016 21:44:57 +0200 Subject: [PATCH 0200/1332] Fix syntax error. --- bin/build-helper | 1 + bin/build-helper.freebsd | 1 + 2 files changed, 2 insertions(+) diff --git a/bin/build-helper b/bin/build-helper index b370d5af..6a70b7f3 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -183,6 +183,7 @@ eof fi tag="$2" if ! git rev-parse -q --verify "${tag}" >/dev/null 2>&1 + then printf "Tag \"${tag}\" not found.\n" exit 1 fi diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index a1e9221e..f1a4af73 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -218,6 +218,7 @@ eof fi tag="$2" if ! git rev-parse -q --verify "${tag}" >/dev/null 2>&1 + then printf "Tag \"${tag}\" not found.\n" exit 1 fi From 317622678a23478ceb8c8cc8dd1d5915489f843f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 11 Jul 2016 08:19:10 +0200 Subject: [PATCH 0201/1332] Add build-helper param for existing archive for sign-git-tag target. --- bin/build-helper | 26 ++++++++++++++++++-------- bin/build-helper.freebsd | 26 ++++++++++++++++++-------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 6a70b7f3..c96cfe6e 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -176,21 +176,27 @@ eof ;; sign-git-tag) - if [ $# -lt 3 ] + if [ $# -lt 2 ] then - printf "usage: $0 sign-git-tag TAG AUTHTOKEN\n" + printf "usage: $0 sign-git-tag TAG TOKEN [ARCHIVE]\n" + printf " if ARCHIVE is not specified then it is created\n" exit 1 fi - tag="$2" + tag="$1" if ! git rev-parse -q --verify "${tag}" >/dev/null 2>&1 then printf "Tag \"${tag}\" not found.\n" exit 1 fi - token="$3" - archivename="cdist-${tag}.tar.gz" - git archive --prefix="cdist-${tag}" -o "${archivename}" "${tag}" \ - || exit 1 + token="$2" + if [ $# -ge 2 ] + then + archivename="$3" + else + archivename="cdist-${tag}.tar.gz" + git archive --prefix="cdist-${tag}" -o "${archivename}" "${tag}" \ + || exit 1 + fi gpg --armor --detach-sign "${archivename}" || exit 1 # make github release @@ -217,7 +223,11 @@ eof || exit 1 # remove generated files (archive and asc) - rm -f "${archivename}" "${archivename}.asc" + if [ $# -ge 2] + then + rm -f "${archivename}" + fi + rm -f "${archivename}.asc" ;; release) diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index f1a4af73..786fa158 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -211,21 +211,27 @@ eof ;; sign-git-tag) - if [ $# -lt 3 ] + if [ $# -lt 2 ] then - printf "usage: $0 sign-git-tag TAG TOKEN\n" + printf "usage: $0 sign-git-tag TAG TOKEN [ARCHIVE]\n" + printf " if ARCHIVE is not specified then it is created\n" exit 1 fi - tag="$2" + tag="$1" if ! git rev-parse -q --verify "${tag}" >/dev/null 2>&1 then printf "Tag \"${tag}\" not found.\n" exit 1 fi - token="$3" - archivename="cdist-${tag}.tar.gz" - git archive --prefix="cdist-${tag}" -o "${archivename}" "${tag}" \ - || exit 1 + token="$2" + if [ $# -ge 2 ] + then + archivename="$3" + else + archivename="cdist-${tag}.tar.gz" + git archive --prefix="cdist-${tag}" -o "${archivename}" "${tag}" \ + || exit 1 + fi gpg --armor --detach-sign "${archivename}" || exit 1 # make github release @@ -252,7 +258,11 @@ eof || exit 1 # remove generated files (archive and asc) - rm -f "${archivename}" "${archivename}.asc" + if [ $# -ge 2] + then + rm -f "${archivename}" + fi + rm -f "${archivename}.asc" ;; release) From 0051240c7cc85f51b2a30cc4f8059baf20a109b7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 11 Jul 2016 08:50:39 +0200 Subject: [PATCH 0202/1332] log.info target_host -> hash --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index e1d7af1c..61256a31 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -66,7 +66,7 @@ class Local(object): # import atexit # atexit.register(lambda: shutil.rmtree(base_path_parent)) self.hostdir = self._hostdir() - self.log.debug("Calculated temp dir for target \"{}\" is " + self.log.info("Calculated temp dir for target \"{}\" is " "\"{}\"".format(self.target_host, self.hostdir)) self.base_path = os.path.join(base_path_parent, self.hostdir) From f10ffed4c624b8b9094d1c0321ae1ce5ba082fb3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 11 Jul 2016 12:28:22 +0200 Subject: [PATCH 0203/1332] sign-git-tag -> sign-git-release --- bin/build-helper | 6 +++--- bin/build-helper.freebsd | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index c96cfe6e..f9b21d76 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -175,10 +175,10 @@ eof git push --tags ;; - sign-git-tag) + sign-git-release) if [ $# -lt 2 ] then - printf "usage: $0 sign-git-tag TAG TOKEN [ARCHIVE]\n" + printf "usage: $0 sign-git-release TAG TOKEN [ARCHIVE]\n" printf " if ARCHIVE is not specified then it is created\n" exit 1 fi @@ -296,7 +296,7 @@ eof # sign git tag printf "Enter github authentication token: " read token - "$0" sign-git-tag "${target_version}" "${token}" + "$0" sign-git-release "${target_version}" "${token}" # Also merge back the version branch if [ "$masterbranch" = yes ]; then diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 786fa158..61a095cb 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -210,10 +210,10 @@ eof git push --tags ;; - sign-git-tag) + sign-git-release) if [ $# -lt 2 ] then - printf "usage: $0 sign-git-tag TAG TOKEN [ARCHIVE]\n" + printf "usage: $0 sign-git-release TAG TOKEN [ARCHIVE]\n" printf " if ARCHIVE is not specified then it is created\n" exit 1 fi @@ -331,7 +331,7 @@ eof # sign git tag printf "Enter github authentication token: " read token - "$0" sign-git-tag "${target_version}" "${token}" + "$0" sign-git-release "${target_version}" "${token}" # Also merge back the version branch if [ "$masterbranch" = yes ]; then From 54e845da6f73f94fc1006e145a47d6a46ca8b0fd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 11 Jul 2016 12:40:50 +0200 Subject: [PATCH 0204/1332] pep8 --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 61256a31..bde2ceba 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -67,7 +67,7 @@ class Local(object): # atexit.register(lambda: shutil.rmtree(base_path_parent)) self.hostdir = self._hostdir() self.log.info("Calculated temp dir for target \"{}\" is " - "\"{}\"".format(self.target_host, self.hostdir)) + "\"{}\"".format(self.target_host, self.hostdir)) self.base_path = os.path.join(base_path_parent, self.hostdir) self._init_permissions() From e2bb6295359a38bbf4bc856065649aae332191dc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 12 Jul 2016 20:15:08 +0200 Subject: [PATCH 0205/1332] Fix shell command not working after new error reporting. --- cdist/exec/local.py | 19 +++++++++++++------ cdist/shell.py | 3 ++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index bde2ceba..e2d07e8d 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -194,7 +194,8 @@ class Local(object): self.log.debug("Local mkdir: %s", path) os.makedirs(path, exist_ok=True) - def run(self, command, env=None, return_output=False, message_prefix=None): + def run(self, command, env=None, return_output=False, message_prefix=None, + save_output=True): """Run the given command with the given environment. Return the output as a string. @@ -216,11 +217,17 @@ class Local(object): env.update(message.env) try: - output, errout = exec_util.call_get_output(command, env=env) - self.log.debug("Local stdout: {}".format(output)) - self.log.debug("Local stderr: {}".format(errout)) - if return_output: - return output.decode() + if save_output: + output, errout = exec_util.call_get_output(command, env=env) + self.log.debug("Local stdout: {}".format(output)) + self.log.debug("Local stderr: {}".format(errout)) + if return_output: + return output.decode() + else: + # In some cases no output is saved. + # This is used for shell command, stdout and stderr + # must not be catched. + subprocess.check_call(command, env=env) except subprocess.CalledProcessError as e: exec_util.handle_called_process_error(e, command) except OSError as error: diff --git a/cdist/shell.py b/cdist/shell.py index 60faa2f8..dacff674 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -73,7 +73,8 @@ class Shell(object): self._init_environment() log.info("Starting shell...") - self.local.run([self.shell], self.env) + # save_output=False -> do not catch stdout and stderr + self.local.run([self.shell], self.env, save_output=False) log.info("Finished shell.") @classmethod From 1501590f8847e6c51190f089c15f26a03a0ad427 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Jul 2016 12:21:41 +0200 Subject: [PATCH 0206/1332] Fix missing stderr in case of script error in python >= 3.5. --- cdist/exec/util.py | 127 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 98 insertions(+), 29 deletions(-) diff --git a/cdist/exec/util.py b/cdist/exec/util.py index 6e04523b..9c8ff48d 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -25,7 +25,98 @@ from tempfile import TemporaryFile import cdist -STDERR_UNSUPPORTED = '' + +STDERR_UNSUPPORTED = '' + + +# IMPORTANT: +# with the code below in python 3.5 when command is executed and error +# occurs then stderr is not captured. +# As it seems from documentation, it is only captured when using +# subprocess.run method with stderr=subprocess.PIPE and is captured +# into CompletedProcess resulting object or into CalledProcessError +# in case of error (only if specified capturing). +# +# If using PIPE then the run is slow. run method uses communicate method +# and internally it uses buffering. +# +# For now we will use capturing only stdout. stderr is written directly to +# stderr from child process. +# +# STDERR_UNSUPPORTED = '' +# +# +# def call_get_output(command, env=None): +# """Run the given command with the given environment. +# Return the tuple of stdout and stderr output as a byte strings. +# """ +# +# assert isinstance(command, (list, tuple)), ( +# "list or tuple argument expected, got: {}".format(command)) +# +# if sys.version_info >= (3, 5): +# return call_get_out_err(command, env) +# else: +# return (call_get_stdout(command, env), STDERR_UNSUPPORTED) +# +# +# def handle_called_process_error(err, command): +# if sys.version_info >= (3, 5): +# errout = err.stderr +# else: +# errout = STDERR_UNSUPPORTED +# raise cdist.Error("Command failed: " + " ".join(command) + +# " with returncode: {} and stdout: {}, stderr: {}".format( +# err.returncode, err.output, errout)) +# +# +# def call_get_stdout(command, env=None): +# """Run the given command with the given environment. +# Return the stdout output as a byte string, stderr is ignored. +# """ +# assert isinstance(command, (list, tuple)), ( +# "list or tuple argument expected, got: {}".format(command)) +# +# with TemporaryFile() as fout: +# subprocess.check_call(command, env=env, stdout=fout) +# fout.seek(0) +# output = fout.read() +# +# return output +# +# +# def call_get_out_err(command, env=None): +# """Run the given command with the given environment. +# Return the tuple of stdout and stderr output as a byte strings. +# """ +# assert isinstance(command, (list, tuple)), ( +# "list or tuple argument expected, got: {}".format(command)) +# +# with TemporaryFile() as fout, TemporaryFile() as ferr: +# subprocess.check_call(command, env=env, +# stdout=fout, stderr=ferr) +# fout.seek(0) +# ferr.seek(0) +# output = (fout.read(), ferr.read()) +# +# return output + +# +# The code below with bufsize=0 does not work either, communicate +# internally uses buffering. It works in case of error, but if everything +# is ok and there is no output in stderr then execution is very very slow. +# +# def _call_get_out_err(command, env=None): +# """Run the given command with the given environment. +# Return the tuple of stdout and stderr output as a byte strings. +# """ +# assert isinstance(command, (list, tuple)), ( +# "list or tuple argument expected, got: {}".format(command)) +# +# result = subprocess.run(command, env=env, bufsize=0, +# stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) +# +# return (result.stdout, result.stderr) def call_get_output(command, env=None): @@ -35,24 +126,19 @@ def call_get_output(command, env=None): assert isinstance(command, (list, tuple)), ( "list or tuple argument expected, got: {}".format(command)) - - if sys.version_info >= (3, 5): - return call_get_out_err(command, env) - else: - return (call_get_stdout(command, env), STDERR_UNSUPPORTED) + return (_call_get_stdout(command, env), STDERR_UNSUPPORTED) def handle_called_process_error(err, command): - if sys.version_info >= (3, 5): - errout = err.stderr - else: - errout = STDERR_UNSUPPORTED + errout = STDERR_UNSUPPORTED raise cdist.Error("Command failed: " + " ".join(command) + - " with returncode: {} and stdout: {}, stderr: {}".format( + (" with returncode: {}\n" + "stdout: {}\n" + "stderr: {}").format( err.returncode, err.output, errout)) -def call_get_stdout(command, env=None): +def _call_get_stdout(command, env=None): """Run the given command with the given environment. Return the stdout output as a byte string, stderr is ignored. """ @@ -65,20 +151,3 @@ def call_get_stdout(command, env=None): output = fout.read() return output - - -def call_get_out_err(command, env=None): - """Run the given command with the given environment. - Return the tuple of stdout and stderr output as a byte strings. - """ - assert isinstance(command, (list, tuple)), ( - "list or tuple argument expected, got: {}".format(command)) - - with TemporaryFile() as fout, TemporaryFile() as ferr: - subprocess.check_call(command, env=env, - stdout=fout, stderr=ferr) - fout.seek(0) - ferr.seek(0) - output = (fout.read(), ferr.read()) - - return output From 7c55364cc2674aab5ad5b7b3629b0b3fd614c535 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jul 2016 08:20:07 +0200 Subject: [PATCH 0207/1332] Fix absent state for verbose in ccollect_source type. --- cdist/conf/type/__ccollect_source/manifest | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__ccollect_source/manifest b/cdist/conf/type/__ccollect_source/manifest index 89c2ef2b..b95b75c3 100755 --- a/cdist/conf/type/__ccollect_source/manifest +++ b/cdist/conf/type/__ccollect_source/manifest @@ -40,7 +40,9 @@ echo "$source" | __file "$source_file" --source - --state "$state" ################################################################################ # Booleans -if [ -f "$__object/parameter/verbose" ]; then +if [ "${state}" = "absent" ]; then + verbosestate="absent" +elif [ -f "$__object/parameter/verbose" ]; then verbosestate="present" else verbosestate="absent" From 2eab9b9598c62a50ffc71f02029ab0e8db199667 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jul 2016 08:22:05 +0200 Subject: [PATCH 0208/1332] Rm stderr debug output, stderr is not captured. --- cdist/exec/local.py | 3 ++- cdist/exec/remote.py | 3 ++- cdist/exec/util.py | 18 ++++++++++-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index e2d07e8d..d115bf24 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -220,7 +220,8 @@ class Local(object): if save_output: output, errout = exec_util.call_get_output(command, env=env) self.log.debug("Local stdout: {}".format(output)) - self.log.debug("Local stderr: {}".format(errout)) + # Currently, stderr is not captured. + # self.log.debug("Local stderr: {}".format(errout)) if return_output: return output.decode() else: diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index ff388e1d..b6ff8c1f 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -173,7 +173,8 @@ class Remote(object): try: output, errout = exec_util.call_get_output(command, env=os_environ) self.log.debug("Remote stdout: {}".format(output)) - self.log.debug("Remote stderr: {}".format(errout)) + # Currently, stderr is not captured. + # self.log.debug("Remote stderr: {}".format(errout)) if return_output: return output.decode() except subprocess.CalledProcessError as e: diff --git a/cdist/exec/util.py b/cdist/exec/util.py index 9c8ff48d..864a73a3 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -26,9 +26,6 @@ from tempfile import TemporaryFile import cdist -STDERR_UNSUPPORTED = '' - - # IMPORTANT: # with the code below in python 3.5 when command is executed and error # occurs then stderr is not captured. @@ -126,16 +123,21 @@ def call_get_output(command, env=None): assert isinstance(command, (list, tuple)), ( "list or tuple argument expected, got: {}".format(command)) - return (_call_get_stdout(command, env), STDERR_UNSUPPORTED) + return (_call_get_stdout(command, env), None) def handle_called_process_error(err, command): - errout = STDERR_UNSUPPORTED + # Currently, stderr is not captured. + # errout = None + # raise cdist.Error("Command failed: " + " ".join(command) + + # (" with returncode: {}\n" + # "stdout: {}\n" + # "stderr: {}").format( + # err.returncode, err.output, errout)) raise cdist.Error("Command failed: " + " ".join(command) + (" with returncode: {}\n" - "stdout: {}\n" - "stderr: {}").format( - err.returncode, err.output, errout)) + "stdout: {}").format( + err.returncode, err.output)) def _call_get_stdout(command, env=None): From 5b401096464690c6dcb790cd21367a2ef40ef26d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jul 2016 21:53:14 +0200 Subject: [PATCH 0209/1332] Prepare for new release 4.2.0. --- docs/changelog | 2 +- docs/web/cdist/install.mdwn | 3 ++ docs/web/cdist/pgp-key-EFD2AE4EC36B6901.asc | 52 +++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 docs/web/cdist/pgp-key-EFD2AE4EC36B6901.asc diff --git a/docs/changelog b/docs/changelog index a1a045a0..1b7724f7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.2.0: 2016-07-15 * Build: Make github signed release (Darko Poljak) * Core: Fix hostdir: use hash instead of target host (Steven Armstrong) * Core: pep8 (Darko Poljak) diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index b3724911..cff2d369 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -33,6 +33,9 @@ To install cdist, execute the following commands: cd cdist export PATH=$PATH:$(pwd -P)/bin +From version 4.2.0 cdist tags and github releases are signed. +You can get GPG public key used for signing [here](/software/cdist/pgp-key-EFD2AE4EC36B6901.asc). + #### Available versions in git * The active development takes place in the **master** branch diff --git a/docs/web/cdist/pgp-key-EFD2AE4EC36B6901.asc b/docs/web/cdist/pgp-key-EFD2AE4EC36B6901.asc new file mode 100644 index 00000000..1762d7c1 --- /dev/null +++ b/docs/web/cdist/pgp-key-EFD2AE4EC36B6901.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +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 +vsomtv+pm41l0JK+Xps= +=/2wY +-----END PGP PUBLIC KEY BLOCK----- From 42b5963c490c2601dd8e34bb28b96905020092ae Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jul 2016 22:06:42 +0200 Subject: [PATCH 0210/1332] Ignore *.pyc files. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 74014aba..4afa9f21 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ docs/src/cdist-reference.rst # Python: cache, distutils, distribution in general __pycache__/ +*.pyc MANIFEST dist/ cdist/version.py From c9f825d7efd8c5d80550445e89a53ac3723a6359 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jul 2016 22:15:46 +0200 Subject: [PATCH 0211/1332] Ensure gpg-agent is running for tag signing. --- bin/build-helper | 3 ++- bin/build-helper.freebsd | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index f9b21d76..5bde6cdf 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -169,7 +169,8 @@ eof # gpg verify signature # gpg --verify # gpg --no-default-keyring --keyring --verify - # + # Ensure gpg-agent is running. + gpg-agent git tag -s "$target_version" -m "$tagmessage" git push --tags diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 61a095cb..32677503 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -204,7 +204,8 @@ eof # gpg verify signature # gpg --verify # gpg --no-default-keyring --keyring --verify - # + # Ensure gpg-agent is running. + gpg-agent git tag -s "$target_version" -m "$tagmessage" git push --tags From 12faca578f61f316de81d5c98c5ec6db3cf9737a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jul 2016 22:21:07 +0200 Subject: [PATCH 0212/1332] gpg needs GPG_TTY env var set. --- bin/build-helper | 1 + bin/build-helper.freebsd | 1 + 2 files changed, 2 insertions(+) diff --git a/bin/build-helper b/bin/build-helper index 5bde6cdf..f0f1ac8f 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -170,6 +170,7 @@ eof # gpg --verify # gpg --no-default-keyring --keyring --verify # Ensure gpg-agent is running. + export GPG_TTY=$(tty) gpg-agent git tag -s "$target_version" -m "$tagmessage" diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 32677503..616c88b2 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -205,6 +205,7 @@ eof # gpg --verify # gpg --no-default-keyring --keyring --verify # Ensure gpg-agent is running. + export GPG_TTY=$(tty) gpg-agent git tag -s "$target_version" -m "$tagmessage" From 0f2cda06b197a7050ede44b9cb2d3eb807dd32c2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jul 2016 22:33:33 +0200 Subject: [PATCH 0213/1332] Fix arg num check. --- bin/build-helper | 2 +- bin/build-helper.freebsd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index f0f1ac8f..2bd62502 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -191,7 +191,7 @@ eof exit 1 fi token="$2" - if [ $# -ge 2 ] + if [ $# -gt 2 ] then archivename="$3" else diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 616c88b2..e1bac8ac 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -226,7 +226,7 @@ eof exit 1 fi token="$2" - if [ $# -ge 2 ] + if [ $# -gt 2 ] then archivename="$3" else From 5127bc2ef73a14695bfd3b9ea475c48a86259ba4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jul 2016 22:50:00 +0200 Subject: [PATCH 0214/1332] Ignore packages and signature files. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 4afa9f21..4258c2eb 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,10 @@ cdist/version.py _build/ docs/dist +# Ignore temp files used for signing +cdist-*.tar.gz +cdist-*.tar.gz.asc + # Packaging: Archlinux /PKGBUILD /cdist-*.pkg.tar.xz From 9256aa8d587f4b4e8eed847c923ea8f3baa50f1e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jul 2016 22:50:26 +0200 Subject: [PATCH 0215/1332] Fix pipe typo bug. --- bin/build-helper | 2 +- bin/build-helper.freebsd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 2bd62502..d1f30fc3 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -214,7 +214,7 @@ eof # get release ID repoid=$(curl "https://api.github.com/repos/ungleich/cdist/releases/tags/${tag}" \ - || python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ + | python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ || exit 1 curl -H "Authorization: token ${token}" \ diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index e1bac8ac..0a656f5e 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -249,7 +249,7 @@ eof # get release ID repoid=$(curl "https://api.github.com/repos/ungleich/cdist/releases/tags/${tag}" \ - || python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ + | python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ || exit 1 curl -H "Authorization: token ${token}" \ From ec425be6241185dc7eac4bc7cdf0f9573ff13f04 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 16 Jul 2016 00:07:13 +0200 Subject: [PATCH 0216/1332] Fix removing archive. Push new branch if builder not Nico. --- bin/build-helper | 2 +- bin/build-helper.freebsd | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index d1f30fc3..725c076f 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -225,7 +225,7 @@ eof || exit 1 # remove generated files (archive and asc) - if [ $# -ge 2] + if [ $# -eq 2] then rm -f "${archivename}" fi diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 0a656f5e..dee12d0e 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -260,7 +260,7 @@ eof || exit 1 # remove generated files (archive and asc) - if [ $# -ge 2] + if [ $# -eq 2] then rm -f "${archivename}" fi @@ -346,6 +346,8 @@ eof freebsd) # if we are not Nico :) then just push, no mirror git push + # push also new branch and set up tracking + git push -u origin "${target_branch}" ;; *) make helper=${helper} WEBDIR=${WEBDIR} pub From 509a728211b79554393d4c88e530de68270a9e2e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 16 Jul 2016 00:49:24 +0200 Subject: [PATCH 0217/1332] Fix lost refs for feature files export. --- docs/src/cdist-reference.rst.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index 42eced05..b168d781 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -70,6 +70,10 @@ confdir By default it consists of everything in \$HOME/.cdist and cdist/conf/. For more details see cdist(1) +confdir/files/ + Cdist does not care about this directory besides providing access to it. + It is thought to be a general file storage area. + confdir/manifest/init This is the central entry point. It is an executable (+x bit set) shell script that can use @@ -193,6 +197,10 @@ The following environment variables are exported by cdist: __explorer Directory that contains all global explorers. Available for: initial manifest, explorer, type explorer, shell +__files + Directory that contains content from the "files" subdirectories + from the configuration directories. + Available for: initial manifest, type manifest, type gencode, shell __manifest Directory that contains the initial manifest. Available for: initial manifest, type manifest, shell From ccbb9697eb0b0df24e42f22f2991ddb503ed0b08 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 16 Jul 2016 00:50:01 +0200 Subject: [PATCH 0218/1332] Clean sphinx docs before building. --- Makefile | 4 ++++ bin/build-helper | 2 ++ bin/build-helper.freebsd | 2 ++ 3 files changed, 8 insertions(+) diff --git a/Makefile b/Makefile index 05c8004e..6d1e1de3 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,7 @@ PYTHON_VERSION=cdist/version.py SPHINXM=make -C $(DOCS_SRC_DIR) man SPHINXH=make -C $(DOCS_SRC_DIR) html +SPHINXC=make -C $(DOCS_SRC_DIR) clean ################################################################################ # Manpages # @@ -71,6 +72,9 @@ html: $(MANTYPES) $(DOCSREF) $(PYTHON_VERSION) docs: man html +docs-clean: + $(SPHINXC) + # Manpages #5: release part MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) HTMLBUILDDIR=docs/dist/html diff --git a/bin/build-helper b/bin/build-helper index 725c076f..55c75ef4 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -284,6 +284,8 @@ eof "$0" check-unittest # Generate documentation (man and html) + # First, clean old generated docs + make docs-clean make docs # Generate speeches (indirect check if they build) diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index dee12d0e..9051ab0d 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -319,6 +319,8 @@ eof "$0" check-unittest # Generate documentation (man and html) + # First, clean old generated docs + make helper=${helper} WEBDIR=${WEBDIR} docs-clean make helper=${helper} WEBDIR=${WEBDIR} docs # Generate speeches (indirect check if they build) From 8571192aa580b25e1a3b57aea02ae82e92fe419a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 16 Jul 2016 00:51:37 +0200 Subject: [PATCH 0219/1332] Clean stuff after signing release. --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 6d1e1de3..71d128fa 100644 --- a/Makefile +++ b/Makefile @@ -229,6 +229,10 @@ clean: rm -f MANIFEST PKGBUILD rm -rf dist/ + # Signed release + rm -f cdist-*.tar.gz + rm -f cdist-*.tar.gz.asc + distclean: clean rm -f cdist/version.py From 804570d8743297b85e464d4ab9516f0edd127476 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 16 Jul 2016 00:55:54 +0200 Subject: [PATCH 0220/1332] 4.2.0 -> second run. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 1b7724f7..7873fff0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -4.2.0: 2016-07-15 +4.2.0: 2016-07-16 * Build: Make github signed release (Darko Poljak) * Core: Fix hostdir: use hash instead of target host (Steven Armstrong) * Core: pep8 (Darko Poljak) From c456284cefb11da97f2bc23f88557ca0b93f7284 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 16 Jul 2016 01:38:22 +0200 Subject: [PATCH 0221/1332] For release generate version file with target version. --- bin/build-helper | 7 ++++++- bin/build-helper.freebsd | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 55c75ef4..ff628847 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -245,7 +245,7 @@ eof "$0" pep8 # Generate version file to be included in packaging - "$0" version + "$0" target-version # Ensure the git status is clean, else abort if ! git diff-index --name-only --exit-code HEAD ; then @@ -382,6 +382,11 @@ eof echo "VERSION = \"$(git describe)\"" > cdist/version.py ;; + target-version) + target_version=$($0 changelog-version) + echo "VERSION = \"${target_version}\"" > cdist/version.py + ;; + *) echo "Unknown helper target $@ - aborting" exit 1 diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 9051ab0d..e5b081ff 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -280,7 +280,7 @@ eof "$0" pep8 # Generate version file to be included in packaging - "$0" version + "$0" target-version # Ensure the git status is clean, else abort if ! git diff-index --name-only --exit-code HEAD ; then @@ -444,6 +444,11 @@ eof echo "VERSION = \"$(git describe)\"" > cdist/version.py ;; + target-version) + target_version=$($0 changelog-version) + echo "VERSION = \"${target_version}\"" > cdist/version.py + ;; + *) echo "Unknown helper target $@ - aborting" exit 1 From a88c8d2afb0b8ce36e99ed815efab40427c347be Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 16 Jul 2016 14:43:26 +0200 Subject: [PATCH 0222/1332] Prepare for next. --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 7873fff0..6e3761a4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,8 @@ Changelog --------- +next: + 4.2.0: 2016-07-16 * Build: Make github signed release (Darko Poljak) * Core: Fix hostdir: use hash instead of target host (Steven Armstrong) From 87d6a9c33666d4c351230150c2be9b0efcda032c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 18 Jul 2016 19:43:05 +0200 Subject: [PATCH 0223/1332] Fix line begining with . is a macro for man page. --- cdist/conf/type/__apt_key/man.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__apt_key/man.rst b/cdist/conf/type/__apt_key/man.rst index 488a1a06..7ee2a621 100644 --- a/cdist/conf/type/__apt_key/man.rst +++ b/cdist/conf/type/__apt_key/man.rst @@ -25,8 +25,8 @@ keyid the id of the key to add. Defaults to __object_id keyserver - the keyserver from which to fetch the key. If omitted the default set in - ./parameter/default/keyserver is used. + the keyserver from which to fetch the key. If omitted the default set + in ./parameter/default/keyserver is used. EXAMPLES From 0d82c379284b2515a3d72332fd4848fd615f680a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 18 Jul 2016 19:43:26 +0200 Subject: [PATCH 0224/1332] Fix spelling errors (Dmitry Bogatov). --- cdist/conf/type/__consul_agent/man.rst | 2 +- cdist/conf/type/__key_value/man.rst | 4 ++-- cdist/conf/type/__staged_file/man.rst | 2 +- cdist/conf/type/__zypper_service/man.rst | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__consul_agent/man.rst b/cdist/conf/type/__consul_agent/man.rst index 5a35a2cc..fcbf112d 100644 --- a/cdist/conf/type/__consul_agent/man.rst +++ b/cdist/conf/type/__consul_agent/man.rst @@ -111,7 +111,7 @@ syslog enables logging to syslog verify-incoming - enforce the use of TLS and verify a client's authenticity on incomming connections + enforce the use of TLS and verify a client's authenticity on incoming connections verify-outgoing enforce the use of TLS and verify the peers authenticity on outgoing connections diff --git a/cdist/conf/type/__key_value/man.rst b/cdist/conf/type/__key_value/man.rst index 80d6aa89..0d0ad3ae 100644 --- a/cdist/conf/type/__key_value/man.rst +++ b/cdist/conf/type/__key_value/man.rst @@ -72,13 +72,13 @@ EXAMPLES --delimiter ' = ' --comment '# my linux kernel should act as a router' # Remove existing key/value - __key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '=' + __key_value LEGACY_KEY --file /etc/somefile --state absent --delimiter '=' MORE INFORMATION ---------------- This type try to handle as many values as possible, so it doesn't use regexes. -So you need to exactly specify the key and delimiter. Delimiter can be of any lenght. +So you need to exactly specify the key and delimiter. Delimiter can be of any length. AUTHORS diff --git a/cdist/conf/type/__staged_file/man.rst b/cdist/conf/type/__staged_file/man.rst index 3d8ee966..4c54e5f5 100644 --- a/cdist/conf/type/__staged_file/man.rst +++ b/cdist/conf/type/__staged_file/man.rst @@ -15,7 +15,7 @@ cdist) and then deployed to the target host using the __file type. REQUIRED PARAMETERS ------------------- source - the URL from which to retreive the source file. + the URL from which to retrieve the source file. e.g. * https://dl.bintray.com/mitchellh/consul/0.4.1_linux_amd64.zip diff --git a/cdist/conf/type/__zypper_service/man.rst b/cdist/conf/type/__zypper_service/man.rst index c596dea0..c76a5ffc 100644 --- a/cdist/conf/type/__zypper_service/man.rst +++ b/cdist/conf/type/__zypper_service/man.rst @@ -20,10 +20,10 @@ uri OPTIONAL PARAMETERS ------------------- service_desc - If supplied, use the service_desc and not the object id as descritpion for the service. + If supplied, use the service_desc and not the object id as description for the service. state - Either "present" or "absent", defaults to "present" + Either "present" or "absent", defaults to "present" type Defaults to "ris", the standard type of services at SLES11. For other values, see manpage of zypper. From 1815936b7d4473fca51abe967fb8de5a34495e90 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 18 Jul 2016 19:47:36 +0200 Subject: [PATCH 0225/1332] Fix import error when PYTHONPATH is not set. --- docs/src/conf.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/src/conf.py b/docs/src/conf.py index dee11095..463bcedd 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -15,7 +15,6 @@ import sys import os -import cdist.version import sphinx_rtd_theme # If extensions (or modules to document with autodoc) are in another directory, @@ -23,7 +22,11 @@ import sphinx_rtd_theme # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath(os.path.join( - os.path.dirname(os.path.realpath(__file__)), "../../"))) + os.path.dirname(os.path.realpath(__file__)), "..", ".."))) + +# Import cdist after sys.path fixup above. + +import cdist.version # nopep8 - ignore error that import is not at top # -- General configuration ------------------------------------------------ From 25bfad452c902f100282301b0f85e9a9edcc7ef1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 18 Jul 2016 19:48:54 +0200 Subject: [PATCH 0226/1332] Fix missing trailing slash for archive prefix. --- bin/build-helper | 2 +- bin/build-helper.freebsd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index ff628847..5fd4941c 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -196,7 +196,7 @@ eof archivename="$3" else archivename="cdist-${tag}.tar.gz" - git archive --prefix="cdist-${tag}" -o "${archivename}" "${tag}" \ + git archive --prefix="cdist-${tag}/" -o "${archivename}" "${tag}" \ || exit 1 fi gpg --armor --detach-sign "${archivename}" || exit 1 diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index e5b081ff..cea75afc 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -231,7 +231,7 @@ eof archivename="$3" else archivename="cdist-${tag}.tar.gz" - git archive --prefix="cdist-${tag}" -o "${archivename}" "${tag}" \ + git archive --prefix="cdist-${tag}/" -o "${archivename}" "${tag}" \ || exit 1 fi gpg --armor --detach-sign "${archivename}" || exit 1 From 25e69d130211b9262e4c5d0496f6304731d516e6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 18 Jul 2016 19:58:21 +0200 Subject: [PATCH 0227/1332] Fix release signing: upload also archive that is signed. --- bin/build-helper | 7 +++++++ bin/build-helper.freebsd | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/bin/build-helper b/bin/build-helper index 5fd4941c..16ad67ee 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -217,6 +217,13 @@ eof | python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ || exit 1 + # upload archive and then signature + curl -H "Authorization: token ${token}" \ + -H "Accept: application/vnd.github.manifold-preview" \ + -H "Content-Type: application/x-gtar" \ + --data-binary @${archivename} \ + "https://uploads.github.com/repos/ungleich/cdist/releases/${repoid}/assets?name=${archivename}" \ + || exit 1 curl -H "Authorization: token ${token}" \ -H "Accept: application/vnd.github.manifold-preview" \ -H "Content-Type: application/pgp-signature" \ diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index cea75afc..829fbf09 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -252,6 +252,13 @@ eof | python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ || exit 1 + # upload archive and then signature + curl -H "Authorization: token ${token}" \ + -H "Accept: application/vnd.github.manifold-preview" \ + -H "Content-Type: application/x-gtar" \ + --data-binary @${archivename} \ + "https://uploads.github.com/repos/ungleich/cdist/releases/${repoid}/assets?name=${archivename}" \ + || exit 1 curl -H "Authorization: token ${token}" \ -H "Accept: application/vnd.github.manifold-preview" \ -H "Content-Type: application/pgp-signature" \ From b7d2ec4b6e0aa75fcc1b4d0f33d55d191f440fdc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 18 Jul 2016 20:12:48 +0200 Subject: [PATCH 0228/1332] 4.2.1 changelog --- docs/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/changelog b/docs/changelog index 7873fff0..d85af785 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,12 @@ Changelog --------- +4.2.1: 2016-07-18 + * Build: Fix signed release (Darko Poljak) + * Build: Fix building docs (Darko Poljak) + * Documentation: Fix man pages (Dmitry Bogatov) + * Documentation: Fix spellings (Dmitry Bogatov) + 4.2.0: 2016-07-16 * Build: Make github signed release (Darko Poljak) * Core: Fix hostdir: use hash instead of target host (Steven Armstrong) From 4e5b9492b81998c680ce84a670d80f2087ea9e8e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 19 Jul 2016 13:00:14 +0200 Subject: [PATCH 0229/1332] Update docs with dist conf dir and .cdist conf dir info. --- docs/src/cdist-quickstart.rst | 6 ++++++ docs/src/man1/cdist.rst | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/src/cdist-quickstart.rst b/docs/src/cdist-quickstart.rst index 20c33cb8..7c967691 100644 --- a/docs/src/cdist-quickstart.rst +++ b/docs/src/cdist-quickstart.rst @@ -68,6 +68,12 @@ code into your shell to get started and configure localhost:: # Find out that cdist created /etc/cdist-configured ls -l /etc/cdist-configured +Note: cdist/conf is configuration directory shipped with cdist distribution. +If exists, ~/.cdist, is also automatically used as cdist configuration +directory. So in the above example you could create ~/.cdist directory, +then ~/.cdist/manifest sub-directory and create init manifest +~/.cdist/manifest/init. + That's it, you've successfully used cdist to configure your first host! Continue reading the next sections, to understand what you did and how to create a more sophisticated configuration. diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 5b821d46..9ac3b1f4 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -102,8 +102,21 @@ usage. Its primary use is for debugging type parameters. .. option:: -s/--shell - Select shell to use, defaults to current shell + Select shell to use, defaults to current shell. Used shell should + be POSIX compatible shell. +FILES +----- +~/.cdist + Your personal cdist config directory. If exists it will be + automatically used. +${cdist_prefix}/cdist/conf + The distribution configuration directory. ${cdist_prefix} is + installation-dependent. If you install cdist using git it is + equal to your cloned directory. If you install it using python + pip then it is equal to + ${prefix}/lib/python/site-packages/cdist sub-directory + where ${prefix}, by default, is /usr/local (see :strong:`python`\ (1)). EXAMPLES -------- From cab0381c2ab9a7041e4e8fca45f6dce9b019d991 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Jul 2016 07:55:48 +0200 Subject: [PATCH 0230/1332] Update license to GPLv3+ for my types and cdist man pages. --- cdist/conf/type/__pyvenv/man.rst | 2 +- docs/src/man1/cdist.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__pyvenv/man.rst b/cdist/conf/type/__pyvenv/man.rst index 977501e6..d7de92fa 100644 --- a/cdist/conf/type/__pyvenv/man.rst +++ b/cdist/conf/type/__pyvenv/man.rst @@ -75,5 +75,5 @@ Darko Poljak COPYING ------- Copyright \(C) 2016 Darko Poljak. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +granted under the terms of the GNU General Public License v3 or later (GPLv3+). diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 9ac3b1f4..114b42fe 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -191,4 +191,4 @@ Nico Schottelius COPYING ------- Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +granted under the terms of the GNU General Public License v3 or later (GPLv3+). From 7e57575f9e1ad0909750d116e9eabc15c1c77e2c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Jul 2016 08:16:58 +0200 Subject: [PATCH 0231/1332] Improve and fix reference doc and cdist man page. --- docs/src/cdist-reference.rst.sh | 59 +++++++++++++++++---------------- docs/src/man1/cdist.rst | 41 +++++++++++++---------- 2 files changed, 55 insertions(+), 45 deletions(-) diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index b168d781..06842450 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -56,19 +56,19 @@ cat << eof Paths ----- \$HOME/.cdist - The standard cdist configuration directory relative to your home directory - This is usually the place you want to store your site specific configuration + The standard cdist configuration directory relative to your home directory. + This is usually the place you want to store your site specific configuration. cdist/conf/ - The distribution configuration directory - This contains types and explorers to be used + The distribution configuration directory. + This contains types and explorers to be used. confdir Cdist will use all available configuration directories and create a temporary confdir containing links to the real configuration directories. This way it is possible to merge configuration directories. By default it consists of everything in \$HOME/.cdist and cdist/conf/. - For more details see cdist(1) + For more details see cdist(1). confdir/files/ Cdist does not care about this directory besides providing access to it. @@ -99,16 +99,16 @@ confdir/type// This directory is referenced by the variable __type (see below). confdir/type//man.rst - Manpage in reStructuredText format (required for inclusion into upstream) + Manpage in reStructuredText format (required for inclusion into upstream). confdir/type//manifest Used to generate additional objects from a type. confdir/type//gencode-local - Used to generate code to be executed on the source host + Used to generate code to be executed on the source host. confdir/type//gencode-remote - Used to generate code to be executed on the target host + Used to generate code to be executed on the target host. confdir/type//parameter/required Parameters required by type, \n separated list. @@ -184,7 +184,7 @@ files (for instance to store template results). changed This empty file exists in an object directory, if the object has - code to be executed (either remote or local) + code to be executed (either remote or local). stdin This file exists and contains data, if data was provided on stdin when the type was called. @@ -196,67 +196,70 @@ The following environment variables are exported by cdist: __explorer Directory that contains all global explorers. - Available for: initial manifest, explorer, type explorer, shell + Available for: initial manifest, explorer, type explorer, shell. __files Directory that contains content from the "files" subdirectories from the configuration directories. - Available for: initial manifest, type manifest, type gencode, shell + Available for: initial manifest, type manifest, type gencode, shell. __manifest Directory that contains the initial manifest. - Available for: initial manifest, type manifest, shell + Available for: initial manifest, type manifest, shell. __global Directory that contains generic output like explorer. - Available for: initial manifest, type manifest, type gencode, shell + Available for: initial manifest, type manifest, type gencode, shell. __messages_in File to read messages from. - Available for: initial manifest, type manifest, type gencode + Available for: initial manifest, type manifest, type gencode. __messages_out File to write messages. - Available for: initial manifest, type manifest, type gencode + Available for: initial manifest, type manifest, type gencode. __object Directory that contains the current object. - Available for: type manifest, type explorer, type gencode and code scripts + Available for: type manifest, type explorer, type gencode and code scripts. __object_id The type unique object id. - Available for: type manifest, type explorer, type gencode and code scripts + Available for: type manifest, type explorer, type gencode and code scripts. Note: The leading and the trailing "/" will always be stripped (caused by the filesystem database and ensured by the core). Note: Double slashes ("//") will not be fixed and result in an error. __object_name The full qualified name of the current object. - Available for: type manifest, type explorer, type gencode + Available for: type manifest, type explorer, type gencode. __target_host The host we are deploying to. - Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell + Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell. __type Path to the current type. - Available for: type manifest, type gencode + Available for: type manifest, type gencode. __type_explorer Directory that contains the type explorers. - Available for: type explorer + Available for: type explorer. Environment variables (for writing) ----------------------------------- The following environment variables influence the behaviour of cdist: require - Setup dependencies between objects (see \`cdist manifest \`_) + Setup dependencies between objects (see \`cdist manifest \`_). + +CDIST_PATH + Colon delimited list of config directories. CDIST_LOCAL_SHELL - Use this shell locally instead of /bin/sh to execute scripts + Use this shell locally instead of /bin/sh to execute scripts. CDIST_REMOTE_SHELL - Use this shell remotely instead of /bin/sh to execute scripts + Use this shell remotely instead of /bin/sh to execute scripts. CDIST_OVERRIDE - Allow overwriting type parameters (see \`cdist manifest \`_) + Allow overwriting type parameters (see \`cdist manifest \`_). CDIST_ORDER_DEPENDENCY - Create dependencies based on the execution order (see \`cdist manifest \`_) + Create dependencies based on the execution order (see \`cdist manifest \`_). CDIST_REMOTE_EXEC - Use this command for remote execution (should behave like ssh) + Use this command for remote execution (should behave like ssh). CDIST_REMOTE_COPY - Use this command for remote copy (should behave like scp) + Use this command for remote copy (should behave like scp). eof diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 114b42fe..5a4873f7 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -23,7 +23,10 @@ SYNOPSIS DESCRIPTION ----------- cdist is the frontend executable to the cdist configuration management. -cdist supports different subcommands as explained below. +It supports different subcommands as explained below. + +It is written in Python so it requires :strong:`python`\ (1) to be installed. +It requires a minimal Python version 3.2. GENERAL ------- @@ -54,7 +57,7 @@ cdist posters - a must have for every office. CONFIG ------ -Configure one or more hosts +Configure one or more hosts. .. option:: -c CONF_DIR, --conf-dir CONF_DIR @@ -110,13 +113,9 @@ FILES ~/.cdist Your personal cdist config directory. If exists it will be automatically used. -${cdist_prefix}/cdist/conf - The distribution configuration directory. ${cdist_prefix} is - installation-dependent. If you install cdist using git it is - equal to your cloned directory. If you install it using python - pip then it is equal to - ${prefix}/lib/python/site-packages/cdist sub-directory - where ${prefix}, by default, is /usr/local (see :strong:`python`\ (1)). +cdist/conf + The distribution configuration directory. It contains official types and + explorers. This path is relative to cdist installation directory. EXAMPLES -------- @@ -162,26 +161,34 @@ TMPDIR, TEMP, TMP more information. This is rather useful, if the standard directory used does not allow executables. +CDIST_PATH + Colon delimited list of config directories. + CDIST_LOCAL_SHELL - Selects shell for local script execution, defaults to /bin/sh + Selects shell for local script execution, defaults to /bin/sh. CDIST_REMOTE_SHELL - Selects shell for remote scirpt execution, defaults to /bin/sh + Selects shell for remote scirpt execution, defaults to /bin/sh. + +CDIST_OVERRIDE + Allow overwriting type parameters. + +CDIST_ORDER_DEPENDENCY + Create dependencies based on the execution order. CDIST_REMOTE_EXEC - Use this command for remote execution (should behave like ssh) + Use this command for remote execution (should behave like ssh). CDIST_REMOTE_COPY - Use this command for remote copy (should behave like scp) + Use this command for remote copy (should behave like scp). EXIT STATUS ----------- The following exit values shall be returned: -0 - Successful completion -1 - One or more host configurations failed +0 Successful completion. + +1 One or more host configurations failed. AUTHORS From 4c106752f1cc6fb381178def90b9fa47da96b610 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 22 Jul 2016 08:12:18 +0200 Subject: [PATCH 0232/1332] Add new types, __keyboard and __locale_system, contributed by Carlos Ortigoza. --- cdist/conf/type/__keyboard/man.rst | 37 ++++++++++++++ cdist/conf/type/__keyboard/manifest | 50 +++++++++++++++++++ cdist/conf/type/__keyboard/parameter/required | 1 + cdist/conf/type/__keyboard/singleton | 0 cdist/conf/type/__locale_system/man.rst | 45 +++++++++++++++++ cdist/conf/type/__locale_system/manifest | 43 ++++++++++++++++ .../__locale_system/parameter/default/locale | 1 + .../type/__locale_system/parameter/optional | 1 + cdist/conf/type/__locale_system/singleton | 0 9 files changed, 178 insertions(+) create mode 100644 cdist/conf/type/__keyboard/man.rst create mode 100644 cdist/conf/type/__keyboard/manifest create mode 100644 cdist/conf/type/__keyboard/parameter/required create mode 100644 cdist/conf/type/__keyboard/singleton create mode 100644 cdist/conf/type/__locale_system/man.rst create mode 100644 cdist/conf/type/__locale_system/manifest create mode 100644 cdist/conf/type/__locale_system/parameter/default/locale create mode 100644 cdist/conf/type/__locale_system/parameter/optional create mode 100644 cdist/conf/type/__locale_system/singleton diff --git a/cdist/conf/type/__keyboard/man.rst b/cdist/conf/type/__keyboard/man.rst new file mode 100644 index 00000000..0eb4cde9 --- /dev/null +++ b/cdist/conf/type/__keyboard/man.rst @@ -0,0 +1,37 @@ +cdist-type__keyboard(7) +======================= + +NAME +---- +cdit-type__keyboard - Set keyboard layout + + +DESCRIPTION +----------- +This cdist type allows you to modify keyboard layout. + + +REQUIRED PARAMETERS +------------------- +type + Any valid type, for example "us" + + +EXAMPLES +-------- + +.. code-block:: sh + + # Set keyboard type to "us" + __keyboard --type "us" + + +AUTHORS +------- +Carlos Ortigoza + + +COPYING +------- +Copyright \(C) 2016 Carlos Ortigoza. Free use of this software is +granted under the terms of the GNU General Public License v3 or later (GPLv3+). diff --git a/cdist/conf/type/__keyboard/manifest b/cdist/conf/type/__keyboard/manifest new file mode 100644 index 00000000..3bfddf0b --- /dev/null +++ b/cdist/conf/type/__keyboard/manifest @@ -0,0 +1,50 @@ +#!/bin/sh +# +# Carlos Ortigoza (carlos.ortigoza at ungleich.ch) +# +# 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 . +# +# +# Configure keyboard type by modifying /etc/sysconfig/keyboard file. +# + +os=$(cat "$__global/explorer/os") +keyboard_type="$(cat "$__object/parameter/type")" + +case "$os" in + centos) + __file /etc/sysconfig/keyboard \ + --owner root --group root --mode 644 \ + --state exists + + require="__file/etc/sysconfig/keyboard" \ + __key_value KEYTABLE \ + --file /etc/sysconfig/keyboard \ + --delimiter '=' \ + --value "\"$keyboard_type\"" + + require="__file/etc/sysconfig/keyboard" \ + __key_value LAYOUT \ + --file /etc/sysconfig/keyboard \ + --delimiter '=' \ + --value "\"$keyboard_type\"" + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__keyboard/parameter/required b/cdist/conf/type/__keyboard/parameter/required new file mode 100644 index 00000000..c3dc0520 --- /dev/null +++ b/cdist/conf/type/__keyboard/parameter/required @@ -0,0 +1 @@ +type \ No newline at end of file diff --git a/cdist/conf/type/__keyboard/singleton b/cdist/conf/type/__keyboard/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__locale_system/man.rst b/cdist/conf/type/__locale_system/man.rst new file mode 100644 index 00000000..8eaa5868 --- /dev/null +++ b/cdist/conf/type/__locale_system/man.rst @@ -0,0 +1,45 @@ +cdist-type__locale_system(7) +============================ + +NAME +---- +cdit-type__locale_system - Set system-wide locale + + +DESCRIPTION +----------- +This cdist type allows you to modify system-wide locale. + + +OPTIONAL PARAMETERS +------------------- +locale + Any valid locale, defaults to en_US.UTF-8 + + +EXAMPLES +-------- + +.. code-block:: sh + + # Set system locale to en_US.UTF-8 + __locale_system + + # Same as above, but more explicit + __locale_system --locale en_US.UTF-8 + + +SEE ALSO +-------- +:strong:`locale`\ (1), :strong:`localedef`\ (1) + + +AUTHORS +------- +Carlos Ortigoza + + +COPYING +------- +Copyright \(C) 2016 Carlos Ortigoza. Free use of this software is +granted under the terms of the GNU General Public License v3 or later (GPLv3+). diff --git a/cdist/conf/type/__locale_system/manifest b/cdist/conf/type/__locale_system/manifest new file mode 100644 index 00000000..065b33c3 --- /dev/null +++ b/cdist/conf/type/__locale_system/manifest @@ -0,0 +1,43 @@ +#!/bin/sh +# +# Carlos Ortigoza (carlos.ortigoza at ungleich.ch) +# +# 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 . +# +# +# Configure system-wide locale by modifying i18n file. +# + +os=$(cat "$__global/explorer/os") +locale="$(cat "$__object/parameter/locale")" + +case "$os" in + centos) + __file /etc/sysconfig/i18n \ + --owner root --group root --mode 644 \ + --state exists + require="__file/etc/sysconfig/i18n" \ + __key_value LANG \ + --file /etc/sysconfig/i18n \ + --delimiter '=' \ + --value "\"$locale\"" + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__locale_system/parameter/default/locale b/cdist/conf/type/__locale_system/parameter/default/locale new file mode 100644 index 00000000..927508f3 --- /dev/null +++ b/cdist/conf/type/__locale_system/parameter/default/locale @@ -0,0 +1 @@ +en_US.UTF-8 diff --git a/cdist/conf/type/__locale_system/parameter/optional b/cdist/conf/type/__locale_system/parameter/optional new file mode 100644 index 00000000..1fc74d6c --- /dev/null +++ b/cdist/conf/type/__locale_system/parameter/optional @@ -0,0 +1 @@ +locale \ No newline at end of file diff --git a/cdist/conf/type/__locale_system/singleton b/cdist/conf/type/__locale_system/singleton new file mode 100644 index 00000000..e69de29b From 88ec06d06fdd2cf0907e8f36614d20f970279ace Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Fri, 22 Jul 2016 09:55:44 +0300 Subject: [PATCH 0233/1332] new type: __hosts This type adds or removes entries from /etc/hosts, ensuring that same hostname can never resolve to several different ip addresses. Signed-off-by: Dmitry Bogatov --- cdist/conf/type/__hosts/man.rst | 55 +++++++++++++++++++ cdist/conf/type/__hosts/manifest | 49 +++++++++++++++++ .../conf/type/__hosts/parameter/default/state | 1 + cdist/conf/type/__hosts/parameter/optional | 2 + 4 files changed, 107 insertions(+) create mode 100644 cdist/conf/type/__hosts/man.rst create mode 100755 cdist/conf/type/__hosts/manifest create mode 100644 cdist/conf/type/__hosts/parameter/default/state create mode 100644 cdist/conf/type/__hosts/parameter/optional diff --git a/cdist/conf/type/__hosts/man.rst b/cdist/conf/type/__hosts/man.rst new file mode 100644 index 00000000..f89a619c --- /dev/null +++ b/cdist/conf/type/__hosts/man.rst @@ -0,0 +1,55 @@ +cdist-type__hosts(7) +==================== + +NAME +---- + +cdist-type__hosts - manage entries in /etc/hosts + +DESCRIPTION +----------- + +Add or remove entries from */etc/hosts* file. + +OPTIONAL PARAMETERS +------------------- + +state + + If state is ``present``, make *object_id* resolve to *ip*. If + state is ``absent``, *object_id* will no longer resolve to + anything via */etc/hosts*. + +ip + + IP address, to which hostname (=\ *object_id*) must resolve. If + state is ``present``, this parameter is mandatory, if state is + ``absent``, this parameter is silently ignored. + +EXAMPLES +-------- + +.. code-block:: sh + + # Now `funny' resolves to 192.168.1.76, + __hosts funny --ip 192.168.1.76 + # and `happy' does not resolve (at least via /etc/hosts) + __hosts happy --state absent + +SEE ALSO +-------- + +:strong:`hosts`\ (5) + +AUTHORS +------- + +Dmitry Bogatov + + +COPYING +------- + +Copyright (C) 2015,2016 Dmitry Bogatov. Free use of this software is granted +under the terms of the GNU General Public License version 3 or later +(GPLv3+). diff --git a/cdist/conf/type/__hosts/manifest b/cdist/conf/type/__hosts/manifest new file mode 100755 index 00000000..99a06c09 --- /dev/null +++ b/cdist/conf/type/__hosts/manifest @@ -0,0 +1,49 @@ +#!/bin/sh +# Copyright (C) 2015 Bogatov Dmitry +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +hostname="$__object_id" +state="$(cat "$__object/parameter/state")" + +# First remove all lines for given hostname and then insert again. +# Otherwise, we risk having multiple entries for same hostname. +# +# There is a corner case, which we do not handle. Namely, /etc/hosts +# format allows several host names on single line, like following: +# +# 192.168.15.16 foo bar +# +# If this type manages hostname `foo', then hostname bar will get erased. + +__line "__hosts/delete/${hostname}" \ + --state absent \ + --regex " ${hostname}[ ]*$" \ + --file /etc/hosts +export require="__line/__hosts/delete/${hostname}" + +case "$state" in + absent) + : # Nothing to do + ;; + present) + ip="$(cat "$__object/parameter/ip")" + __line "__hosts/insert/${hostname}" \ + --line "${ip} ${hostname}" \ + --file /etc/hosts + ;; + *) + echo "ERROR: type (${__type##*/}) does not support state \`$state'" + exit 1 +esac diff --git a/cdist/conf/type/__hosts/parameter/default/state b/cdist/conf/type/__hosts/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__hosts/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__hosts/parameter/optional b/cdist/conf/type/__hosts/parameter/optional new file mode 100644 index 00000000..411fc5d2 --- /dev/null +++ b/cdist/conf/type/__hosts/parameter/optional @@ -0,0 +1,2 @@ +state +ip From 2011db16a8ef409cf8219118e11734adc3e91bf3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 23 Jul 2016 15:10:32 +0200 Subject: [PATCH 0234/1332] Add scripts/cdist to pep8 check. --- bin/build-helper | 2 +- bin/build-helper.freebsd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 16ad67ee..2a6e61da 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -360,7 +360,7 @@ eof ;; pep8) - pep8 ${basedir} | less + pep8 "${basedir}" "${basedir}/scripts/cdist" | less echo "Please review pep8 report." while true do diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 829fbf09..4e4c4c9d 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -422,7 +422,7 @@ eof ;; pep8) - pep8 ${basedir} | less + pep8 "${basedir}" "${basedir}/scripts/cdist" | less echo "Please review pep8 report." while true do From dacb5720c51da94706fa6d5fbd89c37e9d2ed560 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 23 Jul 2016 15:11:14 +0200 Subject: [PATCH 0235/1332] Create hash func for string args to be used cdist wide. --- cdist/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cdist/__init__.py b/cdist/__init__.py index b7436b5a..f58bc15b 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -21,6 +21,7 @@ import os import subprocess +import hashlib import cdist.version @@ -82,3 +83,11 @@ def file_to_list(filename): lines = [] return lines + + +def str_hash(s): + """Return hash of string s""" + if isinstance(s, str): + return hashlib.md5(s.encode('utf-8')).hexdigest() + else: + raise Error("str_hash param should be string") From ca3644a08a11326f834b005d927c97d149dabb9b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 23 Jul 2016 16:00:07 +0200 Subject: [PATCH 0236/1332] Add pep8 target. --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 71d128fa..417140c5 100644 --- a/Makefile +++ b/Makefile @@ -246,3 +246,6 @@ pub: test: $(helper) $@ + +pep8: + $(helper) $@ From 6f28fc2db2c856761a7b5fff2466afac7685c1a6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 23 Jul 2016 16:13:59 +0200 Subject: [PATCH 0237/1332] Fix ssh mux socket file error. ssh ControlPath socket file needs to be unique for each host. To avoid using ssh ControlPath option placeholders move socket file to host's temp directory. Since each host has unique temp directory then, although file name for socket file is fixed, its path is unique. --- cdist/config.py | 93 +++++++++++++++-- cdist/exec/local.py | 40 ++------ cdist/test/code/__init__.py | 5 +- cdist/test/config/__init__.py | 15 ++- cdist/test/emulator/__init__.py | 30 ++++-- cdist/test/exec/local.py | 16 ++- cdist/test/explorer/__init__.py | 5 +- cdist/test/manifest/__init__.py | 5 +- scripts/cdist | 172 +++++++++++++------------------- 9 files changed, 221 insertions(+), 160 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 5ebeab14..da560e91 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -27,6 +27,7 @@ import sys import time import pprint import itertools +import tempfile import cdist @@ -36,6 +37,36 @@ import cdist.exec.remote from cdist import core +def inspect_ssh_mux_opts(): + """Inspect whether or not ssh supports multiplexing options. + + Return string containing multiplexing options if supported. + If ControlPath is supported then placeholder for that path is + specified and can be used for final string formatting. + For example, this function can return string: + "-o ControlMaster=auto -o ControlPersist=125 -o ControlPath={}". + Then it can be formatted: + mux_opts_string.format('/tmp/tmpxxxxxx/ssh-control-path'). + """ + import subprocess + + wanted_mux_opts = { + "ControlPath": "{}", + "ControlMaster": "auto", + "ControlPersist": "125", + } + mux_opts = " ".join([" -o {}={}".format( + x, wanted_mux_opts[x]) for x in wanted_mux_opts]) + try: + subprocess.check_output("ssh {}".format(mux_opts), + stderr=subprocess.STDOUT, shell=True) + except subprocess.CalledProcessError as e: + subproc_output = e.output.decode().lower() + if "bad configuration option" in subproc_output: + return "" + return mux_opts + + class Config(object): """Cdist main class to hold arbitrary data""" @@ -94,7 +125,6 @@ class Config(object): initial_manifest_tempfile = None if args.manifest == '-': # read initial manifest from stdin - import tempfile try: handle, initial_manifest_temp_path = tempfile.mkstemp( prefix='cdist.stdin.') @@ -112,18 +142,47 @@ class Config(object): failed_hosts = [] time_start = time.time() + # default remote cmd patterns + args.remote_exec_pattern = None + args.remote_copy_pattern = None + + args_dict = vars(args) + # if remote-exec and/or remote-copy args are None then user + # didn't specify command line options nor env vars: + # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC + if (args_dict['remote_copy'] is None or + args_dict['remote_exec'] is None): + mux_opts = inspect_ssh_mux_opts() + if args_dict['remote_exec'] is None: + args.remote_exec_pattern = cdist.REMOTE_EXEC + mux_opts + if args_dict['remote_copy'] is None: + args.remote_copy_pattern = cdist.REMOTE_COPY + mux_opts + + if args.out_path: + base_root_path = args.out_path + else: + base_root_path = tempfile.mkdtemp() + hostcnt = 0 for host in itertools.chain(cls.hosts(args.host), cls.hosts(args.hostfile)): + hostdir = cdist.str_hash(host) + host_base_path = os.path.join(base_root_path, hostdir) + + log.debug("Base root path for target host \"{}\" is \"{}\"".format( + host, host_base_path)) + hostcnt += 1 if args.parallel: log.debug("Creating child process for %s", host) process[host] = multiprocessing.Process( - target=cls.onehost, args=(host, args, True)) + target=cls.onehost, + args=(host, host_base_path, hostdir, args, True)) process[host].start() else: try: - cls.onehost(host, args, parallel=False) + cls.onehost(host, host_base_path, hostdir, + args, parallel=False) except cdist.Error as e: failed_hosts.append(host) @@ -145,22 +204,42 @@ class Config(object): " ".join(failed_hosts)) @classmethod - def onehost(cls, host, args, parallel): + def onehost(cls, host, host_base_path, host_dir_name, args, parallel): """Configure ONE system""" log = logging.getLogger(host) try: + control_path = os.path.join(host_base_path, "ssh-control-path") + # If we constructed patterns for remote commands then there is + # placeholder for ssh ControlPath, format it and we have unique + # ControlPath for each host. + # + # If not then use args.remote_exec/copy that user specified. + if args.remote_exec_pattern: + remote_exec = args.remote_exec_pattern.format(control_path) + else: + remote_exec = args.remote_exec + if args.remote_copy_pattern: + remote_copy = args.remote_copy_pattern.format(control_path) + else: + remote_copy = args.remote_copy + log.debug("remote_exec for host \"{}\": {}".format( + host, remote_exec)) + log.debug("remote_copy for host \"{}\": {}".format( + host, remote_copy)) + local = cdist.exec.local.Local( target_host=host, + base_root_path=host_base_path, + host_dir_name=host_dir_name, initial_manifest=args.manifest, - base_path=args.out_path, add_conf_dirs=args.conf_dir) remote = cdist.exec.remote.Remote( target_host=host, - remote_exec=args.remote_exec, - remote_copy=args.remote_copy) + remote_exec=remote_exec, + remote_copy=remote_copy) c = cls(local, remote, dry_run=args.dry_run) c.run() diff --git a/cdist/exec/local.py b/cdist/exec/local.py index d115bf24..4fdb5170 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -29,7 +29,6 @@ import subprocess import shutil import logging import tempfile -import hashlib import cdist import cdist.message @@ -48,40 +47,25 @@ class Local(object): """ def __init__(self, target_host, + base_root_path, + host_dir_name, exec_path=sys.argv[0], initial_manifest=None, - base_path=None, add_conf_dirs=None): self.target_host = target_host - self._init_log() - - # FIXME: stopped: create base that does not require moving later - if base_path: - base_path_parent = base_path - else: - base_path_parent = tempfile.mkdtemp() - # TODO: the below atexit hook nukes any debug info we would have - # if cdist exits with error. - # import atexit - # atexit.register(lambda: shutil.rmtree(base_path_parent)) - self.hostdir = self._hostdir() - self.log.info("Calculated temp dir for target \"{}\" is " - "\"{}\"".format(self.target_host, self.hostdir)) - self.base_path = os.path.join(base_path_parent, self.hostdir) - - self._init_permissions() - - self.mkdir(self.base_path) - - # FIXME: as well - self._init_cache_dir(None) + self.hostdir = host_dir_name + self.base_path = os.path.join(base_root_path, "data") self.exec_path = exec_path self.custom_initial_manifest = initial_manifest - self._add_conf_dirs = add_conf_dirs + self._init_log() + self._init_permissions() + self.mkdir(self.base_path) + # FIXME: create dir that does not require moving later + self._init_cache_dir(None) self._init_paths() self._init_object_marker() self._init_conf_dirs() @@ -98,12 +82,6 @@ class Local(object): else: return None - def _hostdir(self): - # Do not assume target_host is anything that can be used as a - # directory name. - # Instead use a hash, which is known to work as directory name. - return hashlib.md5(self.target_host.encode('utf-8')).hexdigest() - def _init_log(self): self.log = logging.getLogger(self.target_host) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 7ec9e3c4..7f61c13f 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -41,10 +41,13 @@ class CodeTestCase(test.CdistTestCase): def setUp(self): self.local_dir = self.mkdtemp() + self.hostdir = cdist.str_hash(self.target_host) + self.host_base_path = os.path.join(self.local_dir, self.hostdir) self.local = local.Local( target_host=self.target_host, - base_path=self.local_dir, + base_root_path=self.host_base_path, + host_dir_name=self.hostdir, exec_path=cdist.test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index 3fd415fd..cfcc3c70 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -55,10 +55,13 @@ class ConfigRunTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() self.local_dir = os.path.join(self.temp_dir, "local") - os.mkdir(self.local_dir) + self.hostdir = cdist.str_hash(self.target_host) + self.host_base_path = os.path.join(self.local_dir, self.hostdir) + os.makedirs(self.host_base_path) self.local = cdist.exec.local.Local( target_host=self.target_host, - base_path=self.local_dir) + base_root_path=self.host_base_path, + host_dir_name=self.hostdir) # Setup test objects self.object_base_path = op.join(self.temp_dir, 'object') @@ -161,7 +164,8 @@ class ConfigRunTestCase(test.CdistTestCase): """Test if the dryrun option is working like expected""" drylocal = cdist.exec.local.Local( target_host=self.target_host, - base_path=self.local_dir, + base_root_path=self.host_base_path, + host_dir_name=self.hostdir, # exec_path can not derivated from sys.argv in case of unittest exec_path=os.path.abspath(os.path.join( my_dir, '../../../scripts/cdist')), @@ -184,3 +188,8 @@ class ConfigRunTestCase(test.CdistTestCase): # first.requirements = ['__singleton_test/foo'] # with self.assertRaises(cdist.core.?????): # self.config.iterate_until_finished() + +if __name__ == "__main__": + import unittest + + unittest.main() diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 69ca0fd9..3fe9a4e5 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -48,10 +48,13 @@ class EmulatorTestCase(test.CdistTestCase): handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) base_path = self.temp_dir + hostdir = cdist.str_hash(self.target_host) + host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( target_host=self.target_host, - base_path=base_path, + base_root_path=host_base_path, + host_dir_name=hostdir, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -148,10 +151,13 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) base_path = self.temp_dir + hostdir = cdist.str_hash(self.target_host) + host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( target_host=self.target_host, - base_path=base_path, + base_root_path=host_base_path, + host_dir_name=hostdir, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -235,10 +241,13 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() base_path = os.path.join(self.temp_dir, "out") + hostdir = cdist.str_hash(self.target_host) + host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( target_host=self.target_host, - base_path=base_path, + base_root_path=host_base_path, + host_dir_name=hostdir, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -265,10 +274,13 @@ class OverrideTestCase(test.CdistTestCase): handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) base_path = self.temp_dir + hostdir = cdist.str_hash(self.target_host) + host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( target_host=self.target_host, - base_path=base_path, + base_root_path=host_base_path, + host_dir_name=hostdir, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -303,12 +315,15 @@ class ArgumentsTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() base_path = self.temp_dir + hostdir = cdist.str_hash(self.target_host) + host_base_path = os.path.join(base_path, hostdir) handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) self.local = local.Local( target_host=self.target_host, - base_path=base_path, + base_root_path=host_base_path, + host_dir_name=hostdir, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -425,10 +440,13 @@ class StdinTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() base_path = os.path.join(self.temp_dir, "out") + hostdir = cdist.str_hash(self.target_host) + host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( target_host=self.target_host, - base_path=base_path, + base_root_path=host_base_path, + host_dir_name=hostdir, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index 2cd8b6db..f83fd6b7 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -47,11 +47,14 @@ class LocalTestCase(test.CdistTestCase): target_host = 'localhost' self.temp_dir = self.mkdtemp() self.out_parent_path = self.temp_dir - self.out_path = op.join(self.out_parent_path, target_host) + self.hostdir = cdist.str_hash(target_host) + self.host_base_path = op.join(self.out_parent_path, self.hostdir) + self.out_path = op.join(self.host_base_path, "data") self.local = local.Local( target_host=target_host, - base_path=self.out_parent_path, + base_root_path=self.host_base_path, + host_dir_name=self.hostdir, exec_path=test.cdist_exec_path ) @@ -109,7 +112,8 @@ class LocalTestCase(test.CdistTestCase): link_test_local = local.Local( target_host='localhost', - base_path=self.out_parent_path, + base_root_path=self.host_base_path, + host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, ) @@ -127,7 +131,8 @@ class LocalTestCase(test.CdistTestCase): link_test_local = local.Local( target_host='localhost', - base_path=self.out_parent_path, + base_root_path=self.host_base_path, + host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir] ) @@ -148,7 +153,8 @@ class LocalTestCase(test.CdistTestCase): link_test_local = local.Local( target_host='localhost', - base_path=self.out_parent_path, + base_root_path=self.host_base_path, + host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, ) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 2ca50b7c..9a4555b8 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -42,12 +42,15 @@ class ExplorerClassTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() self.local_path = os.path.join(self.temp_dir, "local") + hostdir = cdist.str_hash(self.target_host) + base_root_path = os.path.join(self.local_path, hostdir) self.remote_base_path = os.path.join(self.temp_dir, "remote") os.makedirs(self.remote_base_path) self.local = local.Local( target_host=self.target_host, - base_path=self.local_path, + base_root_path=base_root_path, + host_dir_name=hostdir, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir], ) diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index 84c69ce1..cfaefe5c 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -49,9 +49,12 @@ class ManifestTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() out_path = self.temp_dir + hostdir = cdist.str_hash(self.target_host) + base_root_path = os.path.join(out_path, hostdir) self.local = local.Local( target_host=self.target_host, - base_path=out_path, + base_root_path=base_root_path, + host_dir_name=hostdir, exec_path=cdist.test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() diff --git a/scripts/cdist b/scripts/cdist index 55113be0..953cad78 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -21,31 +21,6 @@ # # -def inspect_ssh_mux_opts(control_path_dir="~/.ssh/"): - """Inspect whether or not ssh supports multiplexing options""" - import subprocess - import os - - # socket is always local to each cdist run, it is created in - # temp directory that is created at starting cdist, so - # control_path file name can be static, it will always be - # unique due to unique temp directory name - control_path = os.path.join(control_path_dir, "ssh-control-path") - wanted_mux_opts = { - "ControlPath": control_path, - "ControlMaster": "auto", - "ControlPersist": "125", - } - mux_opts = " ".join([" -o {}={}".format(x, - wanted_mux_opts[x]) for x in wanted_mux_opts]) - try: - subprocess.check_output("ssh {}".format(mux_opts), - stderr=subprocess.STDOUT, shell=True) - except subprocess.CalledProcessError as e: - subproc_output = e.output.decode().lower() - if "bad configuration option" in subproc_output: - return "" - return mux_opts def commandline(): """Parse command line""" @@ -54,7 +29,6 @@ def commandline(): import cdist.banner import cdist.config import cdist.shell - import tempfile import shutil import os @@ -62,79 +36,88 @@ def commandline(): parser = {} # Options _all_ parsers have in common parser['loglevel'] = argparse.ArgumentParser(add_help=False) - parser['loglevel'].add_argument('-d', '--debug', - help='Set log level to debug', action='store_true', - default=False) - parser['loglevel'].add_argument('-v', '--verbose', - help='Set log level to info, be more verbose', - action='store_true', default=False) + parser['loglevel'].add_argument( + '-d', '--debug', help='Set log level to debug', + action='store_true', default=False) + parser['loglevel'].add_argument( + '-v', '--verbose', help='Set log level to info, be more verbose', + action='store_true', default=False) # Main subcommand parser - parser['main'] = argparse.ArgumentParser(description='cdist ' - + cdist.VERSION, - parents=[parser['loglevel']]) - parser['main'].add_argument('-V', '--version', - help='Show version', action='version', - version='%(prog)s ' + cdist.VERSION) - parser['sub'] = parser['main'].add_subparsers(title="Commands", - dest="command") + parser['main'] = argparse.ArgumentParser( + description='cdist ' + cdist.VERSION, parents=[parser['loglevel']]) + parser['main'].add_argument( + '-V', '--version', help='Show version', action='version', + version='%(prog)s ' + cdist.VERSION) + parser['sub'] = parser['main'].add_subparsers( + title="Commands", dest="command") # Banner - parser['banner'] = parser['sub'].add_parser('banner', - parents=[parser['loglevel']]) + parser['banner'] = parser['sub'].add_parser( + 'banner', parents=[parser['loglevel']]) parser['banner'].set_defaults(func=cdist.banner.banner) # Config - parser['config'] = parser['sub'].add_parser('config', - parents=[parser['loglevel']]) - parser['config'].add_argument('host', nargs='*', - help='host(s) to operate on') - parser['config'].add_argument('-c', '--conf-dir', - help=('Add configuration directory (can be repeated, ' - 'last one wins)'), action='append') - parser['config'].add_argument('-f', '--file', - help=('Read additional hosts to operate on from specified file ' - 'or from stdin if \'-\' (each host on separate line). ' - 'If no host or host file is specified then, by default, ' - 'read hosts from stdin.'), - dest='hostfile', required=False) - parser['config'].add_argument('-i', '--initial-manifest', - help='Path to a cdist manifest or \'-\' to read from stdin.', - dest='manifest', required=False) - parser['config'].add_argument('-n', '--dry-run', - help='Do not execute code', action='store_true') - parser['config'].add_argument('-o', '--out-dir', - help='Directory to save cdist output in', dest="out_path") - parser['config'].add_argument('-p', '--parallel', - help='Operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser['config'].add_argument('-s', '--sequential', - help='Operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') + parser['config'] = parser['sub'].add_parser( + 'config', parents=[parser['loglevel']]) + parser['config'].add_argument( + 'host', nargs='*', help='host(s) to operate on') + parser['config'].add_argument( + '-c', '--conf-dir', + help=('Add configuration directory (can be repeated, ' + 'last one wins)'), action='append') + parser['config'].add_argument( + '-f', '--file', + help=('Read additional hosts to operate on from specified file ' + 'or from stdin if \'-\' (each host on separate line). ' + 'If no host or host file is specified then, by default, ' + 'read hosts from stdin.'), + dest='hostfile', required=False) + parser['config'].add_argument( + '-i', '--initial-manifest', + help='Path to a cdist manifest or \'-\' to read from stdin.', + dest='manifest', required=False) + parser['config'].add_argument( + '-n', '--dry-run', + help='Do not execute code', action='store_true') + parser['config'].add_argument( + '-o', '--out-dir', + help='Directory to save cdist output in', dest="out_path") + parser['config'].add_argument( + '-p', '--parallel', + help='Operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser['config'].add_argument( + '-s', '--sequential', + help='Operate on multiple hosts sequentially (default)', + action='store_false', dest='parallel') # remote-copy and remote-exec defaults are environment variables # if set; if not then None - these will be futher handled after # parsing to determine implementation default - parser['config'].add_argument('--remote-copy', - help='Command to use for remote copy (should behave like scp)', - action='store', dest='remote_copy', - default=os.environ.get('CDIST_REMOTE_COPY')) - parser['config'].add_argument('--remote-exec', - help=('Command to use for remote execution ' - '(should behave like ssh)'), - action='store', dest='remote_exec', - default=os.environ.get('CDIST_REMOTE_EXEC')) + parser['config'].add_argument( + '--remote-copy', + help='Command to use for remote copy (should behave like scp)', + action='store', dest='remote_copy', + default=os.environ.get('CDIST_REMOTE_COPY')) + parser['config'].add_argument( + '--remote-exec', + help=('Command to use for remote execution ' + '(should behave like ssh)'), + action='store', dest='remote_exec', + default=os.environ.get('CDIST_REMOTE_EXEC')) parser['config'].set_defaults(func=cdist.config.Config.commandline) # Shell - parser['shell'] = parser['sub'].add_parser('shell', - parents=[parser['loglevel']]) - parser['shell'].add_argument('-s', '--shell', - help='Select shell to use, defaults to current shell') + parser['shell'] = parser['sub'].add_parser( + 'shell', parents=[parser['loglevel']]) + parser['shell'].add_argument( + '-s', '--shell', + help='Select shell to use, defaults to current shell') parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) - for p in parser: - parser[p].epilog = "Get cdist at http://www.nico.schottelius.org/software/cdist/" + parser[p].epilog = ( + "Get cdist at http://www.nico.schottelius.org/software/cdist/") args = parser['main'].parse_args(sys.argv[1:]) @@ -143,26 +126,6 @@ def commandline(): logging.root.setLevel(logging.INFO) if args.debug: logging.root.setLevel(logging.DEBUG) - args_dict = vars(args) - # if command with remote_copy and remote_exec params - if 'remote_copy' in args_dict and 'remote_exec' in args_dict: - # if remote-exec and/or remote-copy args are None then user - # didn't specify command line options nor env vars: - # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC - if args_dict['remote_copy'] is None or args_dict['remote_exec'] is None: - control_path_dir = tempfile.mkdtemp(prefix="cdist") - import atexit - atexit.register(lambda: shutil.rmtree(control_path_dir)) - mux_opts = inspect_ssh_mux_opts(control_path_dir) - if args_dict['remote_exec'] is None: - args.remote_exec = cdist.REMOTE_EXEC + mux_opts - if args_dict['remote_copy'] is None: - args.remote_copy = cdist.REMOTE_COPY + mux_opts - - if args.command == 'config': - if args.manifest == '-' and args.hostfile == '-': - print('cdist config: error: cannot read both, manifest and host file, from stdin') - sys.exit(1) log.debug(args) log.info("version %s" % cdist.VERSION) @@ -191,10 +154,9 @@ if __name__ == "__main__": cdistpythonversion = '3.2' if sys.version < cdistpythonversion: print('Python >= ' + cdistpythonversion + - ' is required on the source host.', file=sys.stderr) + ' is required on the source host.', file=sys.stderr) sys.exit(1) - exit_code = 0 try: From 135b4fbadf8f5b977fe1b50bca2130181e75a305 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 23 Jul 2016 16:17:43 +0200 Subject: [PATCH 0238/1332] Update changelog. --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index d85af785..1c894ba7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Fix ssh ControlPath socket file error (Darko Poljak) + 4.2.1: 2016-07-18 * Build: Fix signed release (Darko Poljak) * Build: Fix building docs (Darko Poljak) From 099893d11beb151c9614f21e19f71bd721a3f1aa Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 23 Jul 2016 16:19:34 +0200 Subject: [PATCH 0239/1332] Update changelog. --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index d85af785..218182dc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,10 @@ Changelog --------- +next: + * New type: __keyboard: Set keyboard layout (Carlos Ortigoza) + * New type: __locale_system: Set system-wide locale (Carlos Ortigoza) + 4.2.1: 2016-07-18 * Build: Fix signed release (Darko Poljak) * Build: Fix building docs (Darko Poljak) From fdd1062b857a56e55e2f54464561888ba4058522 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 23 Jul 2016 16:20:46 +0200 Subject: [PATCH 0240/1332] Update changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index d85af785..db1cd080 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * New type: __hosts: manage entries in /etc/hosts (Dmitry Bogatov) + 4.2.1: 2016-07-18 * Build: Fix signed release (Darko Poljak) * Build: Fix building docs (Darko Poljak) From 6de632c0b9058b0cda302666813a9c2fefa83599 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 23 Jul 2016 16:25:13 +0200 Subject: [PATCH 0241/1332] Update changelog --- docs/changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog b/docs/changelog index d85af785..5ef5cb6f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,11 @@ Changelog --------- +next: + * Documentation: Update cdist man page and cdist-references (Darko Poljak) + * Documentation: Change cdist and cdist-type__pyvenv man page licenses to GPLv3+ (Darko Poljak) + * Documentation: Add FILES to cdist man page (Darko Poljak) + 4.2.1: 2016-07-18 * Build: Fix signed release (Darko Poljak) * Build: Fix building docs (Darko Poljak) From 1959e9cdd82db479ec411743c279a97628812d38 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 23 Jul 2016 16:29:51 +0200 Subject: [PATCH 0242/1332] Fix error message. --- cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index f58bc15b..74db1a13 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -90,4 +90,4 @@ def str_hash(s): if isinstance(s, str): return hashlib.md5(s.encode('utf-8')).hexdigest() else: - raise Error("str_hash param should be string") + raise Error("Param should be string") From f5dd4e0a766db40a4c02c398ccf877f90e80fe55 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 24 Jul 2016 22:24:15 +0200 Subject: [PATCH 0243/1332] Improve pep8 targets and checking in release. --- bin/build-helper | 6 +++++- bin/build-helper.freebsd | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 2a6e61da..46b139d1 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -249,7 +249,7 @@ eof # First check everything is sane "$0" check-date "$0" check-unittest - "$0" pep8 + "$0" check-pep8 # Generate version file to be included in packaging "$0" target-version @@ -361,6 +361,10 @@ eof pep8) pep8 "${basedir}" "${basedir}/scripts/cdist" | less + ;; + + check-pep8) + "$0" pep8 echo "Please review pep8 report." while true do diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 4e4c4c9d..183129db 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -284,7 +284,7 @@ eof # First check everything is sane "$0" check-date "$0" check-unittest - "$0" pep8 + "$0" check-pep8 # Generate version file to be included in packaging "$0" target-version @@ -423,6 +423,10 @@ eof pep8) pep8 "${basedir}" "${basedir}/scripts/cdist" | less + ;; + + check-pep8) + "$0" pep8 echo "Please review pep8 report." while true do From d2997baf0b86d36a61a6d36c86ab9c7ffaba3804 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 26 Jul 2016 07:50:27 +0200 Subject: [PATCH 0244/1332] Update changelog: v 4.2.2 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 5aee7888..f73ba776 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.2.2: 2016-07-26 * Core: Fix ssh ControlPath socket file error (Darko Poljak) * Documentation: Update cdist man page and cdist-references (Darko Poljak) * Documentation: Change cdist and cdist-type__pyvenv man page licenses to GPLv3+ (Darko Poljak) From 2ed762cd72d426ff0d25cf21ac7ddb48312297e8 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 28 Jul 2016 14:48:32 +0200 Subject: [PATCH 0245/1332] new type __filesystem, first version --- .../type/__filesystem/explorer/blkdev_devname | 38 ++++++++ .../type/__filesystem/explorer/blkdev_fstype | 38 ++++++++ .../type/__filesystem/explorer/blkdev_label | 38 ++++++++ .../__filesystem/explorer/blkdev_mountpoint | 38 ++++++++ cdist/conf/type/__filesystem/gencode-remote | 96 +++++++++++++++++++ cdist/conf/type/__filesystem/man.rst | 79 +++++++++++++++ .../conf/type/__filesystem/parameter/boolean | 1 + .../type/__filesystem/parameter/default/label | 0 .../parameter/default/mkfsoptions | 0 .../conf/type/__filesystem/parameter/optional | 2 + .../conf/type/__filesystem/parameter/required | 2 + docs/changelog | 2 + 12 files changed, 334 insertions(+) create mode 100644 cdist/conf/type/__filesystem/explorer/blkdev_devname create mode 100644 cdist/conf/type/__filesystem/explorer/blkdev_fstype create mode 100644 cdist/conf/type/__filesystem/explorer/blkdev_label create mode 100644 cdist/conf/type/__filesystem/explorer/blkdev_mountpoint create mode 100644 cdist/conf/type/__filesystem/gencode-remote create mode 100644 cdist/conf/type/__filesystem/man.rst create mode 100644 cdist/conf/type/__filesystem/parameter/boolean create mode 100644 cdist/conf/type/__filesystem/parameter/default/label create mode 100644 cdist/conf/type/__filesystem/parameter/default/mkfsoptions create mode 100644 cdist/conf/type/__filesystem/parameter/optional create mode 100644 cdist/conf/type/__filesystem/parameter/required diff --git a/cdist/conf/type/__filesystem/explorer/blkdev_devname b/cdist/conf/type/__filesystem/explorer/blkdev_devname new file mode 100644 index 00000000..30c8409a --- /dev/null +++ b/cdist/conf/type/__filesystem/explorer/blkdev_devname @@ -0,0 +1,38 @@ +#!/bin/sh +# +# 2016 - 2016 Daniel Heule (hda at sfs.biz) +# +# 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 . +# + +os=$("$__explorer/os") + +blkdev="$(cat "$__object/parameter/blkdev")" + +case "$os" in + centos|fedora|redhat|suse|gentoo) + if [ ! -x "$(command -v lsblk)" ]; then + echo "lsblk is required for __filesystem type" >&2 + exit 1 + else + echo -n $(lsblk -n -o NAME "$blkdev" 2>/dev/null) + fi + ;; + *) + echo "__filesystem type lacks implementation for os: $os" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__filesystem/explorer/blkdev_fstype b/cdist/conf/type/__filesystem/explorer/blkdev_fstype new file mode 100644 index 00000000..3f92142f --- /dev/null +++ b/cdist/conf/type/__filesystem/explorer/blkdev_fstype @@ -0,0 +1,38 @@ +#!/bin/sh +# +# 2016 - 2016 Daniel Heule (hda at sfs.biz) +# +# 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 . +# + +os=$("$__explorer/os") + +blkdev="$(cat "$__object/parameter/blkdev")" + +case "$os" in + centos|fedora|redhat|suse|gentoo) + if [ ! -x "$(command -v lsblk)" ]; then + echo "lsblk is required for __filesystem type" >&2 + exit 1 + else + echo -n $(lsblk -n -o FSTYPE "$blkdev" 2>/dev/null) + fi + ;; + *) + echo "__filesystem type lacks implementation for os: $os" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__filesystem/explorer/blkdev_label b/cdist/conf/type/__filesystem/explorer/blkdev_label new file mode 100644 index 00000000..aa227cab --- /dev/null +++ b/cdist/conf/type/__filesystem/explorer/blkdev_label @@ -0,0 +1,38 @@ +#!/bin/sh +# +# 2016 - 2016 Daniel Heule (hda at sfs.biz) +# +# 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 . +# + +os=$("$__explorer/os") + +blkdev="$(cat "$__object/parameter/blkdev")" + +case "$os" in + centos|fedora|redhat|suse|gentoo) + if [ ! -x "$(command -v lsblk)" ]; then + echo "lsblk is required for __filesystem type" >&2 + exit 1 + else + echo -n $(lsblk -n -o LABEL "$blkdev" 2>/dev/null) + fi + ;; + *) + echo "__filesystem type lacks implementation for os: $os" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__filesystem/explorer/blkdev_mountpoint b/cdist/conf/type/__filesystem/explorer/blkdev_mountpoint new file mode 100644 index 00000000..1cef068c --- /dev/null +++ b/cdist/conf/type/__filesystem/explorer/blkdev_mountpoint @@ -0,0 +1,38 @@ +#!/bin/sh +# +# 2016 - 2016 Daniel Heule (hda at sfs.biz) +# +# 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 . +# + +os=$("$__explorer/os") + +blkdev="$(cat "$__object/parameter/blkdev")" + +case "$os" in + centos|fedora|redhat|suse|gentoo) + if [ ! -x "$(command -v lsblk)" ]; then + echo "lsblk is required for __filesystem type" >&2 + exit 1 + else + echo -n $(lsblk -n -o MOUNTPOINT "$blkdev" 2>/dev/null) + fi + ;; + *) + echo "__filesystem type lacks implementation for os: $os" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__filesystem/gencode-remote b/cdist/conf/type/__filesystem/gencode-remote new file mode 100644 index 00000000..9d134dcc --- /dev/null +++ b/cdist/conf/type/__filesystem/gencode-remote @@ -0,0 +1,96 @@ +#!/bin/sh +# +# 2016 - 2016 Daniel Heule (hda at sfs.biz) +# +# 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 . +# + + +fstype="$(cat "$__object/parameter/fstype")" +mydev="$(cat "$__object/parameter/blkdev")" + +label="$(cat "$__object/parameter/label")" +mkfsoptions="$(cat "$__object/parameter/mkfsoptions")" + + +if [ -f "$__object/parameter/force" ]; then + # create filesystem even an other filesystem is on disk or the label is not correct, use with caution ! + forcefs="true" +else + forcefs="false" +fi + + +blkdev_devname="$(cat "$__object/explorer/blkdev_devname")" +blkdev_fstype="$(cat "$__object/explorer/blkdev_fstype")" +blkdev_label="$(cat "$__object/explorer/blkdev_label")" +blkdev_mountpoint="$(cat "$__object/explorer/blkdev_mountpoint")" + +if [ -z "$blkdev_devname" ]; then + echo "Specified device $mydev not found on target system" >&2 + exit 1 +fi + +[ "$blkdev_label" = "$label" ] && [ "$blkdev_fstype" = "$fstype" ] && exit 0 + +if [ -n "$blkdev_mountpoint" ]; then + echo "Specified device $mydev is mounted on $blkdev_mountpoint, __filesystem does NOTHING with mountd devices" >&2 + exit 0 +fi + +if [ -n "$blkdev_fstype" ] && [ "$forcefs" != "true" ]; then + if [ "$blkdev_label" != "$label" ]; then + echo "Specified device $mydev has not the spezified label: $blkdev_label, but __filesystem does NOTHING in this case without the --force option" >&2 + exit 0 + fi + if [ "$blkdev_fstype" != "$fstype" ]; then + echo "Specified device $mydev has not the spezified filesystem: $blkdev_fstype, but __filesystem does NOTHING in this case without the --force option" >&2 + exit 0 + fi +fi + + +# ok, all conditions checked, we need to format the device, lets go +opts="$mkfsoptions" +if [ -n "$label" ]; then + opts="$opts -L '$label'" +fi + +case "$fstype" in + ext2|ext3|ext4) + if [ "$forcefs" = "true" ]; then + opts="$opts -F" + fi + echo "mkfs.$fstype $opts /dev/$blkdev_devname" + ;; + btrfs) + if [ "$forcefs" = "true" ]; then + opts="$opts --force" + fi + echo "mkfs.btrfs $opts /dev/$blkdev_devname" + ;; + xfs) + if [ "$forcefs" = "true" ]; then + opts="$opts -f" + fi + echo "mkfs.xfs $opts /dev/$blkdev_devname" + ;; + *) + echo "__filesystem type lacks implementation for filesystem: $fstype" >&2 + exit 1 + ;; +esac +echo "filesystem $fstype on $mydev : /dev/$blkdev_devname created" >> "$__messages_out" diff --git a/cdist/conf/type/__filesystem/man.rst b/cdist/conf/type/__filesystem/man.rst new file mode 100644 index 00000000..c4787d53 --- /dev/null +++ b/cdist/conf/type/__filesystem/man.rst @@ -0,0 +1,79 @@ +cdist-type__filesystem(7) +========================= + +NAME +---- +cdist-type__filesystem - Create Filesystems. + + +DESCRIPTION +----------- +This cdist type allows you to create filesystems on devices. + +If the device is mounted on target, it refuses to do someting. + +If the device has a filesystem other as the specified and/or + the label is not correct, it only make a new filesystem + if you specified --force option + + +REQUIRED PARAMETERS +------------------- +fstype + Filesystem type, for example 'ext3', 'btrfs' or 'xfs' + +blkdev + Blockdevice for filesystem, + On linux, it can be any by lsblk accepted device notation + + for example + /dev/sdx + or /dev/disk/by-xxxx/xxx + or /dev/mapper/xxxx + + +OPTIONAL PARAMETERS +------------------- +label + Label which sould apply on the filesystem + +mkfsoptions + Additional options which are inserted to the mkfs.xxx call. + + +BOOLEAN PARAMETERS +------------------ +force + Normaly, this type does nothing if a filesystem is found + on the target device. If you specify force, its formated + if the filesystem type or label differs from parameters + Warning: This option can easy lead into data loss ! + +MESSAGES +-------- +filesystem on : created + Filesytem was created on + + +EXAMPLES +-------- + +.. code-block:: sh + + # Ensures that device /dev/sdb is formated with xfs + __filesystem dev_sdb --fstype xfs --blkdev /dev/sdb --label Testdisk1 + # The same thing with btrfs and disk spezified by pci path to disk 1:0 on vmware + __filesystem dev_sdb --fstype btrfs --blkdev /dev/disk/by-path/pci-0000:0b:00.0-scsi-0:0:0:0 --label Testdisk2 + # Make sure that a multipath san device has a filesystem ... + __filesystem dev_sdb --fstype xfs --blkdev /dev/mapper/360060e80432f560050202f22000023ff --label Testdisk3 + + +AUTHORS +------- +Daniel Heule + + +COPYING +------- +Copyright \(C) 2016 Daniel Heule. Free use of this software is +granted under the terms of the GNU General Public License version 3 or any later version (GPLv3+). diff --git a/cdist/conf/type/__filesystem/parameter/boolean b/cdist/conf/type/__filesystem/parameter/boolean new file mode 100644 index 00000000..14b33226 --- /dev/null +++ b/cdist/conf/type/__filesystem/parameter/boolean @@ -0,0 +1 @@ +force diff --git a/cdist/conf/type/__filesystem/parameter/default/label b/cdist/conf/type/__filesystem/parameter/default/label new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__filesystem/parameter/default/mkfsoptions b/cdist/conf/type/__filesystem/parameter/default/mkfsoptions new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__filesystem/parameter/optional b/cdist/conf/type/__filesystem/parameter/optional new file mode 100644 index 00000000..0f63435f --- /dev/null +++ b/cdist/conf/type/__filesystem/parameter/optional @@ -0,0 +1,2 @@ +label +mkfsoptions diff --git a/cdist/conf/type/__filesystem/parameter/required b/cdist/conf/type/__filesystem/parameter/required new file mode 100644 index 00000000..33a66684 --- /dev/null +++ b/cdist/conf/type/__filesystem/parameter/required @@ -0,0 +1,2 @@ +fstype +blkdev diff --git a/docs/changelog b/docs/changelog index f73ba776..ba8ee201 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,5 +1,7 @@ Changelog --------- +next: + * New type __filesystem: manage filesystems on devices ( Daniel Heule ) 4.2.2: 2016-07-26 * Core: Fix ssh ControlPath socket file error (Darko Poljak) From 36c20230b89e78780ae3ff6ca9dae52e3799f212 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 29 Jul 2016 15:27:13 +0200 Subject: [PATCH 0246/1332] optimize the usage of explorers for __filesystem --- .../type/__filesystem/explorer/blkdev_fstype | 38 ------------------- .../type/__filesystem/explorer/blkdev_label | 38 ------------------- .../__filesystem/explorer/blkdev_mountpoint | 38 ------------------- .../explorer/{blkdev_devname => lsblk} | 3 +- cdist/conf/type/__filesystem/gencode-remote | 9 +++-- 5 files changed, 7 insertions(+), 119 deletions(-) delete mode 100644 cdist/conf/type/__filesystem/explorer/blkdev_fstype delete mode 100644 cdist/conf/type/__filesystem/explorer/blkdev_label delete mode 100644 cdist/conf/type/__filesystem/explorer/blkdev_mountpoint rename cdist/conf/type/__filesystem/explorer/{blkdev_devname => lsblk} (86%) diff --git a/cdist/conf/type/__filesystem/explorer/blkdev_fstype b/cdist/conf/type/__filesystem/explorer/blkdev_fstype deleted file mode 100644 index 3f92142f..00000000 --- a/cdist/conf/type/__filesystem/explorer/blkdev_fstype +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# 2016 - 2016 Daniel Heule (hda at sfs.biz) -# -# 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 . -# - -os=$("$__explorer/os") - -blkdev="$(cat "$__object/parameter/blkdev")" - -case "$os" in - centos|fedora|redhat|suse|gentoo) - if [ ! -x "$(command -v lsblk)" ]; then - echo "lsblk is required for __filesystem type" >&2 - exit 1 - else - echo -n $(lsblk -n -o FSTYPE "$blkdev" 2>/dev/null) - fi - ;; - *) - echo "__filesystem type lacks implementation for os: $os" >&2 - exit 1 - ;; -esac diff --git a/cdist/conf/type/__filesystem/explorer/blkdev_label b/cdist/conf/type/__filesystem/explorer/blkdev_label deleted file mode 100644 index aa227cab..00000000 --- a/cdist/conf/type/__filesystem/explorer/blkdev_label +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# 2016 - 2016 Daniel Heule (hda at sfs.biz) -# -# 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 . -# - -os=$("$__explorer/os") - -blkdev="$(cat "$__object/parameter/blkdev")" - -case "$os" in - centos|fedora|redhat|suse|gentoo) - if [ ! -x "$(command -v lsblk)" ]; then - echo "lsblk is required for __filesystem type" >&2 - exit 1 - else - echo -n $(lsblk -n -o LABEL "$blkdev" 2>/dev/null) - fi - ;; - *) - echo "__filesystem type lacks implementation for os: $os" >&2 - exit 1 - ;; -esac diff --git a/cdist/conf/type/__filesystem/explorer/blkdev_mountpoint b/cdist/conf/type/__filesystem/explorer/blkdev_mountpoint deleted file mode 100644 index 1cef068c..00000000 --- a/cdist/conf/type/__filesystem/explorer/blkdev_mountpoint +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# 2016 - 2016 Daniel Heule (hda at sfs.biz) -# -# 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 . -# - -os=$("$__explorer/os") - -blkdev="$(cat "$__object/parameter/blkdev")" - -case "$os" in - centos|fedora|redhat|suse|gentoo) - if [ ! -x "$(command -v lsblk)" ]; then - echo "lsblk is required for __filesystem type" >&2 - exit 1 - else - echo -n $(lsblk -n -o MOUNTPOINT "$blkdev" 2>/dev/null) - fi - ;; - *) - echo "__filesystem type lacks implementation for os: $os" >&2 - exit 1 - ;; -esac diff --git a/cdist/conf/type/__filesystem/explorer/blkdev_devname b/cdist/conf/type/__filesystem/explorer/lsblk similarity index 86% rename from cdist/conf/type/__filesystem/explorer/blkdev_devname rename to cdist/conf/type/__filesystem/explorer/lsblk index 30c8409a..87f95e90 100644 --- a/cdist/conf/type/__filesystem/explorer/blkdev_devname +++ b/cdist/conf/type/__filesystem/explorer/lsblk @@ -28,7 +28,8 @@ case "$os" in echo "lsblk is required for __filesystem type" >&2 exit 1 else - echo -n $(lsblk -n -o NAME "$blkdev" 2>/dev/null) + #echo -n $(lsblk -nd -P -o NAME,FSTYPE,LABEL,MOUNTPOINT "$blkdev" 2>/dev/null) + lsblk -nd -P -o NAME,FSTYPE,LABEL,MOUNTPOINT "$blkdev" 2>/dev/null fi ;; *) diff --git a/cdist/conf/type/__filesystem/gencode-remote b/cdist/conf/type/__filesystem/gencode-remote index 9d134dcc..feb7098d 100644 --- a/cdist/conf/type/__filesystem/gencode-remote +++ b/cdist/conf/type/__filesystem/gencode-remote @@ -34,10 +34,11 @@ else fi -blkdev_devname="$(cat "$__object/explorer/blkdev_devname")" -blkdev_fstype="$(cat "$__object/explorer/blkdev_fstype")" -blkdev_label="$(cat "$__object/explorer/blkdev_label")" -blkdev_mountpoint="$(cat "$__object/explorer/blkdev_mountpoint")" + +blkdev_devname="$(grep -P -o2 'NAME="\K[^"]*' "$__object/explorer/lsblk")" +blkdev_fstype="$(grep -P -o2 'FSTYPE="\K[^"]*' "$__object/explorer/lsblk")" +blkdev_label="$(grep -P -o2 'LABEL="\K[^"]*' "$__object/explorer/lsblk")" +blkdev_mountpoint="$(grep -P -o2 'MOUNTPOINT="\K[^"]*' "$__object/explorer/lsblk")" if [ -z "$blkdev_devname" ]; then echo "Specified device $mydev not found on target system" >&2 From 06d0eabb5ff3a50c9978cf19926e6c91c0da3b21 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Aug 2016 00:58:07 +0200 Subject: [PATCH 0247/1332] Add new type: __locale_system Merge the best of the proposals from Steven and Carlos --- cdist/conf/type/__locale_system/man.rst | 66 +++++++++++++++++++ cdist/conf/type/__locale_system/manifest | 55 ++++++++++++++++ .../__locale_system/parameter/default/state | 1 + .../__locale_system/parameter/default/value | 1 + .../type/__locale_system/parameter/optional | 2 + 5 files changed, 125 insertions(+) create mode 100644 cdist/conf/type/__locale_system/man.rst create mode 100644 cdist/conf/type/__locale_system/manifest create mode 100644 cdist/conf/type/__locale_system/parameter/default/state create mode 100644 cdist/conf/type/__locale_system/parameter/default/value create mode 100644 cdist/conf/type/__locale_system/parameter/optional diff --git a/cdist/conf/type/__locale_system/man.rst b/cdist/conf/type/__locale_system/man.rst new file mode 100644 index 00000000..fe54c01c --- /dev/null +++ b/cdist/conf/type/__locale_system/man.rst @@ -0,0 +1,66 @@ +cdist-type__locale_system(7) +============================ + +NAME +---- +cdist-type__locale_system - Set system-wide locale + + +DESCRIPTION +----------- +This cdist type allows you to modify system-wide locale. +The name of the locale category is given as the object id +(usually you are probably interested in using LANG) + + +OPTIONAL PARAMETERS +------------------- + +state + present or absent, defaults to present. + If present, sets the locale category to the given value. + If absent, removes the locale category from the system file. + +value + The value for the locale category. + Defaults to en_US.UTF-8. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Set LANG to en_US.UTF-8 + __locale_system LANG + + # Same as above, but more explicit + __locale_system LANG --value en_US.UTF-8 + + # Set category LC_MESSAGES to de_CH.UTF-8 + __locale_system LC_MESSAGES --value de_CH.UTF-8 + + # Remove setting for LC_ALL + __locale_system LC_ALL --state absent + + + +SEE ALSO +-------- +:strong:`locale`\ (1) +:strong:`localedef`\ (1) +:strong:`cdist-type__locale`\ (7) + + +AUTHORS +------- +Steven Armstrong , +Carlos Ortigoza , +Nico Schottelius + + +COPYING +------- +Copyright \(C) 2016 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 or +later (GPLv3+). diff --git a/cdist/conf/type/__locale_system/manifest b/cdist/conf/type/__locale_system/manifest new file mode 100644 index 00000000..02cf48df --- /dev/null +++ b/cdist/conf/type/__locale_system/manifest @@ -0,0 +1,55 @@ +#!/bin/sh +# +# 2012-2016 Steven Armstrong (steven-cdist at armstrong.cc) +# 2016 Carlos Ortigoza (carlos.ortigoza at ungleich.ch) +# 2016 Nico Schottelius (nico.schottelius at ungleich.ch) +# +# 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 . +# +# +# Configure system-wide locale by modifying i18n file. +# + +os=$(cat "$__global/explorer/os") + +case "$os" in + debian|ubuntu) + locale_conf="/etc/default/locale" + ;; + archlinux) + locale_conf="/etc/locale.conf" + ;; + redhat|centos) + locale_conf="/etc/sysconfig/i18n" + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac + +__file "$locale_conf" \ + --owner root --group root --mode 644 \ + --state exists + +require="__file/$locale_conf" \ + __key_value "$locale_conf:$__object_id" \ + --file "$locale_conf" \ + --key "$__object_id" \ + --delimiter = \ + --state "$(cat "$__object/parameter/state")" \ + --value "$(cat "$__object/parameter/value")" diff --git a/cdist/conf/type/__locale_system/parameter/default/state b/cdist/conf/type/__locale_system/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__locale_system/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__locale_system/parameter/default/value b/cdist/conf/type/__locale_system/parameter/default/value new file mode 100644 index 00000000..927508f3 --- /dev/null +++ b/cdist/conf/type/__locale_system/parameter/default/value @@ -0,0 +1 @@ +en_US.UTF-8 diff --git a/cdist/conf/type/__locale_system/parameter/optional b/cdist/conf/type/__locale_system/parameter/optional new file mode 100644 index 00000000..d0460d86 --- /dev/null +++ b/cdist/conf/type/__locale_system/parameter/optional @@ -0,0 +1,2 @@ +state +value From 94119003a90a44a998d471e41f0dbd9bffed6a89 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Aug 2016 01:02:47 +0200 Subject: [PATCH 0248/1332] Reference __locale_system in __locale type --- cdist/conf/type/__locale/man.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__locale/man.rst b/cdist/conf/type/__locale/man.rst index e46d14bd..60a4eacc 100644 --- a/cdist/conf/type/__locale/man.rst +++ b/cdist/conf/type/__locale/man.rst @@ -3,7 +3,7 @@ cdist-type__locale(7) NAME ---- -cdit-type__locale - Configure locales +cdist-type__locale - Configure locales DESCRIPTION @@ -34,7 +34,7 @@ EXAMPLES SEE ALSO -------- -:strong:`locale`\ (1), :strong:`localedef`\ (1) +:strong:`locale`\ (1), :strong:`localedef`\ (1), :strong:`cdist-type__locale_system`\ (7) AUTHORS @@ -44,5 +44,6 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2013-2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013-2016 Nico Schottelius. Free use of this software is +granted under the terms of the GNU General Public License version 3 or +later (GPLv3+). From 4254046129e2ca66aaa7da712d28e1633ab23ce8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Aug 2016 01:06:29 +0200 Subject: [PATCH 0249/1332] Update changelog (__locale_system) --- docs/changelog | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/changelog b/docs/changelog index f73ba776..47e6237c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * New type: __locale_system (Steven Armstrong, Carlos Ortigoza, Nico Schottelius) + 4.2.2: 2016-07-26 * Core: Fix ssh ControlPath socket file error (Darko Poljak) * Documentation: Update cdist man page and cdist-references (Darko Poljak) @@ -151,7 +154,7 @@ Changelog * Documentation: Cleanup up, added HTML links (Tomas Pospisek) * Explorer interfaces: Remove test output (Daniel Heule) * Type __jail: Add messaging support (Jake Guffey) - + 3.1.3: 2014-04-29 * New Type: __yum_repo (Steven Armstrong) * Type __hostname: Add support for CentOS (Nico Schottelius) @@ -313,7 +316,7 @@ Changelog * New Type: __postfix_postconf (Steven Armstrong) * New Type: __postfix_postmap (Steven Armstrong) * New Type: __postfix_reload (Steven Armstrong) - * Type __line: Ensure regex does not contain / + * Type __line: Ensure regex does not contain / * Type __ssh_authorized_keys: Bugfix: Preserve ownership (Steven Armstrong) 2.3.3: 2013-09-09 @@ -391,7 +394,7 @@ Changelog * Support for CDIST_PATH (Steven Armstrong) 2.1.0pre8: 2012-11-15 - * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, + * Type cleanup: __apt_ppa, __apt_ppa_update_index, __file, __ssh_authorized_key, __timezone, all install types (Steven Armstrong) * Types: Remove all parameter changing code (Nico Schottelius) * Type __rvm_ruby: Change parameter "default" to be boolean (Nico Schottelius) @@ -455,7 +458,7 @@ Changelog * Feature __group: Added support for FreeBSD (Jake Guffey) * New Type: __package_zypper (Nico Schottelius) * Feature Types: Initial Support for SuSE Linux (Nico Schottelius) - + 2.0.13: 2012-06-05 * Bugfix __ssh_authorized_key: Ensure it sets proper group (contradict) * Bugfix __addifnosuchline: Fixed quotes/interpolation bug ("a b" became "a b") (Nico Schottelius) @@ -487,7 +490,7 @@ Changelog * Various smaller bugfixes (Chris Lamb) 2.0.9: 2012-03-12 - * Cleanup documentation: Fix environment variable list to be properly + * Cleanup documentation: Fix environment variable list to be properly displayed (Giel van Schijndel) * Cleanup documentation: Some minor corrections * New Type: __package_opkg (Giel van Schijndel) @@ -496,7 +499,7 @@ Changelog * Feature __package: Support for OpenWRT (Giel van Schijndel) * Feature __start_on_boot: Support for OpenWRT (Giel van Schijndel) * Feature __start_on_boot: Support for Amazon Linux (Matt Coddington) - * New Example: Use rsync to backup files (Matt Coddington) + * New Example: Use rsync to backup files (Matt Coddington) * Feature core: Exit non-zero, if configuration failed (Nico Schottelius) * Documentation: Describe how to do templating (Aurélien Bondis) @@ -541,7 +544,7 @@ Changelog (Steven Armstrong, Daniel Maher) * Cleanup: Explicitly require Python >= 3.2 (do not fail implicitly) (Nico Schottelius) * Documentation: (Re)write of the tutorial (Nico Schottelius) - * Feature: __addifnosuchline supports matching on + * Feature: __addifnosuchline supports matching on regular expressions (Daniel Maher) * Feature: __directory, __file, __link: Add --state parameter (Steven Armstrong) From a1ff7555768c74288475651a6e1ae51a17c3221b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 31 Jul 2016 23:50:37 +0200 Subject: [PATCH 0250/1332] Add type __sysctl - Migrated asciidoc to rst - Changed license to GPLv3+ --- cdist/conf/type/__sysctl/explorer/value | 22 ++++++++++++ cdist/conf/type/__sysctl/gencode-remote | 30 ++++++++++++++++ cdist/conf/type/__sysctl/man.rst | 38 ++++++++++++++++++++ cdist/conf/type/__sysctl/manifest | 39 +++++++++++++++++++++ cdist/conf/type/__sysctl/parameter/required | 1 + 5 files changed, 130 insertions(+) create mode 100755 cdist/conf/type/__sysctl/explorer/value create mode 100755 cdist/conf/type/__sysctl/gencode-remote create mode 100644 cdist/conf/type/__sysctl/man.rst create mode 100755 cdist/conf/type/__sysctl/manifest create mode 100644 cdist/conf/type/__sysctl/parameter/required diff --git a/cdist/conf/type/__sysctl/explorer/value b/cdist/conf/type/__sysctl/explorer/value new file mode 100755 index 00000000..fc85b3d8 --- /dev/null +++ b/cdist/conf/type/__sysctl/explorer/value @@ -0,0 +1,22 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# + +# get the current runtime value +sysctl -n "$__object_id" || true diff --git a/cdist/conf/type/__sysctl/gencode-remote b/cdist/conf/type/__sysctl/gencode-remote new file mode 100755 index 00000000..0f3b0b40 --- /dev/null +++ b/cdist/conf/type/__sysctl/gencode-remote @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# + +value_should="$(cat "$__object/parameter/value")" +value_is="$(cat "$__object/explorer/value")" + +if [ "$value_should" = "$value_is" ]; then + # Nothing to do + exit 0 +fi + +# set the current runtime value +printf 'sysctl -w %s="%s"\n' "$__object_id" "$value_should" diff --git a/cdist/conf/type/__sysctl/man.rst b/cdist/conf/type/__sysctl/man.rst new file mode 100644 index 00000000..e4d5c504 --- /dev/null +++ b/cdist/conf/type/__sysctl/man.rst @@ -0,0 +1,38 @@ +cdist-type__sysctl(7) +===================== + +NAME +---- +cdist-type__sysctl - manage sysctl settings + + +DESCRIPTION +----------- +Manages permanent as well as runtime sysctl settings. +Permament settings are set by managing entries in /etc/sysctl.conf. +Runtime settings are set by directly calling the sysctl executable. + + +REQUIRED PARAMETERS +------------------- +value:: + The value to set for the given key (object_id) + + +EXAMPLES +-------- + +.. code-block:: sh + + __sysctl net.ipv4.ip_forward --value 1 + + +AUTHORS +------- +Steven Armstrong + + +COPYING +------- +Copyright \(C) 2014 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3+). diff --git a/cdist/conf/type/__sysctl/manifest b/cdist/conf/type/__sysctl/manifest new file mode 100755 index 00000000..dd317806 --- /dev/null +++ b/cdist/conf/type/__sysctl/manifest @@ -0,0 +1,39 @@ +#!/bin/sh +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + redhat|centos|ubuntu|debian|archlinux) + : + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac + +__key_value "$__object_name" \ + --key "$__object_id" \ + --file /etc/sysctl.conf \ + --value "$(cat "$__object/parameter/value")" \ + --delimiter '=' diff --git a/cdist/conf/type/__sysctl/parameter/required b/cdist/conf/type/__sysctl/parameter/required new file mode 100644 index 00000000..6d4e1507 --- /dev/null +++ b/cdist/conf/type/__sysctl/parameter/required @@ -0,0 +1 @@ +value From ad5ceac5637d876d7420021f4c133ddc6828969a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 31 Jul 2016 23:54:13 +0200 Subject: [PATCH 0251/1332] Update changelog for new type __sysctl --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 47e6237c..755a5a44 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,8 +1,8 @@ Changelog --------- -next: * New type: __locale_system (Steven Armstrong, Carlos Ortigoza, Nico Schottelius) + * New type: __sysctl (Steven Armstrong) 4.2.2: 2016-07-26 * Core: Fix ssh ControlPath socket file error (Darko Poljak) From 6479ffc4990aaa404d53976d635a9d4e54670e0c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 1 Aug 2016 00:04:02 +0200 Subject: [PATCH 0252/1332] Really fix the GPLv3+ text --- cdist/conf/type/__sysctl/man.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__sysctl/man.rst b/cdist/conf/type/__sysctl/man.rst index e4d5c504..d5c6495c 100644 --- a/cdist/conf/type/__sysctl/man.rst +++ b/cdist/conf/type/__sysctl/man.rst @@ -35,4 +35,5 @@ Steven Armstrong COPYING ------- Copyright \(C) 2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3+). +granted under the terms of the GNU General Public License version 3 or +later (GPLv3+). From 13b2443d6b7d4e181fc6dac4b112dd43292ead4d Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 2 Aug 2016 10:07:27 +0200 Subject: [PATCH 0253/1332] last cleanups --- cdist/conf/type/__filesystem/explorer/lsblk | 2 +- cdist/conf/type/__filesystem/gencode-remote | 10 +++++----- cdist/conf/type/__filesystem/man.rst | 10 +++++----- cdist/conf/type/__filesystem/parameter/required | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cdist/conf/type/__filesystem/explorer/lsblk b/cdist/conf/type/__filesystem/explorer/lsblk index 87f95e90..a0a87a9d 100644 --- a/cdist/conf/type/__filesystem/explorer/lsblk +++ b/cdist/conf/type/__filesystem/explorer/lsblk @@ -20,7 +20,7 @@ os=$("$__explorer/os") -blkdev="$(cat "$__object/parameter/blkdev")" +blkdev="$(cat "$__object/parameter/device")" case "$os" in centos|fedora|redhat|suse|gentoo) diff --git a/cdist/conf/type/__filesystem/gencode-remote b/cdist/conf/type/__filesystem/gencode-remote index feb7098d..66c25ef0 100644 --- a/cdist/conf/type/__filesystem/gencode-remote +++ b/cdist/conf/type/__filesystem/gencode-remote @@ -20,7 +20,7 @@ fstype="$(cat "$__object/parameter/fstype")" -mydev="$(cat "$__object/parameter/blkdev")" +mydev="$(cat "$__object/parameter/device")" label="$(cat "$__object/parameter/label")" mkfsoptions="$(cat "$__object/parameter/mkfsoptions")" @@ -35,10 +35,10 @@ fi -blkdev_devname="$(grep -P -o2 'NAME="\K[^"]*' "$__object/explorer/lsblk")" -blkdev_fstype="$(grep -P -o2 'FSTYPE="\K[^"]*' "$__object/explorer/lsblk")" -blkdev_label="$(grep -P -o2 'LABEL="\K[^"]*' "$__object/explorer/lsblk")" -blkdev_mountpoint="$(grep -P -o2 'MOUNTPOINT="\K[^"]*' "$__object/explorer/lsblk")" +blkdev_devname="$(grep -P -o 'NAME="\K[^"]*' "$__object/explorer/lsblk")" +blkdev_fstype="$(grep -P -o 'FSTYPE="\K[^"]*' "$__object/explorer/lsblk")" +blkdev_label="$(grep -P -o 'LABEL="\K[^"]*' "$__object/explorer/lsblk")" +blkdev_mountpoint="$(grep -P -o 'MOUNTPOINT="\K[^"]*' "$__object/explorer/lsblk")" if [ -z "$blkdev_devname" ]; then echo "Specified device $mydev not found on target system" >&2 diff --git a/cdist/conf/type/__filesystem/man.rst b/cdist/conf/type/__filesystem/man.rst index c4787d53..25c2eeda 100644 --- a/cdist/conf/type/__filesystem/man.rst +++ b/cdist/conf/type/__filesystem/man.rst @@ -22,7 +22,7 @@ REQUIRED PARAMETERS fstype Filesystem type, for example 'ext3', 'btrfs' or 'xfs' -blkdev +device Blockdevice for filesystem, On linux, it can be any by lsblk accepted device notation @@ -51,7 +51,7 @@ force MESSAGES -------- -filesystem on : created +filesystem on : created Filesytem was created on @@ -61,11 +61,11 @@ EXAMPLES .. code-block:: sh # Ensures that device /dev/sdb is formated with xfs - __filesystem dev_sdb --fstype xfs --blkdev /dev/sdb --label Testdisk1 + __filesystem dev_sdb --fstype xfs --device /dev/sdb --label Testdisk1 # The same thing with btrfs and disk spezified by pci path to disk 1:0 on vmware - __filesystem dev_sdb --fstype btrfs --blkdev /dev/disk/by-path/pci-0000:0b:00.0-scsi-0:0:0:0 --label Testdisk2 + __filesystem dev_sdb --fstype btrfs --device /dev/disk/by-path/pci-0000:0b:00.0-scsi-0:0:0:0 --label Testdisk2 # Make sure that a multipath san device has a filesystem ... - __filesystem dev_sdb --fstype xfs --blkdev /dev/mapper/360060e80432f560050202f22000023ff --label Testdisk3 + __filesystem dev_sdb --fstype xfs --device /dev/mapper/360060e80432f560050202f22000023ff --label Testdisk3 AUTHORS diff --git a/cdist/conf/type/__filesystem/parameter/required b/cdist/conf/type/__filesystem/parameter/required index 33a66684..480e3669 100644 --- a/cdist/conf/type/__filesystem/parameter/required +++ b/cdist/conf/type/__filesystem/parameter/required @@ -1,2 +1,2 @@ fstype -blkdev +device From 8747474fd577eaa6d3ebdb117da02a21915ecf7b Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 2 Aug 2016 11:06:17 +0200 Subject: [PATCH 0254/1332] device now defaults to object_id --- cdist/conf/type/__filesystem/explorer/lsblk | 6 +++++- cdist/conf/type/__filesystem/gencode-remote | 7 ++++++- cdist/conf/type/__filesystem/man.rst | 11 ++++++----- cdist/conf/type/__filesystem/parameter/optional | 1 + cdist/conf/type/__filesystem/parameter/required | 1 - 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/cdist/conf/type/__filesystem/explorer/lsblk b/cdist/conf/type/__filesystem/explorer/lsblk index a0a87a9d..9ae544ac 100644 --- a/cdist/conf/type/__filesystem/explorer/lsblk +++ b/cdist/conf/type/__filesystem/explorer/lsblk @@ -20,7 +20,11 @@ os=$("$__explorer/os") -blkdev="$(cat "$__object/parameter/device")" +if [ -f "$__object/parameter/device" ]; then + blkdev="$(cat "$__object/parameter/device")" +else + blkdev="$__object_id" +fi case "$os" in centos|fedora|redhat|suse|gentoo) diff --git a/cdist/conf/type/__filesystem/gencode-remote b/cdist/conf/type/__filesystem/gencode-remote index 66c25ef0..3ca1c498 100644 --- a/cdist/conf/type/__filesystem/gencode-remote +++ b/cdist/conf/type/__filesystem/gencode-remote @@ -20,7 +20,12 @@ fstype="$(cat "$__object/parameter/fstype")" -mydev="$(cat "$__object/parameter/device")" + +if [ -f "$__object/parameter/device" ]; then + mydev="$(cat "$__object/parameter/device")" +else + mydev="$__object_id" +fi label="$(cat "$__object/parameter/label")" mkfsoptions="$(cat "$__object/parameter/mkfsoptions")" diff --git a/cdist/conf/type/__filesystem/man.rst b/cdist/conf/type/__filesystem/man.rst index 25c2eeda..c69cc839 100644 --- a/cdist/conf/type/__filesystem/man.rst +++ b/cdist/conf/type/__filesystem/man.rst @@ -22,8 +22,12 @@ REQUIRED PARAMETERS fstype Filesystem type, for example 'ext3', 'btrfs' or 'xfs' + + +OPTIONAL PARAMETERS +------------------- device - Blockdevice for filesystem, + Blockdevice for filesystem, Defaults to object_id. On linux, it can be any by lsblk accepted device notation for example @@ -31,9 +35,6 @@ device or /dev/disk/by-xxxx/xxx or /dev/mapper/xxxx - -OPTIONAL PARAMETERS -------------------- label Label which sould apply on the filesystem @@ -61,7 +62,7 @@ EXAMPLES .. code-block:: sh # Ensures that device /dev/sdb is formated with xfs - __filesystem dev_sdb --fstype xfs --device /dev/sdb --label Testdisk1 + __filesystem /dev/sdb --fstype xfs --label Testdisk1 # The same thing with btrfs and disk spezified by pci path to disk 1:0 on vmware __filesystem dev_sdb --fstype btrfs --device /dev/disk/by-path/pci-0000:0b:00.0-scsi-0:0:0:0 --label Testdisk2 # Make sure that a multipath san device has a filesystem ... diff --git a/cdist/conf/type/__filesystem/parameter/optional b/cdist/conf/type/__filesystem/parameter/optional index 0f63435f..79dddc21 100644 --- a/cdist/conf/type/__filesystem/parameter/optional +++ b/cdist/conf/type/__filesystem/parameter/optional @@ -1,2 +1,3 @@ +device label mkfsoptions diff --git a/cdist/conf/type/__filesystem/parameter/required b/cdist/conf/type/__filesystem/parameter/required index 480e3669..98f8b69f 100644 --- a/cdist/conf/type/__filesystem/parameter/required +++ b/cdist/conf/type/__filesystem/parameter/required @@ -1,2 +1 @@ fstype -device From 67429479f09b3607e0e8b92ca6dd85654e72a4d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 5 Aug 2016 12:31:36 +0200 Subject: [PATCH 0255/1332] Remove very old notes Not up-to-date anymore and might be misleading. --- docs/dev/fancy-ideas | 17 ---- docs/dev/git-post-commit-hook | 108 ------------------------ docs/dev/show_all_exported_variables | 25 ------ docs/dev/sync-to-testhost | 28 ------- docs/dev/todo/3.0 | 1 - docs/dev/todo/niconext | 25 ------ docs/dev/todo/performance-ideas | 3 - docs/dev/todo/steven | 118 --------------------------- docs/dev/todo/tests | 27 ------ 9 files changed, 352 deletions(-) delete mode 100644 docs/dev/fancy-ideas delete mode 100755 docs/dev/git-post-commit-hook delete mode 100755 docs/dev/show_all_exported_variables delete mode 100755 docs/dev/sync-to-testhost delete mode 100644 docs/dev/todo/3.0 delete mode 100644 docs/dev/todo/niconext delete mode 100644 docs/dev/todo/steven delete mode 100644 docs/dev/todo/tests diff --git a/docs/dev/fancy-ideas b/docs/dev/fancy-ideas deleted file mode 100644 index 8ee290cd..00000000 --- a/docs/dev/fancy-ideas +++ /dev/null @@ -1,17 +0,0 @@ -== types with namespaces == -- allow types to have namespaces, e.g. - __path/my/type -implemented as a proof of concept at: -https://github.com/asteven/cdist/tree/type-namespaces - - - -Execute all global explorers only when needed #286 - -My intention is to create a brunch of global explorer which are of use in some cases and makes cdist more userfriendly. But now, all global explorers are allways executed, even the return value of the explorers is never used. - -I think a possible approach can be to replace the result files with pipes, and on first read of the pipe, the explorer is executed by the core, all following read calls from the pipe are answered from the core with the result of the first real execute of the explorer. - -So cdist can have an unlimited number of global explorers and only used explorers are executed on the target host, all other explorers laying around are simply ignored. - -Also a possible approach would be to create a new explorer type (dynamic explorers) which are sitting in a different directory to (for example dynexploer) and only this ones are executed with the conditional approach explained above. So the overhead to create pipes and monitor it is only in place on explorers which are not interesting for everyone ... diff --git a/docs/dev/git-post-commit-hook b/docs/dev/git-post-commit-hook deleted file mode 100755 index b16caa2a..00000000 --- a/docs/dev/git-post-commit-hook +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bash -# Distributed under the terms of the GNU General Public License v2 -# Copyright (c) 2006 Fernando J. Pereda -# -# Git CIA bot in bash. (no, not the POSIX shell, bash). -# It is *heavily* based on Git ciabot.pl by Petr Baudis. -# -# It is meant to be run either on a post-commit hook or in an update -# hook: -# -# post-commit: It parses latest commit and current HEAD to get the -# information it needs. -# -# update: You have to call it once per merged commit: -# -# refname=$1 -# oldhead=$2 -# newhead=$3 -# for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do -# /path/to/ciabot.bash ${refname} ${merged} -# done -# - -# The project as known to CIA -project="cdist" - -# Set to true if you want the full log to be sent -noisy=false - -# Addresses for the e-mail -from="nico-cia.vc@schottelius.org" -to="cia@cia.vc" - -# SMTP client to use -sendmail="/usr/sbin/sendmail -f ${from} ${to}" - -# Changeset URL -url="http://git.schottelius.org/?p=${project};a=commit;h=@@sha1@@" - -# You shouldn't be touching anything else. -if [[ $# = 0 ]] ; then - refname=$(git symbolic-ref HEAD 2>/dev/null) - merged=$(git rev-parse HEAD) -else - refname=$1 - merged=$2 -fi - -refname=${refname##refs/heads/} - -gitver=$(git --version) -gitver=${gitver##* } - -rev=$(git describe ${merged} 2>/dev/null) -[[ -z ${rev} ]] && rev=${merged:0:12} - -rawcommit=$(git cat-file commit ${merged}) - -author=$(sed -n -e '/^author .*<\([^@]*\).*$/s--\1-p' \ - <<< "${rawcommit}") - -logmessage=$(sed -e '1,/^$/d' <<< "${rawcommit}") -${noisy} || logmessage=$(head -n 1 <<< "${logmessage}") -logmessage=${logmessage//&/&} -logmessage=${logmessage///>} - -ts=$(sed -n -e '/^author .*> \([0-9]\+\).*$/s--\1-p' \ - <<< "${rawcommit}") - -out=" - - - CIA Bash client for Git - ${gitver} - http://dev.gentoo.org/~ferdy/stuff/ciabot.bash - - - ${project} - ${refname} - - ${ts} - - - ${author} - ${rev} - - $(git diff-tree -r --name-only ${merged} | - sed -e '1d' -e 's-.*-&-') - - -${logmessage} - - ${url//@@sha1@@/${merged}} - - -" - -${sendmail} << EOM -Message-ID: <${merged:0:12}.${author}@${project}> -From: ${from} -To: ${to} -Content-type: text/xml -Subject: DeliverXML -${out} -EOM - -# vim: set tw=70 : diff --git a/docs/dev/show_all_exported_variables b/docs/dev/show_all_exported_variables deleted file mode 100755 index 18acceca..00000000 --- a/docs/dev/show_all_exported_variables +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# 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 . -# -# -# Generate documentation of exported variables -# - - -cat bin/* | awk '/^export/ { print $2 }' diff --git a/docs/dev/sync-to-testhost b/docs/dev/sync-to-testhost deleted file mode 100755 index cc59eb8d..00000000 --- a/docs/dev/sync-to-testhost +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# -# 2011 Nico Schottelius (nico-cdist at schottelius.org) -# -# 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 . -# -# -# Sync repo to testhosts -# - -dirs="cdist cdist-nutzung" - -for dir in $dirs; do - rsync -av --delete /home/users/nico/p/$dir/ root@rnic01:$dir -done diff --git a/docs/dev/todo/3.0 b/docs/dev/todo/3.0 deleted file mode 100644 index 97699879..00000000 --- a/docs/dev/todo/3.0 +++ /dev/null @@ -1 +0,0 @@ -- remove __self and all references to it diff --git a/docs/dev/todo/niconext b/docs/dev/todo/niconext deleted file mode 100644 index aa5f6001..00000000 --- a/docs/dev/todo/niconext +++ /dev/null @@ -1,25 +0,0 @@ -- introduce default parameters - - valid for optional parameters only - - stored in parameter/default/$name - - - when/where to save? in emulator? - - read vi fsproperty? - -- cleanup object_id handling - - have a look at singletons - -- update/create docs - - cdist-cache:: - How to get use information about the hosts we have been working on [advanced] - - cdist-scaling-tuning:: - How to scale out with cdist and which tunings to apply. [advanced] - - cdist-installation - How to use cdist to install hosts - - check speech publishing - - and speeches, which may be outdated as well - - Create new video for cdist 2.x - http://www.youtube.com/watch?v=PRMjzy48eTI - - - exec flag is not true for manifest anymore - - SSH HINTS - ssh agent - diff --git a/docs/dev/todo/performance-ideas b/docs/dev/todo/performance-ideas index bbbfe427..0320affa 100644 --- a/docs/dev/todo/performance-ideas +++ b/docs/dev/todo/performance-ideas @@ -1,6 +1,3 @@ -- Migrate scripts from bin/* to functions in bin/cdist-deploy-to - Use one pipe-shell for type execution - Parallelise gencode and code-run of all objects - Diff against local cache only instead of real target -- Use only one ssh session? - - Can be indirectly improved via ssh config already! diff --git a/docs/dev/todo/steven b/docs/dev/todo/steven deleted file mode 100644 index 2aacaa42..00000000 --- a/docs/dev/todo/steven +++ /dev/null @@ -1,118 +0,0 @@ -autorequire: - - objects defined in type manifests should be automatically prerequisites of the current object - - __foo/some-id - __other other-id --state present - => require="__other/other-id" __foo/some-id - - -metaparameters: - - steal the metaparameters from puppet: - - # I have to be there before the other one - __directory /etc/ssh \ - --before __file/etc/ssh/sshd_config - - # the other one has to be there before me - __file /etc/ssh/sshd_config \ - --after __directory/etc/ssh - - # if I change, tell the other one about it - __file /etc/ssh/sshd_config \ - --notify __init_script/etc/rc.d/sshd - - # whenever the other one changes, I want to know - __init_script /etc/rc.d/sshd \ - --subscribe __file/etc/ssh/sshd_config - - - how does a type react to a received 'event'? - - maybe something like: - __some_type/ - manifest - ... - gencode-refresh - ... - - gencode-refresh -> code-refresh -> ssh $target sh -e code-refresh - - - - -logging: - - logging from type emulator without clobbering stdout - maybe implement logging server as described here [1] - [1] http://docs.python.org/py3k/howto/logging-cookbook.html#configuration-server-example - - - use different logger to limit output to current area of interest, - e.g. - explorer.$target_host: explorer related messages for the run for $target_host - manifest.$target_host: manifest related messages for the run for $target_host - ... - then one could filter e.g. on explorer.* - - - more granular debug output, - [2] http://blog.ooz.ie/2011/03/python-logging-extending-standard.html - - - -tests: - - __init__(): - - sets up env: __target_host - - run_initial_manifest(): - - parameter is actually used (from __init__) - - ensure changing the manifest actually runs a different manifest - -> give ConfigInstall Constructor different manifest - -> different manifest is executed. - - test all submitted (from core to type manifest) variables: - - ENVIRONMENT - - they are set - - they contain the correct values - - run_type_manifest(): - - test all submitted (from core to type manifest) variables: - - ENVIRONMENT - - they are set - - they contain the correct values - - same tests as for test_initial_manifest_*? - - run_manifest(): - - test all submitted variables: - - ENVIRONMENT - - including __debug, if debug - - they are set - - they contain the correct values - - does $require work? - - check that exception raised, if manifest is not existent - - object_run(): - - ensure no object is run twice - - ensure requirements are taken into account? - - and order of run is adjusted - - check (from extern?) that all needed variables are setup - - ensure no code-{local, remote} is created, - if gencode is not producing code - - ensure THAT code-{local, remote} contains what gencode created - - abort if gencode-* fails - - abort if code-* fails - - abort == raise(FooException) - - gencode-*: ensure ENVIRONMENT is setup correctly - - run_type_explorer() - - ensure ALL type explores have been run - - ensure output is saved to correct path - - ensure a type with {0,1,2} explorers works ? - - none, one, multiple - - ensure ENVIRONMENT is setup correctly - - fails if ANY of the given explorer fails - - run_global_explorers(): - - ensure ALL type explores have been run - - ensure output is saved to correct path - - ensure a type with {0,1,2} explorers works ? - - none, one, multiple - - ensure ENVIRONMENT is setup correctly - - fails if ANY of the given explorer fails - -Code fixes needed: - - - shutil, os.mkdir, etc. everywhere: catch/reraise exceptions correctly diff --git a/docs/dev/todo/tests b/docs/dev/todo/tests deleted file mode 100644 index d2101980..00000000 --- a/docs/dev/todo/tests +++ /dev/null @@ -1,27 +0,0 @@ -Tests needed for config_install: - - cleanup() - - Fail if cache_dir from previous run cannot be deleted - - Fail if cache_dir cannot be created from current out_dir - - filter() - - ensure logformat is changed: target host is prefixed: - LOGLEVEL: target_host: MESSAGE - - link_emulator(): - - ensure that links to ALL types are created - - ensure that links points to correct executable - - i.e. readlink() works - - AND target of readlink is the correct executable - - remote_mkdir() - - is directory created - - remove_remote_path - - is path removed - - transfer_path - - is src to dst transferred? - -emulator: - may only be called with __ as prefix - fail otherwise! From ffc3451c674e9c65febe58cd4f68f35764c8c9bd Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Wed, 20 Jul 2016 18:34:47 +0300 Subject: [PATCH 0256/1332] GPLv3+ relicensing: Ricardo Catalinas --- .../conf/type/__package_update_index/man.rst | 9 +- cdist/conf/type/__package_upgrade_all/man.rst | 8 +- legal/README | 10 + legal/Ricardo_Catalinas.email | 183 ++++++++++++++++++ 4 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 legal/README create mode 100644 legal/Ricardo_Catalinas.email diff --git a/cdist/conf/type/__package_update_index/man.rst b/cdist/conf/type/__package_update_index/man.rst index e64fddae..454aa05b 100644 --- a/cdist/conf/type/__package_update_index/man.rst +++ b/cdist/conf/type/__package_update_index/man.rst @@ -22,7 +22,7 @@ OPTIONAL PARAMETERS type The package manager to use. Default is determined based on the $os explorer variable. - e.g. + e.g. * apt for Debian * yum for Red Hat * pacman for Arch Linux @@ -47,5 +47,8 @@ Ricardo Catalinas Jiménez COPYING ------- -Copyright \(C) 2014 Ricardo Catalinas Jiménez. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). + +Copyright \(C) 2014 Ricardo Catalinas Jiménez. 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/__package_upgrade_all/man.rst b/cdist/conf/type/__package_upgrade_all/man.rst index fd4dba44..62cbc43d 100644 --- a/cdist/conf/type/__package_upgrade_all/man.rst +++ b/cdist/conf/type/__package_upgrade_all/man.rst @@ -44,8 +44,10 @@ AUTHORS ------- Ricardo Catalinas Jiménez - COPYING ------- -Copyright \(C) 2014 Ricardo Catalinas Jiménez. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). + +Copyright \(C) 2014 Ricardo Catalinas Jiménez. 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/legal/README b/legal/README new file mode 100644 index 00000000..91a2a0d3 --- /dev/null +++ b/legal/README @@ -0,0 +1,10 @@ +Around 20 Jule 2016 year was discovered issue, that while all code is +GPLv3+ licensed, type documentation is GPLv3 only. As such +contributors was emailed to ask them permission to relicense to +GPLv3+. + +This directory contains emails, containing permission with all +headers. Not sure about legal significance, since email is so easy to +forge, but it is best option availiable. + + -- Dmitry Bogatov Wed, 20 Jul 2016 18:25:27 +0300 diff --git a/legal/Ricardo_Catalinas.email b/legal/Ricardo_Catalinas.email new file mode 100644 index 00000000..306ec073 --- /dev/null +++ b/legal/Ricardo_Catalinas.email @@ -0,0 +1,183 @@ +From kaction Wed Jul 20 18:15:05 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Wed, 20 Jul 2016 11:13:48 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Wed, 20 Jul 2016 18:15:05 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:33032) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bPtBz-0007Ty-T1 + for KAction@gnu.org; Wed, 20 Jul 2016 11:13:48 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bPtBx-0005MG-9h + for KAction@gnu.org; Wed, 20 Jul 2016 11:13:46 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: +X-Spam-Status: No, score=0.8 required=5.0 tests=BAYES_50,FREEMAIL_FROM, + HTML_MESSAGE,T_DKIM_INVALID autolearn=disabled version=3.3.2 +Received: from mail-wm0-x22f.google.com ([2a00:1450:400c:c09::22f]:36812) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bPtBw-0005Lt-Ul + for KAction@gnu.org; Wed, 20 Jul 2016 11:13:45 -0400 +Received: by mail-wm0-x22f.google.com with SMTP id q128so60444546wma.1 + for ; Wed, 20 Jul 2016 08:13:44 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20120113; + h=mime-version:in-reply-to:references:date:message-id:subject:from:to; + bh=YrPuTGXNLw9oFiHKKS+IheiScrs5DuAEvUTlakl0Mxg=; + b=WyUhnGVNalPpcJVnkHrFy1wNBjA/S7fZujrzehx9NGmJFOnawS4GJeatEZ4Pdj3hcq + sBzndUsU57BoYVn99QGM5eELbngARMKyU81V3sobYs5oeP6tFdKxnDpedgS6+yTKXLjP + ZH/tJiINIpXhjSxJkqw8q/dV5SKz6do840Roj1234XUKinRnUPX+zJt3Kjy2M+/dDfL8 + wp5u9xTIS1c9cA3xYN/rdrsIjbRkgo01Yh1wVaZBYpaWFybX09uOSo4fXFGZ6rKQl8iJ + 3M+S3+wQxaP2PZzj9z0eV/GVNM5+5lVcmUjI/PAqIq6nS6mOawolTB078FMFD9cvDRtS + KiNg== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20130820; + h=x-gm-message-state:mime-version:in-reply-to:references:date + :message-id:subject:from:to; + bh=YrPuTGXNLw9oFiHKKS+IheiScrs5DuAEvUTlakl0Mxg=; + b=EwpgAswQ/18QAMRKkz00dKKmXL7loG/R2ZX6KjvFCsBb0x8sV90eWI+17vBF+GVS1y + k6pXyyfLBFgeFBlgjN8oqaSqHhKNoOzWLNKHpOwAW+WnJ/SyprpxdU1BHz2ZOMDTOJuP + 9NTW8LoB4fU24ns1Yor6ykRMeBGQZDvTT3Zi4JsU48522W1WRXXH/Y4sJRm/hdlSaU18 + 1UN7ySE0Oey6Ufk+yG7M6EwJvY7ZI+zRlPsoknGwofg8H6VH7mKBcDvHc71Wk5tGOVMN + iJeKjmgmReG38Em5C+uGO0h9zjsIYZsYC8dUyRCkfNLD66pRdpFuRFIWhG/PU1aH9hIo + Wlng== +X-Gm-Message-State: ALyK8tLwjExHqmfFbrI69OlGTEDrsSCXwwBlBtD3gfpXU42hI/M5850STADANQROCfznBfKvk/zO9N4+82n/hA== +MIME-Version: 1.0 +X-Received: by 10.194.209.163 with SMTP id mn3mr1847437wjc.45.1469027623430; + Wed, 20 Jul 2016 08:13:43 -0700 (PDT) +Received: by 10.194.228.10 with HTTP; Wed, 20 Jul 2016 08:13:43 -0700 (PDT) +Received: by 10.194.228.10 with HTTP; Wed, 20 Jul 2016 08:13:43 -0700 (PDT) +In-Reply-To: +References: +Date: Wed, 20 Jul 2016 16:13:43 +0100 +Message-ID: +Subject: Re: cdist contribution relicensing +From: =?UTF-8?Q?Ricardo_Catalinas_Jim=C3=A9nez?= +To: Dmitry Bogatov +Content-Type: multipart/alternative; boundary=047d7b3a8d24a8fb78053812a524 +X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] +X-Received-From: 2a00:1450:400c:c09::22f +X-UIDL: H8X!!VF3!!(#b"!\C)!! + +--047d7b3a8d24a8fb78053812a524 +Content-Type: text/plain; charset=UTF-8 + + I, Ricardo Catalinas permit to relicense all my +contribution to + cdist project, source codehttps://github.com/ungleich/cdist + to GNU General Public license, version 3 or (at your option) + any later version, as published by Free Software Foundation. + + 20th Jule 2016 year + +/Ricardo + +On Jul 20, 2016 4:11 PM, "Dmitry Bogatov" wrote: + +> +> Hello, dear contributors of cdist project! +> +> Recently we discovered licensing issue with your contribution. Namely, +> while most of code is GPLv3+, including some of code written by you, +> manpages (man.txt, now man.rst) are GPLv3 only licensed. +> +> On behalf of cdist releasers (Darko and Nico), I (another cdist +> contributor and cdist Debian maintainer) ask you to permit relicense +> your contribution from GPLv3 to GPLv3+. Without your permission, we +> would be stuck the day when GPLv4 come (hope it will never come, but +> still), or have to reimplement your contribution. +> +> If you agree, please respond with something like +> +> I, #name# <#email#> permit to relicense all my contribution to +> cdist project, source code https://github.com/ungleich/cdist +> to GNU General Public license, version 3 or (at your option) +> any later version, as published by Free Software Foundation. +> +> #day# Jule 2016 year. +> +> If possible, GPG-sign such email. Do not include anything else +> valuable in this email that you do not want to be stored forever in +> public. +> +> Dear contributors, when replying to this email, please do not send +> copy to other contributors -- save their inbox storage. +> +> Thank you in advance for one more contribution. +> +> -- +> Accept: text/plain, text/x-diff +> Accept-Language: eo,en,ru +> X-Web-Site: sinsekvu.github.io +> + +--047d7b3a8d24a8fb78053812a524 +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + +

=C2=A0 I, Ricardo Catalinas <jimenezrick@gmail.com> permit to relicense all my contr= +ibution to
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 cdist project, source codehttps://github.com/ungleich/cdist
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 to GNU General Public license, version 3 or (at= + your option)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 any later version, as published by Free Softwar= +e Foundation.

+

=C2=A0 =C2=A0 =C2=A0 =C2=A0 20th Jule 2016 year

+

/Ricardo

+

On Jul 20, 2016 4= +:11 PM, "Dmitry Bogatov" <K= +Action@gnu.org> wrote:

+Hello, dear contributors of cdist project!
+
+Recently we discovered licensing issue with your contribution. Namely,
+while most of code is GPLv3+, including some of code written by you,
+manpages (man.txt, now man.rst) are GPLv3 only licensed.
+
+On behalf of cdist releasers (Darko and Nico), I (another cdist
+contributor and cdist Debian maintainer) ask you to permit relicense
+your contribution from GPLv3 to GPLv3+. Without your permission, we
+would be stuck the day when GPLv4 come (hope it will never come, but
+still), or have to reimplement your contribution.
+
+If you agree, please respond with something like
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 I, #name# <#email#> permit to relicense a= +ll my contribution to
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 cdist project, source code https://gith= +ub.com/ungleich/cdist
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 to GNU General Public license, version 3 or (at= + your option)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 any later version, as published by Free Softwar= +e Foundation.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 #day# Jule 2016 year.
+
+If possible, GPG-sign such email. Do not include anything else
+valuable in this email that you do not want to be stored forever in
+public.
+
+Dear contributors, when replying to this email, please do not send
+copy to other contributors -- save their inbox storage.
+
+Thank you in advance for one more contribution.
+
+--
+Accept: text/plain, text/x-diff
+Accept-Language: eo,en,ru
+X-Web-Site: sinsekvu.github.io
+
+ +--047d7b3a8d24a8fb78053812a524-- + From b1152464c328cbee817e891405b6b4ce2117b253 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Fri, 22 Jul 2016 05:14:32 +0300 Subject: [PATCH 0257/1332] Include relicense agreements --- legal/Chase_James.email | 185 +++++++++++++++++++++++++++++++++ legal/Christian_Warden.email | 122 ++++++++++++++++++++++ legal/Daniel_Maher.email | 180 ++++++++++++++++++++++++++++++++ legal/Giel_van_Schijndel.email | 85 +++++++++++++++ legal/Steven_Armstrong.email | 57 ++++++++++ 5 files changed, 629 insertions(+) create mode 100644 legal/Chase_James.email create mode 100644 legal/Christian_Warden.email create mode 100644 legal/Daniel_Maher.email create mode 100644 legal/Giel_van_Schijndel.email create mode 100644 legal/Steven_Armstrong.email diff --git a/legal/Chase_James.email b/legal/Chase_James.email new file mode 100644 index 00000000..c57c62fd --- /dev/null +++ b/legal/Chase_James.email @@ -0,0 +1,185 @@ +From kaction Wed Jul 20 21:30:05 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Wed, 20 Jul 2016 14:25:53 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Wed, 20 Jul 2016 21:30:05 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:48289) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bPwBt-00025s-Lu + for KAction@gnu.org; Wed, 20 Jul 2016 14:25:53 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bPwBr-0007tM-Uq + for KAction@gnu.org; Wed, 20 Jul 2016 14:25:53 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: +X-Spam-Status: No, score=0.8 required=5.0 tests=BAYES_50,HTML_MESSAGE, + T_DKIM_INVALID autolearn=disabled version=3.3.2 +Received: from mail-io0-x236.google.com ([2607:f8b0:4001:c06::236]:32874) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bPwBr-0007t9-NK + for KAction@gnu.org; Wed, 20 Jul 2016 14:25:51 -0400 +Received: by mail-io0-x236.google.com with SMTP id 38so55303707iol.0 + for ; Wed, 20 Jul 2016 11:25:50 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=nu-ex-com.20150623.gappssmtp.com; s=20150623; + h=mime-version:references:in-reply-to:from:date:message-id:subject:to; + bh=jeiFw5Oto9q90WQrIDawOh/M0DSQuTm6MsNWzCa2iqM=; + b=w2EjWx2jk9uB85wrWykVmNEy9QEg28aOHaekBeO8iyoODPF2j8MsXjtXhvUs+4ZxLF + 9fo3qkCLMV9NrPtteb8y4y5kTjbAHJsskIf7r2vdmG1VavbaHlkg8RNya2D90M46cJtz + uaQHQsup+ukaia6j5rQOSq96ioa+hB6mDifxDyvuHY8nbnKnZ3ZYcs+XWnMEBFYa+fPr + Uy/WEnszBVLXVBWh8DN4KNYNuIenzTo0UBSscrriq4vVs3+7uzqimK2jK2OGYAx6sNot + S/DRbSGlY4HRrELgfL654UZsdExXAgphu1X+ibAjCaFjPPK/Nn+rOBif9KFmjLI5c+pF + tLQw== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20130820; + h=x-gm-message-state:mime-version:references:in-reply-to:from:date + :message-id:subject:to; + bh=jeiFw5Oto9q90WQrIDawOh/M0DSQuTm6MsNWzCa2iqM=; + b=QzC2SV8Hl3lehpfi0nN2IboohDGuxFsjoqLSL38THT412ruqWgwQoVLbBQg4XRmAgg + rrT2sR8LCCTHJqUBjFlaTIOAFxxWj8ji9E9p9BNTHHvQ6Gqhl5U3SOPAXvtFtoEPEoLa + 9EyNGzjO7VqsZHoYcYgXf/Tpw8Nsro14Lnv7ShbPS5ZNitwwXlVO+7v1FvxxARQskM3a + NWmw5/8fXLqsd5bQATq6Lq3APmV2wZFmVdJ9QZam9BZHqq5X11hLf6t4r0OgEyhwZ4/o + MX1rJvYL7Qnc3Gy6iQJTw8IJeECYP1jJ+g87C15kgKiyE70x2Xg/dPTPi5wuO2OSBnNq + 0gAg== +X-Gm-Message-State: ALyK8tKkwgnTTOBYgFgESByuR5isjDNaKDDSP1OBDQYyhq6gPsDbGeLfq9zPZ7jm2ZciBSSvH2DS7EF+bA/qcw== +X-Received: by 10.107.130.170 with SMTP id m42mr43873568ioi.78.1469039149834; + Wed, 20 Jul 2016 11:25:49 -0700 (PDT) +MIME-Version: 1.0 +References: +In-Reply-To: +From: nx +Date: Wed, 20 Jul 2016 18:25:40 +0000 +Message-ID: +Subject: Re: cdist contribution relicensing +To: Dmitry Bogatov +Content-Type: multipart/alternative; boundary=001a113bd076affa64053815546c +X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] +X-Received-From: 2607:f8b0:4001:c06::236 +X-UIDL: ~j$"!G$!#!92;"!/;T"! + +--001a113bd076affa64053815546c +Content-Type: text/plain; charset=UTF-8 + +I, Chase James , permit to relicense all my +contribution to cdist project, source code https://github.com/ungleich/cdist + to GNU General Public license, version 3 or (at your option) any later +version, as published by Free Software Foundation. + +20 July 2016 + +On Wed, Jul 20, 2016 at 11:10 AM Dmitry Bogatov wrote: + +> +> Hello, dear contributors of cdist project! +> +> Recently we discovered licensing issue with your contribution. Namely, +> while most of code is GPLv3+, including some of code written by you, +> manpages (man.txt, now man.rst) are GPLv3 only licensed. +> +> On behalf of cdist releasers (Darko and Nico), I (another cdist +> contributor and cdist Debian maintainer) ask you to permit relicense +> your contribution from GPLv3 to GPLv3+. Without your permission, we +> would be stuck the day when GPLv4 come (hope it will never come, but +> still), or have to reimplement your contribution. +> +> If you agree, please respond with something like +> +> I, #name# <#email#> permit to relicense all my contribution to +> cdist project, source code https://github.com/ungleich/cdist +> to GNU General Public license, version 3 or (at your option) +> any later version, as published by Free Software Foundation. +> +> #day# Jule 2016 year. +> +> If possible, GPG-sign such email. Do not include anything else +> valuable in this email that you do not want to be stored forever in +> public. +> +> Dear contributors, when replying to this email, please do not send +> copy to other contributors -- save their inbox storage. +> +> Thank you in advance for one more contribution. +> +> -- +> Accept: text/plain, text/x-diff +> Accept-Language: eo,en,ru +> X-Web-Site: sinsekvu.github.io +> + +--001a113bd076affa64053815546c +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + +
I, Chase James <nx-cdist@nu-ex.com>, permit to relicense a= +ll my contribution to=C2=A0cdist project,= + source code=C2=A0= +https://github.com/ungleich/cdist=C2=A0to GNU General Public license, version 3 or (at your option)=C2= +=A0any later version, as published by Fre= +e Software Foundation.

20 July 2016
= +

On Wed, Jul 20, 2016 = +at 11:10 AM Dmitry Bogatov <KAction@g= +nu.org> wrote:

+Hello, dear contributors of cdist project!
+
+Recently we discovered licensing issue with your contribution. Namely,
+while most of code is GPLv3+, including some of code written by you,
+manpages (man.txt, now man.rst) are GPLv3 only licensed.
+
+On behalf of cdist releasers (Darko and Nico), I (another cdist
+contributor and cdist Debian maintainer) ask you to permit relicense
+your contribution from GPLv3 to GPLv3+. Without your permission, we
+would be stuck the day when GPLv4 come (hope it will never come, but
+still), or have to reimplement your contribution.
+
+If you agree, please respond with something like
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 I, #name# <#email#> permit to relicense a= +ll my contribution to
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 cdist project, source code https://gith= +ub.com/ungleich/cdist
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 to GNU General Public license, version 3 or (at= + your option)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 any later version, as published by Free Softwar= +e Foundation.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 #day# Jule 2016 year.
+
+If possible, GPG-sign such email. Do not include anything else
+valuable in this email that you do not want to be stored forever in
+public.
+
+Dear contributors, when replying to this email, please do not send
+copy to other contributors -- save their inbox storage.
+
+Thank you in advance for one more contribution.
+
+--
+Accept: text/plain, text/x-diff
+Accept-Language: eo,en,ru
+X-Web-Site: sinsekvu.github.io
+
+ +--001a113bd076affa64053815546c-- + diff --git a/legal/Christian_Warden.email b/legal/Christian_Warden.email new file mode 100644 index 00000000..798b3201 --- /dev/null +++ b/legal/Christian_Warden.email @@ -0,0 +1,122 @@ +From kaction Wed Jul 20 18:25:04 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Wed, 20 Jul 2016 11:20:15 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Wed, 20 Jul 2016 18:25:04 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:34238) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bPtIF-000809-Ob + for KAction@gnu.org; Wed, 20 Jul 2016 11:20:15 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bPtIB-0006jv-SP + for KAction@gnu.org; Wed, 20 Jul 2016 11:20:15 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: +X-Spam-Status: No, score=-0.5 required=5.0 tests=BAYES_50,RP_MATCHES_RCVD, + T_DKIM_INVALID autolearn=disabled version=3.3.2 +Received: from sage.xerus.org ([207.210.217.189]:21397) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bPtIB-0006cm-9G + for KAction@gnu.org; Wed, 20 Jul 2016 11:20:11 -0400 +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=xerus.org; s=sage; + h=In-Reply-To:Content-Type:MIME-Version:References:Message-ID:Subject:To:From:Date; bh=O5u4neMHAeGrtpVYFlmpULGNH1YPNhLUEaWPXxzf2xk=; + b=KjzaEXo/CKeUuLj2B1Hrf3krvsJgkMnjqvjJM2KfFJWsiiHU9qPlUtaETBG9jE9tD5MTjg/5/Wr/4u+CnA3xLeNBMIDrFaLaPW2vdlqFsRSVsjl3g/a4LqNrIZcU60/Lwlzb4ber5Y5i69MUX4Y/m1p57FjXTlqONbZZzOa82WQ=; +Received: from c-71-59-214-243.hsd1.or.comcast.net ([71.59.214.243] helo=speedy.xerus.org) + by sage.xerus.org (envelope-from ) + with esmtpsa (Exim 4.80 #2 (Debian)) + id 1bPtHk-0005To-3h + for ; Wed, 20 Jul 2016 08:19:44 -0700 +Received: from cwarden by speedy.xerus.org with local (Exim 4.80) + (envelope-from ) + id 1bPtHj-0007NB-6e + for KAction@gnu.org; Wed, 20 Jul 2016 08:19:43 -0700 +Date: Wed, 20 Jul 2016 08:19:43 -0700 +From: "Christian G. Warden" +To: Dmitry Bogatov +Subject: Re: cdist contribution relicensing +Message-ID: <20160720151943.GD8681@xerus.org> +References: +MIME-Version: 1.0 +Content-Type: multipart/signed; micalg=pgp-sha1; + protocol="application/pgp-signature"; boundary="eAbsdosE1cNLO4uF" +Content-Disposition: inline +In-Reply-To: +X-Face: jD^+@)>yf8|'#1~7ie$N]>2XN},k*wInk~T->gX/l"0?GDg#b;M[;(4'R94H`6,~p"&"(`$ + ?KVH_(2BuS[Zi(IFt,DWb'j77JZMQ~S0mN]o^>zAGQOaz6/uCSFu(O,jf*(e<*'Sa~yW1k1RC0xhd1 + ]'F2p]Wvt3bJ$i2E69!rDttE@/nw?1kS#-#Al(p=G\{Jj4GaRlN(V=R@+&dqD{`v7Y{!WE_?H!iD2D + Z$ +User-Agent: Mutt/1.6.0 (2016-04-01) +X-Sender-Verification: OK +X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x (no timestamps) [generic] +X-Received-From: 207.210.217.189 +X-UIDL: Dh>"!+M_"!, waive all copyright and +related rights in my contribution to the cdist project. + +Christian + +On Wed, Jul 20, 2016 at 06:09:46PM +0300, Dmitry Bogatov wrote: +>=20 +> Hello, dear contributors of cdist project! +>=20 +> Recently we discovered licensing issue with your contribution. Namely, +> while most of code is GPLv3+, including some of code written by you, +> manpages (man.txt, now man.rst) are GPLv3 only licensed. +>=20 +> On behalf of cdist releasers (Darko and Nico), I (another cdist +> contributor and cdist Debian maintainer) ask you to permit relicense +> your contribution from GPLv3 to GPLv3+. Without your permission, we +> would be stuck the day when GPLv4 come (hope it will never come, but +> still), or have to reimplement your contribution. +>=20 +> If you agree, please respond with something like +>=20 +> I, #name# <#email#> permit to relicense all my contribution to +> cdist project, source code https://github.com/ungleich/cdist +> to GNU General Public license, version 3 or (at your option) +> any later version, as published by Free Software Foundation. +>=20 +> #day# Jule 2016 year. +>=20 +> If possible, GPG-sign such email. Do not include anything else +> valuable in this email that you do not want to be stored forever in +> public. +>=20 +> Dear contributors, when replying to this email, please do not send +> copy to other contributors -- save their inbox storage. +>=20 +> Thank you in advance for one more contribution. +>=20 +> -- +> Accept: text/plain, text/x-diff +> Accept-Language: eo,en,ru +> X-Web-Site: sinsekvu.github.io + + + +--eAbsdosE1cNLO4uF +Content-Type: application/pgp-signature; name="signature.asc" + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1 + +iEYEARECAAYFAlePlo8ACgkQXSJ4OU73l6Ap6wCgjNo7oLH8G6KUECBOTyCoGbMk +wgAAoJHq5Tx5EWNO9pg3YvBtff5m1iHx +=srJn +-----END PGP SIGNATURE----- + +--eAbsdosE1cNLO4uF-- + diff --git a/legal/Daniel_Maher.email b/legal/Daniel_Maher.email new file mode 100644 index 00000000..3e7ab892 --- /dev/null +++ b/legal/Daniel_Maher.email @@ -0,0 +1,180 @@ +From kaction Thu Jul 21 17:05:06 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Thu, 21 Jul 2016 10:00:45 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Thu, 21 Jul 2016 17:05:06 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:51771) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bQEWr-0007dw-7V + for KAction@gnu.org; Thu, 21 Jul 2016 10:00:45 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bQEWm-0005MY-BL + for KAction@gnu.org; Thu, 21 Jul 2016 10:00:44 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: * +X-Spam-Status: No, score=1.8 required=5.0 tests=BAYES_50,FREEMAIL_FROM, + FREEMAIL_REPLY,HTML_MESSAGE,T_DKIM_INVALID autolearn=disabled version=3.3.2 +Received: from mail-lf0-x22f.google.com ([2a00:1450:4010:c07::22f]:33089) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bQEWl-0005Lm-Ra + for KAction@gnu.org; Thu, 21 Jul 2016 10:00:40 -0400 +Received: by mail-lf0-x22f.google.com with SMTP id b199so62920486lfe.0 + for ; Thu, 21 Jul 2016 07:00:39 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20120113; + h=mime-version:in-reply-to:references:from:date:message-id:subject:to; + bh=QxAnWA/6Ux99c9jwOxhyzuW7Mgg4vOlk5/YLw6lG7vI=; + b=GxRkrDAKMCBYgbFXFw//11UoxJ1DI3SANR2ZJTIGfJQWun/PdH/UIp9Y/yrUgReQ52 + aF+/xiGwZtwAtNrW5x5sH8t6eKTEDX98F44kqyTn8W0r4UKlFveIGyqGLKhwgiysUa7s + V7t4HeZHf6KuS1M2v7pGHfY8RWNKkcqbAfc1o5RvSf5w7Fma7vwYTfHhpOTHymjJ6Q0r + 9Ite/jxAuZkg1MD1AQftYpJX1MHpEvsZfSwNNl/rc06onY8uF5/WCbORoDJdDvnFnIle + UKDqPxvOO5b82FH1t4YZQy3qN6uJEZj5XHTHNVe0wmnl09hkKJgq2OF7ih1tKLPhxyo+ + MhJw== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20130820; + h=x-gm-message-state:mime-version:in-reply-to:references:from:date + :message-id:subject:to; + bh=QxAnWA/6Ux99c9jwOxhyzuW7Mgg4vOlk5/YLw6lG7vI=; + b=Um0d/lugkccoSfexFcSRQXYK9NPQW24ciOdTfq6HfF1io3u/LCeIg8Vevtk0aY2aJd + 88LeTX66bYD3s3fDRaAo3/GFnjD48IaXkkLNqXD9WHvLdC01RHVerPU0gG0drd28gFfS + BLr6EO7Eyx1VNNFw9eT9PSkzJdRBA73h6zv+/eJLLSI+xz2e9oMlixZ4UnVj7Zc2GDBD + QKftxgjr499rVbkRDXCvjBhEEUdYVJSPlr+gNCnmfy9Me6tqRvjWOwGbxwvnOj/DZ0Lc + s7F7oy6K3DnJMweLH48JsQLiOp4FDJjMydhrxavr2FZ1xdTtDXQzxQCPZfyJsilteQKd + VX1A== +X-Gm-Message-State: ALyK8tJIaYrPzw331bl+6pm5hf75dGrGWIlW3nvRHHCunoAIji4D3HIofy8DADE4ckYnaOxRSf6aYlYIrHPoYg== +X-Received: by 10.25.22.152 with SMTP id 24mr24682317lfw.180.1469109638281; + Thu, 21 Jul 2016 07:00:38 -0700 (PDT) +MIME-Version: 1.0 +Received: by 10.25.85.141 with HTTP; Thu, 21 Jul 2016 07:00:18 -0700 (PDT) +In-Reply-To: +References: +From: dan maher +Date: Thu, 21 Jul 2016 16:00:18 +0200 +Message-ID: +Subject: Re: cdist contribution relicensing +To: Dmitry Bogatov +Content-Type: multipart/alternative; boundary=001a11408306203f8e053825be9d +X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] +X-Received-From: 2a00:1450:4010:c07::22f +X-UIDL: PnS!!MF-!!Y1/!!@L permit to relicense all +my contribution to + cdist project, source code https://github.com/ungleich/cdist + to GNU General Public license, version 3 or (at your option) + any later version, as published by Free Software Foundation. + + 21 July 2016. + +On 20 July 2016 at 17:09, Dmitry Bogatov wrote: + +> +> Hello, dear contributors of cdist project! +> +> Recently we discovered licensing issue with your contribution. Namely, +> while most of code is GPLv3+, including some of code written by you, +> manpages (man.txt, now man.rst) are GPLv3 only licensed. +> +> On behalf of cdist releasers (Darko and Nico), I (another cdist +> contributor and cdist Debian maintainer) ask you to permit relicense +> your contribution from GPLv3 to GPLv3+. Without your permission, we +> would be stuck the day when GPLv4 come (hope it will never come, but +> still), or have to reimplement your contribution. +> +> If you agree, please respond with something like +> +> I, #name# <#email#> permit to relicense all my contribution to +> cdist project, source code https://github.com/ungleich/cdist +> to GNU General Public license, version 3 or (at your option) +> any later version, as published by Free Software Foundation. +> +> #day# Jule 2016 year. +> +> If possible, GPG-sign such email. Do not include anything else +> valuable in this email that you do not want to be stored forever in +> public. +> +> Dear contributors, when replying to this email, please do not send +> copy to other contributors -- save their inbox storage. +> +> Thank you in advance for one more contribution. +> +> -- +> Accept: text/plain, text/x-diff +> Accept-Language: eo,en,ru +> X-Web-Site: sinsekvu.github.io +> + +--001a11408306203f8e053825be9d +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + +
=C2=A0 =C2=A0 =C2=A0 =C2=A0 I, Daniel MAHER <phrawzty+cdist@gmail.com> permit= + to relicense all my contribution to
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 cdist project, source code https://gith= +ub.com/ungleich/cdist
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 to GNU General Public license, version 3 or (at= + your option)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 any later version, as published by Free Softwar= +e Foundation.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 21 July 2016.
<= +br>
On 20 July 2016 at 17:09, Dmitry Bogatov <KAct= +ion@gnu.org> wrote:

+Hello, dear contributors of cdist project!
+
+Recently we discovered licensing issue with your contribution. Namely,
+while most of code is GPLv3+, including some of code written by you,
+manpages (man.txt, now man.rst) are GPLv3 only licensed.
+
+On behalf of cdist releasers (Darko and Nico), I (another cdist
+contributor and cdist Debian maintainer) ask you to permit relicense
+your contribution from GPLv3 to GPLv3+. Without your permission, we
+would be stuck the day when GPLv4 come (hope it will never come, but
+still), or have to reimplement your contribution.
+
+If you agree, please respond with something like
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 I, #name# <#email#> permit to relicense a= +ll my contribution to
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 cdist project, source code https://gith= +ub.com/ungleich/cdist
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 to GNU General Public license, version 3 or (at= + your option)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 any later version, as published by Free Softwar= +e Foundation.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 #day# Jule 2016 year.
+
+If possible, GPG-sign such email. Do not include anything else
+valuable in this email that you do not want to be stored forever in
+public.
+
+Dear contributors, when replying to this email, please do not send
+copy to other contributors -- save their inbox storage.
+
+Thank you in advance for one more contribution.
+
+--
+Accept: text/plain, text/x-diff
+Accept-Language: eo,en,ru
+X-Web-Site: sinsekvu.github.io
+

+ +--001a11408306203f8e053825be9d-- + diff --git a/legal/Giel_van_Schijndel.email b/legal/Giel_van_Schijndel.email new file mode 100644 index 00000000..2f085653 --- /dev/null +++ b/legal/Giel_van_Schijndel.email @@ -0,0 +1,85 @@ +From kaction Thu Jul 21 01:10:04 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Wed, 20 Jul 2016 18:06:32 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Thu, 21 Jul 2016 01:10:04 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:44575) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bPzdP-0004KA-R1 + for KAction@gnu.org; Wed, 20 Jul 2016 18:06:31 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bPzdL-0005W4-Bl + for KAction@gnu.org; Wed, 20 Jul 2016 18:06:30 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: +X-Spam-Status: No, score=-0.5 required=5.0 tests=BAYES_50,RP_MATCHES_RCVD + autolearn=disabled version=3.3.2 +Received: from khitomer.mortis.eu ([185.27.175.75]:55475) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bPzdL-0005VB-4y + for KAction@gnu.org; Wed, 20 Jul 2016 18:06:27 -0400 +Received: from salidar.dom.custoft.eu (unknown [IPv6:2001:981:4eab:1:7016:52bb:c51b:646d]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (Client CN "Giel van Schijndel", Issuer "CAcert Class 3 Root" (not verified)) + by khitomer.mortis.eu (Postfix) with ESMTPS id 0634E1D8 + for ; Thu, 21 Jul 2016 00:06:24 +0200 (CEST) +Received: by salidar.dom.custoft.eu (Postfix, from userid 2079) + id BA3033216E; Thu, 21 Jul 2016 00:06:22 +0200 (CEST) +Date: Thu, 21 Jul 2016 00:06:22 +0200 +From: Giel van Schijndel +To: Dmitry Bogatov +Subject: Re: cdist contribution relicensing +Message-ID: <20160720220622.GC2228@salidar.dom.custoft.eu> +References: +MIME-Version: 1.0 +Content-Type: multipart/signed; micalg=pgp-sha1; + protocol="application/pgp-signature"; boundary="2qXFWqzzG3v1+95a" +Content-Disposition: inline +In-Reply-To: +OpenPGP: id=CEE5E742; url=http://gpg.mortis.eu/me.asc +User-Agent: Mutt/1.6.0 (2016-04-01) +X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x +X-Received-From: 185.27.175.75 +X-UIDL: Kgn!!Pf9!!I,+!!#DW"! + + +--2qXFWqzzG3v1+95a +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline +Content-Transfer-Encoding: quoted-printable + +I, Giel van Schijndel, hereby give permission to any recipients of my +contributions to the cdist project done up to this date, to redistribute +these or derivatives thereof 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. For clarity: +these contributions should be reachable through the Git commit +identifiable by SHA-1 160-bit hash 7e57575f9e1ad0909750d116e9eabc15c1c77e2c +to be considered "up to this date". + +Signed, July 21th, 2016. + +--=20 +Met vriendelijke groet, +With kind regards, +Giel van Schijndel + +--2qXFWqzzG3v1+95a +Content-Type: application/pgp-signature; name="signature.asc" + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1 + +iEYEARECAAYFAleP9dgACgkQZBYm/87l50LVfQCfXo/2XqCwreH0VEmsmYzE5nE/ +zlMAn0D8/9qif3bAwOwDtvFKJWtfabrg +=f6r/ +-----END PGP SIGNATURE----- + +--2qXFWqzzG3v1+95a-- + diff --git a/legal/Steven_Armstrong.email b/legal/Steven_Armstrong.email new file mode 100644 index 00000000..02951a32 --- /dev/null +++ b/legal/Steven_Armstrong.email @@ -0,0 +1,57 @@ +From kaction Thu Jul 21 00:55:04 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Wed, 20 Jul 2016 17:51:39 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Thu, 21 Jul 2016 00:55:04 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:42614) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bPzP1-0005f6-89 + for KAction@gnu.org; Wed, 20 Jul 2016 17:51:39 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bPzOx-00032C-RS + for KAction@gnu.org; Wed, 20 Jul 2016 17:51:38 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: +X-Spam-Status: No, score=-0.5 required=5.0 tests=BAYES_50,RP_MATCHES_RCVD + autolearn=disabled version=3.3.2 +Received: from wolke.armstrong.cc ([136.243.209.126]:37928) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bPzOx-00031o-L9 + for KAction@gnu.org; Wed, 20 Jul 2016 17:51:35 -0400 +Sender: steven@armstrong.cc +Subject: Re: cdist contribution relicensing +To: Dmitry Bogatov +References: +From: Steven Armstrong +Message-ID: +Date: Wed, 20 Jul 2016 23:51:28 +0200 +MIME-Version: 1.0 +In-Reply-To: +Content-Type: text/plain; charset=windows-1252; format=flowed +Content-Transfer-Encoding: 7bit +X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] +X-Received-From: 136.243.209.126 +X-UIDL: b-6"!eP*"!*!D"!c+f!! + +Dmitry Bogatov wrote on 07/20/16 17:09: +> I, #name# <#email#> permit to relicense all my contribution to +> cdist project, source code https://github.com/ungleich/cdist +> to GNU General Public license, version 3 or (at your option) +> any later version, as published by Free Software Foundation. +> +> #day# Jule 2016 year. + +I, Steven Armstrong , permit to re-license +all my contribution to the cdist project source code +https://github.com/ungleich/cdist to GNU General Public license, version +3 or (at your option) any later version, as published by Free Software +Foundation. + +20 July 2016 + From df566f4ff8b00c5a254c5634ab0e55df7694e743 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Aug 2016 18:15:54 +0200 Subject: [PATCH 0258/1332] GPLv3+ relicensing. --- cdist/conf/type/__apt_key/man.rst | 6 ++++-- cdist/conf/type/__apt_key_uri/man.rst | 6 ++++-- cdist/conf/type/__apt_norecommends/man.rst | 6 ++++-- cdist/conf/type/__apt_ppa/man.rst | 6 ++++-- cdist/conf/type/__apt_source/man.rst | 6 ++++-- cdist/conf/type/__apt_update_index/man.rst | 6 ++++-- cdist/conf/type/__block/man.rst | 6 ++++-- cdist/conf/type/__ccollect_source/man.rst | 6 ++++-- cdist/conf/type/__cdist/man.rst | 6 ++++-- cdist/conf/type/__cdistmarker/man.rst | 6 ++++-- cdist/conf/type/__config_file/man.rst | 6 ++++-- cdist/conf/type/__consul/man.rst | 6 ++++-- cdist/conf/type/__consul_agent/man.rst | 6 ++++-- cdist/conf/type/__consul_check/man.rst | 6 ++++-- cdist/conf/type/__consul_reload/man.rst | 6 ++++-- cdist/conf/type/__consul_service/man.rst | 6 ++++-- cdist/conf/type/__consul_template/man.rst | 6 ++++-- cdist/conf/type/__consul_template_template/man.rst | 6 ++++-- cdist/conf/type/__consul_watch_checks/man.rst | 6 ++++-- cdist/conf/type/__consul_watch_event/man.rst | 6 ++++-- cdist/conf/type/__consul_watch_key/man.rst | 6 ++++-- cdist/conf/type/__consul_watch_keyprefix/man.rst | 6 ++++-- cdist/conf/type/__consul_watch_nodes/man.rst | 6 ++++-- cdist/conf/type/__consul_watch_service/man.rst | 6 ++++-- cdist/conf/type/__consul_watch_services/man.rst | 6 ++++-- cdist/conf/type/__cron/man.rst | 6 ++++-- cdist/conf/type/__debconf_set_selections/man.rst | 6 ++++-- cdist/conf/type/__directory/man.rst | 6 ++++-- cdist/conf/type/__dog_vdi/man.rst | 6 ++++-- cdist/conf/type/__file/man.rst | 6 ++++-- cdist/conf/type/__firewalld_rule/man.rst | 6 ++++-- cdist/conf/type/__git/man.rst | 6 ++++-- cdist/conf/type/__group/man.rst | 6 ++++-- cdist/conf/type/__hostname/man.rst | 6 ++++-- cdist/conf/type/__iptables_apply/man.rst | 6 ++++-- cdist/conf/type/__iptables_rule/man.rst | 6 ++++-- cdist/conf/type/__issue/man.rst | 6 ++++-- cdist/conf/type/__key_value/man.rst | 6 ++++-- cdist/conf/type/__line/man.rst | 6 ++++-- cdist/conf/type/__link/man.rst | 6 ++++-- cdist/conf/type/__motd/man.rst | 6 ++++-- cdist/conf/type/__mount/man.rst | 6 ++++-- cdist/conf/type/__package/man.rst | 6 ++++-- cdist/conf/type/__package_apt/man.rst | 6 ++++-- cdist/conf/type/__package_luarocks/man.rst | 6 ++++-- cdist/conf/type/__package_opkg/man.rst | 6 ++++-- cdist/conf/type/__package_pacman/man.rst | 6 ++++-- cdist/conf/type/__package_pip/man.rst | 6 ++++-- cdist/conf/type/__package_rubygem/man.rst | 7 +++++-- cdist/conf/type/__package_yum/man.rst | 6 ++++-- cdist/conf/type/__package_zypper/man.rst | 4 +++- cdist/conf/type/__postfix/man.rst | 6 ++++-- cdist/conf/type/__postfix_master/man.rst | 7 ++++--- cdist/conf/type/__postfix_postconf/man.rst | 6 ++++-- cdist/conf/type/__postfix_postmap/man.rst | 6 ++++-- cdist/conf/type/__postfix_reload/man.rst | 6 ++++-- cdist/conf/type/__postgres_database/man.rst | 6 ++++-- cdist/conf/type/__postgres_role/man.rst | 6 ++++-- cdist/conf/type/__process/man.rst | 6 ++++-- cdist/conf/type/__qemu_img/man.rst | 6 ++++-- cdist/conf/type/__rbenv/man.rst | 6 ++++-- cdist/conf/type/__rsync/man.rst | 6 ++++-- cdist/conf/type/__ssh_authorized_key/man.rst | 6 ++++-- cdist/conf/type/__ssh_authorized_keys/man.rst | 6 ++++-- cdist/conf/type/__ssh_dot_ssh/man.rst | 6 ++++-- cdist/conf/type/__staged_file/man.rst | 6 ++++-- cdist/conf/type/__start_on_boot/man.rst | 6 ++++-- cdist/conf/type/__update_alternatives/man.rst | 6 ++++-- cdist/conf/type/__user/man.rst | 6 ++++-- cdist/conf/type/__user_groups/man.rst | 6 ++++-- cdist/conf/type/__yum_repo/man.rst | 6 ++++-- 71 files changed, 284 insertions(+), 142 deletions(-) diff --git a/cdist/conf/type/__apt_key/man.rst b/cdist/conf/type/__apt_key/man.rst index 7ee2a621..9009877e 100644 --- a/cdist/conf/type/__apt_key/man.rst +++ b/cdist/conf/type/__apt_key/man.rst @@ -55,5 +55,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011-2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2014 Steven Armstrong. 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_key_uri/man.rst b/cdist/conf/type/__apt_key_uri/man.rst index e8741dff..82a191b9 100644 --- a/cdist/conf/type/__apt_key_uri/man.rst +++ b/cdist/conf/type/__apt_key_uri/man.rst @@ -45,5 +45,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011-2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2014 Steven Armstrong. 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_norecommends/man.rst b/cdist/conf/type/__apt_norecommends/man.rst index 7ef496c3..001fffe4 100644 --- a/cdist/conf/type/__apt_norecommends/man.rst +++ b/cdist/conf/type/__apt_norecommends/man.rst @@ -36,5 +36,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2014 Steven Armstrong. 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_ppa/man.rst b/cdist/conf/type/__apt_ppa/man.rst index 978e1252..8347c908 100644 --- a/cdist/conf/type/__apt_ppa/man.rst +++ b/cdist/conf/type/__apt_ppa/man.rst @@ -44,5 +44,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011-2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2014 Steven Armstrong. 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_source/man.rst b/cdist/conf/type/__apt_source/man.rst index 31f2e9e6..8aa6c144 100644 --- a/cdist/conf/type/__apt_source/man.rst +++ b/cdist/conf/type/__apt_source/man.rst @@ -63,5 +63,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011-2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2014 Steven Armstrong. 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_update_index/man.rst b/cdist/conf/type/__apt_update_index/man.rst index 326d4c2f..3031902f 100644 --- a/cdist/conf/type/__apt_update_index/man.rst +++ b/cdist/conf/type/__apt_update_index/man.rst @@ -35,5 +35,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__block/man.rst b/cdist/conf/type/__block/man.rst index 6d7b8ba1..90e50381 100644 --- a/cdist/conf/type/__block/man.rst +++ b/cdist/conf/type/__block/man.rst @@ -76,5 +76,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2013 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 Steven Armstrong. 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/__ccollect_source/man.rst b/cdist/conf/type/__ccollect_source/man.rst index a6723fa8..617571bb 100644 --- a/cdist/conf/type/__ccollect_source/man.rst +++ b/cdist/conf/type/__ccollect_source/man.rst @@ -63,5 +63,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2014 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. diff --git a/cdist/conf/type/__cdist/man.rst b/cdist/conf/type/__cdist/man.rst index 1bfb35c5..f02f848a 100644 --- a/cdist/conf/type/__cdist/man.rst +++ b/cdist/conf/type/__cdist/man.rst @@ -57,5 +57,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 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. diff --git a/cdist/conf/type/__cdistmarker/man.rst b/cdist/conf/type/__cdistmarker/man.rst index cb4dace8..f3a8bafe 100644 --- a/cdist/conf/type/__cdistmarker/man.rst +++ b/cdist/conf/type/__cdistmarker/man.rst @@ -49,5 +49,7 @@ Daniel Maher COPYING ------- -Copyright \(C) 2011 Daniel Maher. Free use of this software is granted under -the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Daniel Maher. 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/__config_file/man.rst b/cdist/conf/type/__config_file/man.rst index 414a970b..5e0e58bd 100644 --- a/cdist/conf/type/__config_file/man.rst +++ b/cdist/conf/type/__config_file/man.rst @@ -58,5 +58,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul/man.rst b/cdist/conf/type/__consul/man.rst index c15ded45..19ceb535 100644 --- a/cdist/conf/type/__consul/man.rst +++ b/cdist/conf/type/__consul/man.rst @@ -48,5 +48,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_agent/man.rst b/cdist/conf/type/__consul_agent/man.rst index fcbf112d..0f4aa12c 100644 --- a/cdist/conf/type/__consul_agent/man.rst +++ b/cdist/conf/type/__consul_agent/man.rst @@ -175,5 +175,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_check/man.rst b/cdist/conf/type/__consul_check/man.rst index 699bbfad..dc7895de 100644 --- a/cdist/conf/type/__consul_check/man.rst +++ b/cdist/conf/type/__consul_check/man.rst @@ -96,5 +96,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015-2016 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015-2016 Steven Armstrong. 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/__consul_reload/man.rst b/cdist/conf/type/__consul_reload/man.rst index 410bd5e6..f48a041a 100644 --- a/cdist/conf/type/__consul_reload/man.rst +++ b/cdist/conf/type/__consul_reload/man.rst @@ -36,5 +36,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_service/man.rst b/cdist/conf/type/__consul_service/man.rst index 0c815402..bcfe4067 100644 --- a/cdist/conf/type/__consul_service/man.rst +++ b/cdist/conf/type/__consul_service/man.rst @@ -76,5 +76,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_template/man.rst b/cdist/conf/type/__consul_template/man.rst index a6228cad..f13c699d 100644 --- a/cdist/conf/type/__consul_template/man.rst +++ b/cdist/conf/type/__consul_template/man.rst @@ -135,5 +135,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_template_template/man.rst b/cdist/conf/type/__consul_template_template/man.rst index 406a06df..b2e3820b 100644 --- a/cdist/conf/type/__consul_template_template/man.rst +++ b/cdist/conf/type/__consul_template_template/man.rst @@ -78,5 +78,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015-2016 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015-2016 Steven Armstrong. 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/__consul_watch_checks/man.rst b/cdist/conf/type/__consul_watch_checks/man.rst index 35c8c9ca..a9a9f58d 100644 --- a/cdist/conf/type/__consul_watch_checks/man.rst +++ b/cdist/conf/type/__consul_watch_checks/man.rst @@ -67,5 +67,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_watch_event/man.rst b/cdist/conf/type/__consul_watch_event/man.rst index 03c2f07e..6fe60d40 100644 --- a/cdist/conf/type/__consul_watch_event/man.rst +++ b/cdist/conf/type/__consul_watch_event/man.rst @@ -60,5 +60,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_watch_key/man.rst b/cdist/conf/type/__consul_watch_key/man.rst index efa6cb41..a12f8425 100644 --- a/cdist/conf/type/__consul_watch_key/man.rst +++ b/cdist/conf/type/__consul_watch_key/man.rst @@ -57,5 +57,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_watch_keyprefix/man.rst b/cdist/conf/type/__consul_watch_keyprefix/man.rst index d884eb79..c600323c 100644 --- a/cdist/conf/type/__consul_watch_keyprefix/man.rst +++ b/cdist/conf/type/__consul_watch_keyprefix/man.rst @@ -57,5 +57,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_watch_nodes/man.rst b/cdist/conf/type/__consul_watch_nodes/man.rst index 52974c3c..d886a586 100644 --- a/cdist/conf/type/__consul_watch_nodes/man.rst +++ b/cdist/conf/type/__consul_watch_nodes/man.rst @@ -53,5 +53,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_watch_service/man.rst b/cdist/conf/type/__consul_watch_service/man.rst index f22ee568..37cabcc9 100644 --- a/cdist/conf/type/__consul_watch_service/man.rst +++ b/cdist/conf/type/__consul_watch_service/man.rst @@ -77,5 +77,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__consul_watch_services/man.rst b/cdist/conf/type/__consul_watch_services/man.rst index c53caa04..cea5f901 100644 --- a/cdist/conf/type/__consul_watch_services/man.rst +++ b/cdist/conf/type/__consul_watch_services/man.rst @@ -53,5 +53,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__cron/man.rst b/cdist/conf/type/__cron/man.rst index 59f59e14..d0694738 100644 --- a/cdist/conf/type/__cron/man.rst +++ b/cdist/conf/type/__cron/man.rst @@ -78,5 +78,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011-2013 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2013 Steven Armstrong. 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/__debconf_set_selections/man.rst b/cdist/conf/type/__debconf_set_selections/man.rst index 3f7f05ae..58c25b81 100644 --- a/cdist/conf/type/__debconf_set_selections/man.rst +++ b/cdist/conf/type/__debconf_set_selections/man.rst @@ -47,5 +47,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011-2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2014 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. diff --git a/cdist/conf/type/__directory/man.rst b/cdist/conf/type/__directory/man.rst index e756b1d6..74b00afe 100644 --- a/cdist/conf/type/__directory/man.rst +++ b/cdist/conf/type/__directory/man.rst @@ -95,5 +95,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 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. diff --git a/cdist/conf/type/__dog_vdi/man.rst b/cdist/conf/type/__dog_vdi/man.rst index 2d6f15b8..4be1920d 100644 --- a/cdist/conf/type/__dog_vdi/man.rst +++ b/cdist/conf/type/__dog_vdi/man.rst @@ -53,5 +53,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2014 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. diff --git a/cdist/conf/type/__file/man.rst b/cdist/conf/type/__file/man.rst index e21390c7..7d9b413b 100644 --- a/cdist/conf/type/__file/man.rst +++ b/cdist/conf/type/__file/man.rst @@ -106,5 +106,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2013 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. diff --git a/cdist/conf/type/__firewalld_rule/man.rst b/cdist/conf/type/__firewalld_rule/man.rst index 5e8e25a7..53ae52b8 100644 --- a/cdist/conf/type/__firewalld_rule/man.rst +++ b/cdist/conf/type/__firewalld_rule/man.rst @@ -75,5 +75,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2015 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +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. diff --git a/cdist/conf/type/__git/man.rst b/cdist/conf/type/__git/man.rst index c1341ec0..64adfd2f 100644 --- a/cdist/conf/type/__git/man.rst +++ b/cdist/conf/type/__git/man.rst @@ -54,5 +54,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 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. diff --git a/cdist/conf/type/__group/man.rst b/cdist/conf/type/__group/man.rst index daea0909..614f3d57 100644 --- a/cdist/conf/type/__group/man.rst +++ b/cdist/conf/type/__group/man.rst @@ -74,5 +74,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011-2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2015 Steven Armstrong. 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/__hostname/man.rst b/cdist/conf/type/__hostname/man.rst index ea1186bc..d23a3b8a 100644 --- a/cdist/conf/type/__hostname/man.rst +++ b/cdist/conf/type/__hostname/man.rst @@ -46,5 +46,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__iptables_apply/man.rst b/cdist/conf/type/__iptables_apply/man.rst index 6f9ab923..76e1f6bf 100644 --- a/cdist/conf/type/__iptables_apply/man.rst +++ b/cdist/conf/type/__iptables_apply/man.rst @@ -39,5 +39,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 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. diff --git a/cdist/conf/type/__iptables_rule/man.rst b/cdist/conf/type/__iptables_rule/man.rst index 5256c711..92d8859f 100644 --- a/cdist/conf/type/__iptables_rule/man.rst +++ b/cdist/conf/type/__iptables_rule/man.rst @@ -60,5 +60,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 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. diff --git a/cdist/conf/type/__issue/man.rst b/cdist/conf/type/__issue/man.rst index eacd8378..097f2c01 100644 --- a/cdist/conf/type/__issue/man.rst +++ b/cdist/conf/type/__issue/man.rst @@ -41,5 +41,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 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. diff --git a/cdist/conf/type/__key_value/man.rst b/cdist/conf/type/__key_value/man.rst index 0d0ad3ae..f069d989 100644 --- a/cdist/conf/type/__key_value/man.rst +++ b/cdist/conf/type/__key_value/man.rst @@ -88,5 +88,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__line/man.rst b/cdist/conf/type/__line/man.rst index 11840bac..e6adce9c 100644 --- a/cdist/conf/type/__line/man.rst +++ b/cdist/conf/type/__line/man.rst @@ -71,5 +71,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2012-2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012-2013 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. diff --git a/cdist/conf/type/__link/man.rst b/cdist/conf/type/__link/man.rst index 4560b1af..9dc4665f 100644 --- a/cdist/conf/type/__link/man.rst +++ b/cdist/conf/type/__link/man.rst @@ -54,5 +54,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2012 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. diff --git a/cdist/conf/type/__motd/man.rst b/cdist/conf/type/__motd/man.rst index b568985f..17369684 100644 --- a/cdist/conf/type/__motd/man.rst +++ b/cdist/conf/type/__motd/man.rst @@ -42,5 +42,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 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. diff --git a/cdist/conf/type/__mount/man.rst b/cdist/conf/type/__mount/man.rst index 799288af..d719a1cd 100644 --- a/cdist/conf/type/__mount/man.rst +++ b/cdist/conf/type/__mount/man.rst @@ -78,5 +78,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2014 Steven Armstrong. 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/__package/man.rst b/cdist/conf/type/__package/man.rst index 91319e18..fc36402b 100644 --- a/cdist/conf/type/__package/man.rst +++ b/cdist/conf/type/__package/man.rst @@ -58,5 +58,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__package_apt/man.rst b/cdist/conf/type/__package_apt/man.rst index 45818636..0a7958d4 100644 --- a/cdist/conf/type/__package_apt/man.rst +++ b/cdist/conf/type/__package_apt/man.rst @@ -56,5 +56,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2012 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. diff --git a/cdist/conf/type/__package_luarocks/man.rst b/cdist/conf/type/__package_luarocks/man.rst index fd831aa5..5dc10195 100644 --- a/cdist/conf/type/__package_luarocks/man.rst +++ b/cdist/conf/type/__package_luarocks/man.rst @@ -49,5 +49,7 @@ Christian G. Warden COPYING ------- -Copyright \(C) 2012 SwellPath, Inc. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 SwellPath, Inc. 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/__package_opkg/man.rst b/cdist/conf/type/__package_opkg/man.rst index d7858ba2..0fd40b33 100644 --- a/cdist/conf/type/__package_opkg/man.rst +++ b/cdist/conf/type/__package_opkg/man.rst @@ -49,5 +49,7 @@ Giel van Schijndel COPYING ------- -Copyright \(C) 2012 Giel van Schijndel. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Giel van Schijndel. 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/__package_pacman/man.rst b/cdist/conf/type/__package_pacman/man.rst index 7b9bd1b4..2686202d 100644 --- a/cdist/conf/type/__package_pacman/man.rst +++ b/cdist/conf/type/__package_pacman/man.rst @@ -52,5 +52,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2012 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. diff --git a/cdist/conf/type/__package_pip/man.rst b/cdist/conf/type/__package_pip/man.rst index 85d6d42b..234ceee2 100644 --- a/cdist/conf/type/__package_pip/man.rst +++ b/cdist/conf/type/__package_pip/man.rst @@ -59,5 +59,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 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. diff --git a/cdist/conf/type/__package_rubygem/man.rst b/cdist/conf/type/__package_rubygem/man.rst index 5bec9d2d..96ad21f7 100644 --- a/cdist/conf/type/__package_rubygem/man.rst +++ b/cdist/conf/type/__package_rubygem/man.rst @@ -49,5 +49,8 @@ Chase Allen James COPYING ------- -Copyright \(C) 2011 Chase Allen James. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). + +Copyright \(C) 2011 Chase Allen James. 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/__package_yum/man.rst b/cdist/conf/type/__package_yum/man.rst index 581d3539..45ad9a55 100644 --- a/cdist/conf/type/__package_yum/man.rst +++ b/cdist/conf/type/__package_yum/man.rst @@ -59,5 +59,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2012 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. diff --git a/cdist/conf/type/__package_zypper/man.rst b/cdist/conf/type/__package_zypper/man.rst index cb9cb518..0051359b 100644 --- a/cdist/conf/type/__package_zypper/man.rst +++ b/cdist/conf/type/__package_zypper/man.rst @@ -68,4 +68,6 @@ COPYING ------- Copyright \(C) 2012 Nico Schottelius. Copyright \(C) 2013 Daniel Heule. -Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). +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/__postfix/man.rst b/cdist/conf/type/__postfix/man.rst index dff85fec..43b158e0 100644 --- a/cdist/conf/type/__postfix/man.rst +++ b/cdist/conf/type/__postfix/man.rst @@ -36,5 +36,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__postfix_master/man.rst b/cdist/conf/type/__postfix_master/man.rst index b6e6fc94..07756f74 100644 --- a/cdist/conf/type/__postfix_master/man.rst +++ b/cdist/conf/type/__postfix_master/man.rst @@ -78,6 +78,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). - +Copyright \(C) 2012 Steven Armstrong. 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/__postfix_postconf/man.rst b/cdist/conf/type/__postfix_postconf/man.rst index 5c2c2a0e..3222d4a7 100644 --- a/cdist/conf/type/__postfix_postconf/man.rst +++ b/cdist/conf/type/__postfix_postconf/man.rst @@ -48,5 +48,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__postfix_postmap/man.rst b/cdist/conf/type/__postfix_postmap/man.rst index 2f455346..2a82b44a 100644 --- a/cdist/conf/type/__postfix_postmap/man.rst +++ b/cdist/conf/type/__postfix_postmap/man.rst @@ -36,5 +36,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__postfix_reload/man.rst b/cdist/conf/type/__postfix_reload/man.rst index 36a66d45..944e22fa 100644 --- a/cdist/conf/type/__postfix_reload/man.rst +++ b/cdist/conf/type/__postfix_reload/man.rst @@ -36,5 +36,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__postgres_database/man.rst b/cdist/conf/type/__postgres_database/man.rst index 517c12a3..acceec9b 100644 --- a/cdist/conf/type/__postgres_database/man.rst +++ b/cdist/conf/type/__postgres_database/man.rst @@ -40,5 +40,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__postgres_role/man.rst b/cdist/conf/type/__postgres_role/man.rst index a2a0268a..11fd73d5 100644 --- a/cdist/conf/type/__postgres_role/man.rst +++ b/cdist/conf/type/__postgres_role/man.rst @@ -61,5 +61,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__process/man.rst b/cdist/conf/type/__process/man.rst index 0e4690b1..e439f37c 100644 --- a/cdist/conf/type/__process/man.rst +++ b/cdist/conf/type/__process/man.rst @@ -68,5 +68,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011-2012 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. diff --git a/cdist/conf/type/__qemu_img/man.rst b/cdist/conf/type/__qemu_img/man.rst index 663e9162..210c7f5f 100644 --- a/cdist/conf/type/__qemu_img/man.rst +++ b/cdist/conf/type/__qemu_img/man.rst @@ -47,5 +47,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2012-2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012-2014 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. diff --git a/cdist/conf/type/__rbenv/man.rst b/cdist/conf/type/__rbenv/man.rst index 6341908a..607019cf 100644 --- a/cdist/conf/type/__rbenv/man.rst +++ b/cdist/conf/type/__rbenv/man.rst @@ -43,5 +43,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2012-2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012-2014 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. diff --git a/cdist/conf/type/__rsync/man.rst b/cdist/conf/type/__rsync/man.rst index 295feceb..94b06d63 100644 --- a/cdist/conf/type/__rsync/man.rst +++ b/cdist/conf/type/__rsync/man.rst @@ -108,5 +108,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2015 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +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. diff --git a/cdist/conf/type/__ssh_authorized_key/man.rst b/cdist/conf/type/__ssh_authorized_key/man.rst index a65ebdd9..b58ad879 100644 --- a/cdist/conf/type/__ssh_authorized_key/man.rst +++ b/cdist/conf/type/__ssh_authorized_key/man.rst @@ -65,5 +65,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2014 Steven Armstrong. 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/__ssh_authorized_keys/man.rst b/cdist/conf/type/__ssh_authorized_keys/man.rst index e6829883..ba310ff9 100644 --- a/cdist/conf/type/__ssh_authorized_keys/man.rst +++ b/cdist/conf/type/__ssh_authorized_keys/man.rst @@ -115,5 +115,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012-2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012-2014 Steven Armstrong. 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/__ssh_dot_ssh/man.rst b/cdist/conf/type/__ssh_dot_ssh/man.rst index 3084d60d..7d35affa 100644 --- a/cdist/conf/type/__ssh_dot_ssh/man.rst +++ b/cdist/conf/type/__ssh_dot_ssh/man.rst @@ -43,5 +43,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2014 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2014 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. diff --git a/cdist/conf/type/__staged_file/man.rst b/cdist/conf/type/__staged_file/man.rst index 4c54e5f5..9a6ba732 100644 --- a/cdist/conf/type/__staged_file/man.rst +++ b/cdist/conf/type/__staged_file/man.rst @@ -109,5 +109,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2015 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Steven Armstrong. 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/__start_on_boot/man.rst b/cdist/conf/type/__start_on_boot/man.rst index 4d4dd631..851d1a89 100644 --- a/cdist/conf/type/__start_on_boot/man.rst +++ b/cdist/conf/type/__start_on_boot/man.rst @@ -55,5 +55,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2012 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 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. diff --git a/cdist/conf/type/__update_alternatives/man.rst b/cdist/conf/type/__update_alternatives/man.rst index 2fff3cba..73d82d11 100644 --- a/cdist/conf/type/__update_alternatives/man.rst +++ b/cdist/conf/type/__update_alternatives/man.rst @@ -40,5 +40,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2013 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 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. diff --git a/cdist/conf/type/__user/man.rst b/cdist/conf/type/__user/man.rst index 172bde7c..5001bfa4 100644 --- a/cdist/conf/type/__user/man.rst +++ b/cdist/conf/type/__user/man.rst @@ -94,5 +94,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__user_groups/man.rst b/cdist/conf/type/__user_groups/man.rst index 37fd25d7..6767b7a8 100644 --- a/cdist/conf/type/__user_groups/man.rst +++ b/cdist/conf/type/__user_groups/man.rst @@ -46,5 +46,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__yum_repo/man.rst b/cdist/conf/type/__yum_repo/man.rst index 543a456d..94366c3a 100644 --- a/cdist/conf/type/__yum_repo/man.rst +++ b/cdist/conf/type/__yum_repo/man.rst @@ -118,5 +118,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2014 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2014 Steven Armstrong. 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. From ba0ea2206e35b648cee1b701fc21681f950707a8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Aug 2016 18:18:54 +0200 Subject: [PATCH 0259/1332] Move legal to docs. --- {legal => docs/legal}/Chase_James.email | 0 {legal => docs/legal}/Christian_Warden.email | 0 {legal => docs/legal}/Daniel_Maher.email | 0 {legal => docs/legal}/Giel_van_Schijndel.email | 0 {legal => docs/legal}/README | 0 {legal => docs/legal}/Ricardo_Catalinas.email | 0 {legal => docs/legal}/Steven_Armstrong.email | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {legal => docs/legal}/Chase_James.email (100%) rename {legal => docs/legal}/Christian_Warden.email (100%) rename {legal => docs/legal}/Daniel_Maher.email (100%) rename {legal => docs/legal}/Giel_van_Schijndel.email (100%) rename {legal => docs/legal}/README (100%) rename {legal => docs/legal}/Ricardo_Catalinas.email (100%) rename {legal => docs/legal}/Steven_Armstrong.email (100%) diff --git a/legal/Chase_James.email b/docs/legal/Chase_James.email similarity index 100% rename from legal/Chase_James.email rename to docs/legal/Chase_James.email diff --git a/legal/Christian_Warden.email b/docs/legal/Christian_Warden.email similarity index 100% rename from legal/Christian_Warden.email rename to docs/legal/Christian_Warden.email diff --git a/legal/Daniel_Maher.email b/docs/legal/Daniel_Maher.email similarity index 100% rename from legal/Daniel_Maher.email rename to docs/legal/Daniel_Maher.email diff --git a/legal/Giel_van_Schijndel.email b/docs/legal/Giel_van_Schijndel.email similarity index 100% rename from legal/Giel_van_Schijndel.email rename to docs/legal/Giel_van_Schijndel.email diff --git a/legal/README b/docs/legal/README similarity index 100% rename from legal/README rename to docs/legal/README diff --git a/legal/Ricardo_Catalinas.email b/docs/legal/Ricardo_Catalinas.email similarity index 100% rename from legal/Ricardo_Catalinas.email rename to docs/legal/Ricardo_Catalinas.email diff --git a/legal/Steven_Armstrong.email b/docs/legal/Steven_Armstrong.email similarity index 100% rename from legal/Steven_Armstrong.email rename to docs/legal/Steven_Armstrong.email From b400ae9c949617317c5cf465f6cc362d99bb2c61 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Aug 2016 18:34:49 +0200 Subject: [PATCH 0260/1332] Separate __keyboard type. --- cdist/conf/type/__locale_system/parameter/default/locale | 1 - cdist/conf/type/__locale_system/singleton | 0 docs/changelog | 8 ++------ 3 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 cdist/conf/type/__locale_system/parameter/default/locale delete mode 100644 cdist/conf/type/__locale_system/singleton diff --git a/cdist/conf/type/__locale_system/parameter/default/locale b/cdist/conf/type/__locale_system/parameter/default/locale deleted file mode 100644 index 927508f3..00000000 --- a/cdist/conf/type/__locale_system/parameter/default/locale +++ /dev/null @@ -1 +0,0 @@ -en_US.UTF-8 diff --git a/cdist/conf/type/__locale_system/singleton b/cdist/conf/type/__locale_system/singleton deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/changelog b/docs/changelog index 054910c1..e21d14a5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,15 +1,11 @@ Changelog --------- next: - * New type __filesystem: manage filesystems on devices ( Daniel Heule ) - + * New type: __keyboard: Set keyboard layout (Carlos Ortigoza) + * New type __filesystem: manage filesystems on devices (Daniel Heule) * New type: __locale_system (Steven Armstrong, Carlos Ortigoza, Nico Schottelius) * New type: __sysctl (Steven Armstrong) -next: - * New type: __keyboard: Set keyboard layout (Carlos Ortigoza) - * New type: __locale_system: Set system-wide locale (Carlos Ortigoza) - 4.2.2: 2016-07-26 * Core: Fix ssh ControlPath socket file error (Darko Poljak) * Documentation: Update cdist man page and cdist-references (Darko Poljak) From d82bd52b04fb76dde32e9eba161b7fd9c6528771 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Aug 2016 18:37:40 +0200 Subject: [PATCH 0261/1332] Fix no newline at the end of file. --- cdist/conf/type/__keyboard/parameter/required | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__keyboard/parameter/required b/cdist/conf/type/__keyboard/parameter/required index c3dc0520..aa80e646 100644 --- a/cdist/conf/type/__keyboard/parameter/required +++ b/cdist/conf/type/__keyboard/parameter/required @@ -1 +1 @@ -type \ No newline at end of file +type From dbcc94ab659c861cc9af416073f235da22f21c8c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Aug 2016 23:56:56 +0200 Subject: [PATCH 0262/1332] Add derived env vars for target hostname and fqdn. --- cdist/config.py | 29 +++++++++++++++++-- cdist/core/code.py | 18 ++++++++++-- cdist/core/explorer.py | 6 ++-- cdist/core/manifest.py | 9 ++++-- cdist/emulator.py | 4 ++- cdist/exec/local.py | 9 ++++-- cdist/exec/remote.py | 15 ++++++---- cdist/shell.py | 11 +++++-- cdist/test/__init__.py | 6 +++- cdist/test/code/__init__.py | 16 ++++++++-- .../type/__dump_environment/gencode-local | 2 ++ cdist/test/config/__init__.py | 2 +- cdist/test/emulator/__init__.py | 12 ++++---- .../conf/type/__cdist_test_type/gencode-local | 2 ++ cdist/test/exec/local.py | 26 +++++++++++++---- cdist/test/exec/remote.py | 28 ++++++++++-------- cdist/test/explorer/__init__.py | 2 +- cdist/test/manifest/__init__.py | 18 +++++++++--- .../fixtures/conf/manifest/dump_environment | 2 ++ .../conf/type/__dump_environment/manifest | 2 ++ docs/changelog | 4 +-- docs/src/cdist-manifest.rst | 4 +-- docs/src/cdist-reference.rst.sh | 13 ++++++++- 23 files changed, 181 insertions(+), 59 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index da560e91..dac5e923 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -28,6 +28,7 @@ import time import pprint import itertools import tempfile +import socket import cdist @@ -74,7 +75,7 @@ class Config(object): self.local = local self.remote = remote - self.log = logging.getLogger(self.local.target_host) + self.log = logging.getLogger(self.local.target_host[0]) self.dry_run = dry_run self.explorer = core.Explorer(self.local.target_host, self.local, @@ -229,15 +230,37 @@ class Config(object): log.debug("remote_copy for host \"{}\": {}".format( host, remote_copy)) + try: + # getaddrinfo returns a list of 5-tuples: + # (family, type, proto, canonname, sockaddr) + # where sockaddr is: + # (address, port) for AF_INET, + # (address, port, flow_info, scopeid) for AF_INET6 + ip_addr = socket.getaddrinfo( + host, None, type=socket.SOCK_STREAM)[0][4][0] + host_name = socket.gethostbyaddr(ip_addr)[0] + except socket.gaierror as e: + log.error("{}: {}".format(e[0], e[1])) + # in case of error provide empty value + host_name = None + + try: + host_fqdn = socket.getfqdn(host) + except socket.herror as e: + log.error("{}: {}".format(e[0], e[1])) + # in case of error provide empty value + host_fqdn = None + target_host = (host, host_name, host_fqdn) + local = cdist.exec.local.Local( - target_host=host, + target_host=target_host, base_root_path=host_base_path, host_dir_name=host_dir_name, initial_manifest=args.manifest, add_conf_dirs=args.conf_dir) remote = cdist.exec.remote.Remote( - target_host=host, + target_host=target_host, remote_exec=remote_exec, remote_copy=remote_copy) diff --git a/cdist/core/code.py b/cdist/core/code.py index 8e3cd63e..cfc1316a 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -36,6 +36,9 @@ common: env: PATH: prepend directory with type emulator symlinks == local.bin_path __target_host: the target host we are working on + __target_hostname: the target hostname provided from __target_host + __target_fqdn: the target's fully qualified domain name provided from + __target_host __cdist_manifest: full qualified path of the manifest == script __cdist_type_base_path: full qualified path to the directory where types are defined for use in type emulator @@ -46,6 +49,9 @@ gencode-local env: __target_host: the target host we are working on + __target_hostname: the target hostname provided from __target_host + __target_fqdn: the target's fully qualified domain name provided from + __target_host __global: full qualified path to the global output dir == local.out_path __object: full qualified path to the object's dir @@ -61,6 +67,9 @@ gencode-remote env: __target_host: the target host we are working on + __target_hostname: the target hostname provided from __target_host + __target_fqdn: the target's fully qualified domain name provided from + __target_host __global: full qualified path to the global output dir == local.out_path __object: full qualified path to the object's dir @@ -89,12 +98,17 @@ class Code(object): """Generates and executes cdist code scripts. """ + # target_host is tuple (target_host, target_hostname, target_fqdn) def __init__(self, target_host, local, remote): - self.target_host = target_host + self.target_host = target_host[0] + self.target_hostname = target_host[1] + self.target_fqdn = target_host[2] self.local = local self.remote = remote self.env = { - '__target_host': self.target_host, + '__target_host': self.target_host[0], + '__target_hostname': self.target_host[1], + '__target_fqdn': self.target_host[2], '__global': self.local.base_path, '__files': self.local.files_path, } diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 345f45ff..faf1d23b 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -68,12 +68,14 @@ class Explorer(object): def __init__(self, target_host, local, remote): self.target_host = target_host - self.log = logging.getLogger(target_host) + self.log = logging.getLogger(target_host[0]) self.local = local self.remote = remote self.env = { - '__target_host': self.target_host, + '__target_host': self.target_host[0], + '__target_hostname': self.target_host[1], + '__target_fqdn': self.target_host[2], '__explorer': self.remote.global_explorer_path, } self._type_explorers_transferred = [] diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index ac322101..a16e9346 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -32,6 +32,9 @@ common: env: PATH: prepend directory with type emulator symlinks == local.bin_path __target_host: the target host we are working on + __target_hostname: the target hostname provided from __target_host + __target_fqdn: the target's fully qualified domain name provided from + __target_host __global: full qualified path to the global output dir == local.out_path __cdist_manifest: full qualified path of the manifest == script @@ -95,14 +98,16 @@ class Manifest(object): self.target_host = target_host self.local = local - self.log = logging.getLogger(self.target_host) + self.log = logging.getLogger(self.target_host[0]) self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), # for use in type emulator '__cdist_type_base_path': self.local.type_path, '__global': self.local.base_path, - '__target_host': self.target_host, + '__target_host': self.target_host[0], + '__target_hostname': self.target_host[1], + '__target_fqdn': self.target_host[2], '__files': self.local.files_path, } diff --git a/cdist/emulator.py b/cdist/emulator.py index 58ab7389..52dd6828 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -65,6 +65,8 @@ class Emulator(object): try: self.global_path = self.env['__global'] self.target_host = self.env['__target_host'] + self.target_hostname = self.env['__target_hostname'] + self.target_fqdn = self.env['__target_fqdn'] # Internal variables self.object_source = self.env['__cdist_manifest'] @@ -101,7 +103,7 @@ class Emulator(object): else: logging.root.setLevel(logging.INFO) - self.log = logging.getLogger(self.target_host) + self.log = logging.getLogger(self.target_host[0]) def commandline(self): """Parse command line""" diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 4fdb5170..6876124b 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -83,7 +83,7 @@ class Local(object): return None def _init_log(self): - self.log = logging.getLogger(self.target_host) + self.log = logging.getLogger(self.target_host[0]) def _init_permissions(self): # Setup file permissions using umask @@ -184,8 +184,11 @@ class Local(object): if env is None: env = os.environ.copy() - # Export __target_host for use in __remote_{copy,exec} scripts - env['__target_host'] = self.target_host + # Export __target_host, __target_hostname, __target_fqdn + # for use in __remote_{copy,exec} scripts + env['__target_host'] = self.target_host[0] + env['__target_hostname'] = self.target_host[1] + env['__target_fqdn'] = self.target_host[2] # Export for emulator env['__cdist_object_marker'] = self.object_marker_name diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index b6ff8c1f..f157d65c 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -66,7 +66,7 @@ class Remote(object): self.type_path = os.path.join(self.conf_path, "type") self.global_explorer_path = os.path.join(self.conf_path, "explorer") - self.log = logging.getLogger(self.target_host) + self.log = logging.getLogger(self.target_host[0]) self._init_env() @@ -102,12 +102,12 @@ class Remote(object): command = self._copy.split() path = os.path.join(source, f) command.extend([path, '{0}:{1}'.format( - self.target_host, destination)]) + self.target_host[0], destination)]) self._run_command(command) else: command = self._copy.split() command.extend([source, '{0}:{1}'.format( - self.target_host, destination)]) + self.target_host[0], destination)]) self._run_command(command) def run_script(self, script, env=None, return_output=False): @@ -128,7 +128,7 @@ class Remote(object): """ # prefix given command with remote_exec cmd = self._exec.split() - cmd.append(self.target_host) + cmd.append(self.target_host[0]) # FIXME: replace this by -o SendEnv name -o SendEnv name ... to ssh? # can't pass environment to remote side, so prepend command with @@ -165,9 +165,12 @@ class Remote(object): assert isinstance(command, (list, tuple)), ( "list or tuple argument expected, got: %s" % command) - # export target_host for use in __remote_{exec,copy} scripts + # export target_host, target_hostname, target_fqdn + # for use in __remote_{exec,copy} scripts os_environ = os.environ.copy() - os_environ['__target_host'] = self.target_host + os_environ['__target_host'] = self.target_host[0] + os_environ['__target_hostname'] = self.target_host[1] + os_environ['__target_fqdn'] = self.target_host[2] self.log.debug("Remote run: %s", command) try: diff --git a/cdist/shell.py b/cdist/shell.py index dacff674..ffbc310a 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -38,7 +38,12 @@ class Shell(object): self.shell = shell - self.target_host = "cdist-shell-no-target-host" + self.target_host = ( + "cdist-shell-no-target-host", + "cdist-shell-no-target-host", + "cdist-shell-no-target-host", + ) + self.local = cdist.exec.local.Local( target_host=self.target_host) @@ -59,7 +64,9 @@ class Shell(object): '__cdist_type_base_path': self.local.type_path, '__cdist_manifest': "cdist shell", '__global': self.local.base_path, - '__target_host': self.target_host, + '__target_host': self.target_host[0], + '__target_hostname': self.target_host[1], + '__target_fqdn': self.target_host[2], '__manifest': self.local.manifest_path, '__explorer': self.local.global_explorer_path, '__files': self.local.files_path, diff --git a/cdist/test/__init__.py b/cdist/test/__init__.py index d9630f53..83b0c618 100644 --- a/cdist/test/__init__.py +++ b/cdist/test/__init__.py @@ -37,7 +37,11 @@ class CdistTestCase(unittest.TestCase): remote_exec = os.path.join(global_fixtures_dir, "remote", "exec") remote_copy = os.path.join(global_fixtures_dir, "remote", "copy") - target_host = 'cdisttesthost' + target_host = ( + 'cdisttesthost', + 'cdisttesthost', + 'cdisttesthost', + ) def mkdtemp(self, **kwargs): return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 7f61c13f..83c93f8b 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -41,7 +41,7 @@ class CodeTestCase(test.CdistTestCase): def setUp(self): self.local_dir = self.mkdtemp() - self.hostdir = cdist.str_hash(self.target_host) + self.hostdir = cdist.str_hash(self.target_host[0]) self.host_base_path = os.path.join(self.local_dir, self.hostdir) self.local = local.Local( @@ -83,7 +83,12 @@ class CodeTestCase(test.CdistTestCase): junk, value = line.split(': ') key = junk.split(' ')[1] output_dict[key] = value - self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__target_host'], + self.local.target_host[0]) + self.assertEqual(output_dict['__target_hostname'], + self.local.target_host[1]) + self.assertEqual(output_dict['__target_fqdn'], + self.local.target_host[2]) self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) self.assertEqual(output_dict['__object'], @@ -101,7 +106,12 @@ class CodeTestCase(test.CdistTestCase): junk, value = line.split(': ') key = junk.split(' ')[1] output_dict[key] = value - self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__target_host'], + self.local.target_host[0]) + self.assertEqual(output_dict['__target_hostname'], + self.local.target_host[1]) + self.assertEqual(output_dict['__target_fqdn'], + self.local.target_host[2]) self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__type'], self.cdist_type.absolute_path) self.assertEqual(output_dict['__object'], diff --git a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local index 5883c268..7fa70342 100755 --- a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local +++ b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local @@ -1,6 +1,8 @@ #!/bin/sh echo "echo __target_host: $__target_host" +echo "echo __target_hostname: $__target_hostname" +echo "echo __target_fqdn: $__target_fqdn" echo "echo __global: $__global" echo "echo __type: $__type" echo "echo __object: $__object" diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index cfcc3c70..db753f41 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -55,7 +55,7 @@ class ConfigRunTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() self.local_dir = os.path.join(self.temp_dir, "local") - self.hostdir = cdist.str_hash(self.target_host) + self.hostdir = cdist.str_hash(self.target_host[0]) self.host_base_path = os.path.join(self.local_dir, self.hostdir) os.makedirs(self.host_base_path) self.local = cdist.exec.local.Local( diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 3fe9a4e5..4fd0ed40 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -48,7 +48,7 @@ class EmulatorTestCase(test.CdistTestCase): handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) base_path = self.temp_dir - hostdir = cdist.str_hash(self.target_host) + hostdir = cdist.str_hash(self.target_host[0]) host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( @@ -151,7 +151,7 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) base_path = self.temp_dir - hostdir = cdist.str_hash(self.target_host) + hostdir = cdist.str_hash(self.target_host[0]) host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( @@ -241,7 +241,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() base_path = os.path.join(self.temp_dir, "out") - hostdir = cdist.str_hash(self.target_host) + hostdir = cdist.str_hash(self.target_host[0]) host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( @@ -274,7 +274,7 @@ class OverrideTestCase(test.CdistTestCase): handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) base_path = self.temp_dir - hostdir = cdist.str_hash(self.target_host) + hostdir = cdist.str_hash(self.target_host[0]) host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( @@ -315,7 +315,7 @@ class ArgumentsTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() base_path = self.temp_dir - hostdir = cdist.str_hash(self.target_host) + hostdir = cdist.str_hash(self.target_host[0]) host_base_path = os.path.join(base_path, hostdir) handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) @@ -440,7 +440,7 @@ class StdinTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() base_path = os.path.join(self.temp_dir, "out") - hostdir = cdist.str_hash(self.target_host) + hostdir = cdist.str_hash(self.target_host[0]) host_base_path = os.path.join(base_path, hostdir) self.local = local.Local( diff --git a/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-local b/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-local index 771894fb..3d568ad3 100755 --- a/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-local +++ b/cdist/test/exec/fixtures/conf/type/__cdist_test_type/gencode-local @@ -1,6 +1,8 @@ #!/bin/sh echo "echo __target_host: $__target_host" +echo "echo __target_hostname: $__target_hostname" +echo "echo __target_fqdn: $__target_fqdn" echo "echo __global: $__global" echo "echo __type: $__type" echo "echo __object: $__object" diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index f83fd6b7..0efdfa0a 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -44,10 +44,14 @@ class LocalTestCase(test.CdistTestCase): def setUp(self): - target_host = 'localhost' + target_host = ( + 'localhost', + 'localhost', + 'localhost', + ) self.temp_dir = self.mkdtemp() self.out_parent_path = self.temp_dir - self.hostdir = cdist.str_hash(target_host) + self.hostdir = cdist.str_hash(target_host[0]) self.host_base_path = op.join(self.out_parent_path, self.hostdir) self.out_path = op.join(self.host_base_path, "data") @@ -111,7 +115,11 @@ class LocalTestCase(test.CdistTestCase): test_type = "__file" link_test_local = local.Local( - target_host='localhost', + target_host=( + 'localhost', + 'localhost', + 'localhost', + ), base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, @@ -130,7 +138,11 @@ class LocalTestCase(test.CdistTestCase): test_type = "__cdist_test_type" link_test_local = local.Local( - target_host='localhost', + target_host=( + 'localhost', + 'localhost', + 'localhost', + ), base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, @@ -152,7 +164,11 @@ class LocalTestCase(test.CdistTestCase): os.environ['CDIST_PATH'] = conf_dir link_test_local = local.Local( - target_host='localhost', + target_host=( + 'localhost', + 'localhost', + 'localhost', + ), base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 318e4c7b..1cb4490a 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -34,7 +34,11 @@ class RemoteTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() - self.target_host = 'localhost' + self.target_host = ( + 'localhost', + 'localhost', + 'localhost', + ) self.base_path = self.temp_dir user = getpass.getuser() remote_exec = "ssh -o User=%s -q" % user @@ -67,22 +71,22 @@ class RemoteTestCase(test.CdistTestCase): # /test api def test_run_success(self): - self.remote.run(['/bin/true']) + self.remote.run(['true']) def test_run_fail(self): - self.assertRaises(cdist.Error, self.remote.run, ['/bin/false']) + self.assertRaises(cdist.Error, self.remote.run, ['false']) def test_run_script_success(self): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", "/bin/true"]) + fd.writelines(["#!/bin/sh\n", "true"]) self.remote.run_script(script) def test_run_script_fail(self): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", "/bin/false"]) - self.assertRaises(remote.RemoteScriptError, self.remote.run_script, + fd.writelines(["#!/bin/sh\n", "false"]) + self.assertRaises(cdist.Error, self.remote.run_script, script) def test_run_script_get_output(self): @@ -121,8 +125,8 @@ class RemoteTestCase(test.CdistTestCase): # test if the payload file is in the target directory self.assertTrue(os.path.isfile(os.path.join(target, source_file_name))) - def test_create_directories(self): - self.remote.create_directories() + def test_create_files_dirs(self): + self.remote.create_files_dirs() self.assertTrue(os.path.isdir(self.remote.base_path)) self.assertTrue(os.path.isdir(self.remote.conf_path)) @@ -135,8 +139,8 @@ class RemoteTestCase(test.CdistTestCase): remote_copy = "echo" r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) - self.assertEqual(r.run('/bin/true', return_output=True), - "%s\n" % self.target_host) + self.assertEqual(r.run('true', return_output=True), + "%s\n" % self.target_host[0]) def test_run_script_target_host_in_env(self): handle, remote_exec_path = self.mkstemp(dir=self.temp_dir) @@ -149,9 +153,9 @@ class RemoteTestCase(test.CdistTestCase): remote_exec=remote_exec, remote_copy=remote_copy) handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", "/bin/true"]) + fd.writelines(["#!/bin/sh\n", "true"]) self.assertEqual(r.run_script(script, return_output=True), - "%s\n" % self.target_host) + "%s\n" % self.target_host[0]) def test_run_script_with_env_target_host_in_env(self): handle, script = self.mkstemp(dir=self.temp_dir) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 9a4555b8..9efa1680 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -42,7 +42,7 @@ class ExplorerClassTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() self.local_path = os.path.join(self.temp_dir, "local") - hostdir = cdist.str_hash(self.target_host) + hostdir = cdist.str_hash(self.target_host[0]) base_root_path = os.path.join(self.local_path, hostdir) self.remote_base_path = os.path.join(self.temp_dir, "remote") os.makedirs(self.remote_base_path) diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index cfaefe5c..3e07c1a7 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -49,7 +49,7 @@ class ManifestTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() out_path = self.temp_dir - hostdir = cdist.str_hash(self.target_host) + hostdir = cdist.str_hash(self.target_host[0]) base_root_path = os.path.join(out_path, hostdir) self.local = local.Local( target_host=self.target_host, @@ -60,7 +60,7 @@ class ManifestTestCase(test.CdistTestCase): self.local.create_files_dirs() self.manifest = manifest.Manifest(self.target_host, self.local) - self.log = logging.getLogger(self.target_host) + self.log = logging.getLogger(self.target_host[0]) def tearDown(self): os.environ = self.orig_environ @@ -82,7 +82,12 @@ class ManifestTestCase(test.CdistTestCase): key, value = line.split(': ') output_dict[key] = value self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) - self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__target_host'], + self.local.target_host[0]) + self.assertEqual(output_dict['__target_hostname'], + self.local.target_host[1]) + self.assertEqual(output_dict['__target_fqdn'], + self.local.target_host[2]) self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) @@ -107,7 +112,12 @@ class ManifestTestCase(test.CdistTestCase): key, value = line.split(': ') output_dict[key] = value self.assertTrue(output_dict['PATH'].startswith(self.local.bin_path)) - self.assertEqual(output_dict['__target_host'], self.local.target_host) + self.assertEqual(output_dict['__target_host'], + self.local.target_host[0]) + self.assertEqual(output_dict['__target_hostname'], + self.local.target_host[1]) + self.assertEqual(output_dict['__target_fqdn'], + self.local.target_host[2]) self.assertEqual(output_dict['__global'], self.local.base_path) self.assertEqual(output_dict['__cdist_type_base_path'], self.local.type_path) diff --git a/cdist/test/manifest/fixtures/conf/manifest/dump_environment b/cdist/test/manifest/fixtures/conf/manifest/dump_environment index df901910..702145e2 100755 --- a/cdist/test/manifest/fixtures/conf/manifest/dump_environment +++ b/cdist/test/manifest/fixtures/conf/manifest/dump_environment @@ -3,6 +3,8 @@ cat > $__cdist_test_out << DONE PATH: $PATH __target_host: $__target_host +__target_hostname: $__target_hostname +__target_fqdn: $__target_fqdn __global: $__global __cdist_type_base_path: $__cdist_type_base_path __manifest: $__manifest diff --git a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest index 13efe038..757d07b5 100755 --- a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest +++ b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest @@ -3,6 +3,8 @@ cat > $__cdist_test_out << DONE PATH: $PATH __target_host: $__target_host +__target_hostname: $__target_hostname +__target_fqdn: $__target_fqdn __global: $__global __cdist_type_base_path: $__cdist_type_base_path __type: $__type diff --git a/docs/changelog b/docs/changelog index 5dd49ef5..0906f2c0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,8 +1,8 @@ Changelog --------- next: - * New type __filesystem: manage filesystems on devices ( Daniel Heule ) - + * Core: Add derived env vars for target hostname and fqdn (Darko Poljak) + * New type __filesystem: manage filesystems on devices (Daniel Heule) * New type: __locale_system (Steven Armstrong, Carlos Ortigoza, Nico Schottelius) * New type: __sysctl (Steven Armstrong) diff --git a/docs/src/cdist-manifest.rst b/docs/src/cdist-manifest.rst index 5c35b6a5..5655c6c2 100644 --- a/docs/src/cdist-manifest.rst +++ b/docs/src/cdist-manifest.rst @@ -53,8 +53,8 @@ Cdist expects the initial manifest at **cdist/conf/manifest/init**. Within this initial manifest you define, which objects should be created on which host. To distinguish between hosts, you can use the -environment variable **__target_host**. Let's have a look at a simple -example:: +environment variable **__target_host** and/or **__target_hostname** and/or +**__target_fqdn**. Let's have a look at a simple example:: __cdistmarker diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index 06842450..97b22473 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -226,7 +226,18 @@ __object_name The full qualified name of the current object. Available for: type manifest, type explorer, type gencode. __target_host - The host we are deploying to. + The host we are deploying to. This is primary variable. It's content is + literally the one user passed in. + Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell. +__target_hostname + The hostname of host we are deploying to. This variable is derived from + **__target_host** (using **socket.getaddrinfo(__target_host)** and then + **socket.gethostbyaddr()**). + Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell. +__target_fqdn + The fully qualified domain name of the host we are deploying to. + This variable is derived from **__target_host** + (using **socket.getfqdn()**). Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell. __type Path to the current type. From 45298b810c6293cbcd2c4d2fa379ece45040a75e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 11 Aug 2016 00:04:37 +0200 Subject: [PATCH 0263/1332] Add more comments. --- cdist/config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/config.py b/cdist/config.py index dac5e923..17fb33ca 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -238,6 +238,8 @@ class Config(object): # (address, port, flow_info, scopeid) for AF_INET6 ip_addr = socket.getaddrinfo( host, None, type=socket.SOCK_STREAM)[0][4][0] + # gethostbyaddr returns triple + # (hostname, aliaslist, ipaddrlist) host_name = socket.gethostbyaddr(ip_addr)[0] except socket.gaierror as e: log.error("{}: {}".format(e[0], e[1])) From 8d6e0760dcd2362a04969722dfcfaddfb0095a3d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 11 Aug 2016 21:55:20 +0200 Subject: [PATCH 0264/1332] Fix errors in remote.py unit test. --- cdist/test/exec/remote.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 318e4c7b..121ec4ac 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -67,22 +67,22 @@ class RemoteTestCase(test.CdistTestCase): # /test api def test_run_success(self): - self.remote.run(['/bin/true']) + self.remote.run(['true']) def test_run_fail(self): - self.assertRaises(cdist.Error, self.remote.run, ['/bin/false']) + self.assertRaises(cdist.Error, self.remote.run, ['false']) def test_run_script_success(self): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", "/bin/true"]) + fd.writelines(["#!/bin/sh\n", "true"]) self.remote.run_script(script) def test_run_script_fail(self): handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", "/bin/false"]) - self.assertRaises(remote.RemoteScriptError, self.remote.run_script, + fd.writelines(["#!/bin/sh\n", "false"]) + self.assertRaises(cdist.Error, self.remote.run_script, script) def test_run_script_get_output(self): @@ -121,8 +121,8 @@ class RemoteTestCase(test.CdistTestCase): # test if the payload file is in the target directory self.assertTrue(os.path.isfile(os.path.join(target, source_file_name))) - def test_create_directories(self): - self.remote.create_directories() + def test_create_files_dirs(self): + self.remote.create_files_dirs() self.assertTrue(os.path.isdir(self.remote.base_path)) self.assertTrue(os.path.isdir(self.remote.conf_path)) @@ -135,7 +135,7 @@ class RemoteTestCase(test.CdistTestCase): remote_copy = "echo" r = remote.Remote(self.target_host, base_path=self.base_path, remote_exec=remote_exec, remote_copy=remote_copy) - self.assertEqual(r.run('/bin/true', return_output=True), + self.assertEqual(r.run('true', return_output=True), "%s\n" % self.target_host) def test_run_script_target_host_in_env(self): @@ -149,7 +149,7 @@ class RemoteTestCase(test.CdistTestCase): remote_exec=remote_exec, remote_copy=remote_copy) handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: - fd.writelines(["#!/bin/sh\n", "/bin/true"]) + fd.writelines(["#!/bin/sh\n", "true"]) self.assertEqual(r.run_script(script, return_output=True), "%s\n" % self.target_host) From a4c49201c0d6f4d821fcb21798fa28a2885262b4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 11 Aug 2016 23:54:31 +0200 Subject: [PATCH 0265/1332] Add jobs option for parallel execution, global explorers first. --- cdist/config.py | 7 +++--- cdist/core/explorer.py | 38 ++++++++++++++++++++++++++++----- cdist/test/explorer/__init__.py | 32 +++++++++++++++++++++++++++ scripts/cdist | 20 +++++++++++++++++ 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index da560e91..34d647e1 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -70,15 +70,16 @@ def inspect_ssh_mux_opts(): class Config(object): """Cdist main class to hold arbitrary data""" - def __init__(self, local, remote, dry_run=False): + def __init__(self, local, remote, dry_run=False, jobs=None): self.local = local self.remote = remote self.log = logging.getLogger(self.local.target_host) self.dry_run = dry_run + self.jobs = jobs self.explorer = core.Explorer(self.local.target_host, self.local, - self.remote) + self.remote, jobs=self.jobs) self.manifest = core.Manifest(self.local.target_host, self.local) self.code = core.Code(self.local.target_host, self.local, self.remote) @@ -241,7 +242,7 @@ class Config(object): remote_exec=remote_exec, remote_copy=remote_copy) - c = cls(local, remote, dry_run=args.dry_run) + c = cls(local, remote, dry_run=args.dry_run, jobs=args.jobs) c.run() except cdist.Error as e: diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 345f45ff..ac2a45ca 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -23,6 +23,7 @@ import logging import os import glob +import multiprocessing import cdist @@ -65,7 +66,7 @@ class Explorer(object): """Executes cdist explorers. """ - def __init__(self, target_host, local, remote): + def __init__(self, target_host, local, remote, jobs=None): self.target_host = target_host self.log = logging.getLogger(target_host) @@ -77,6 +78,7 @@ class Explorer(object): '__explorer': self.remote.global_explorer_path, } self._type_explorers_transferred = [] + self.jobs = jobs # global @@ -91,11 +93,37 @@ class Explorer(object): """ self.log.info("Running global explorers") self.transfer_global_explorers() + if self.jobs is None: + self._run_global_explorers_seq(out_path) + else: + self._run_global_explorers_parallel(out_path) + + def _run_global_explorer(self, explorer, out_path): + output = self.run_global_explorer(explorer) + path = os.path.join(out_path, explorer) + with open(path, 'w') as fd: + fd.write(output) + + def _run_global_explorers_seq(self, out_path): + self.log.info("Running global explorers sequentially") for explorer in self.list_global_explorer_names(): - output = self.run_global_explorer(explorer) - path = os.path.join(out_path, explorer) - with open(path, 'w') as fd: - fd.write(output) + self._run_global_explorer(explorer, out_path) + + def _run_global_explorers_parallel(self, out_path): + self.log.info("Running global explorers in {} parallel jobs".format( + self.jobs)) + self.log.info("Starting multiprocessing Pool") + with multiprocessing.Pool(self.jobs) as pool: + self.log.info("Starting async global explorer run") + results = [ + pool.apply_async(self._run_global_explorer, (e, out_path,)) + for e in self.list_global_explorer_names() + ] + self.log.info("Waiting async global explorer run results") + for r in results: + r.get() + self.log.info("Async global explorer run finished") + self.log.info("Multiprocessing Pool finished") def transfer_global_explorers(self): """Transfer the global explorers to the remote side.""" diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 9a4555b8..27820292 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -23,6 +23,7 @@ import os import shutil import getpass +import multiprocessing import cdist from cdist import core @@ -168,3 +169,34 @@ class ExplorerClassTestCase(test.CdistTestCase): cdist_object.create() self.explorer.run_type_explorers(cdist_object) self.assertEqual(cdist_object.explorers, {'world': 'hello'}) + + def test_jobs_parameter(self): + self.assertIsNone(self.explorer.jobs) + expl = explorer.Explorer( + self.target_host, + self.local, + self.remote, + jobs=8) + self.assertEqual(expl.jobs, 8) + + def test_run_parallel_jobs(self): + expl = explorer.Explorer( + self.target_host, + self.local, + self.remote, + jobs=multiprocessing.cpu_count()) + self.assertIsNotNone(expl.jobs) + out_path = self.mkdtemp() + + expl.run_global_explorers(out_path) + names = sorted(expl.list_global_explorer_names()) + output = sorted(os.listdir(out_path)) + + self.assertEqual(names, output) + shutil.rmtree(out_path) + + +if __name__ == '__main__': + import unittest + + unittest.main() diff --git a/scripts/cdist b/scripts/cdist index 953cad78..b7e3a805 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -22,6 +22,20 @@ # +def check_positive_int(value): + import argparse + + try: + val = int(value) + except ValueError as e: + raise argparse.ArgumentTypeError( + "{} is invalid int value".format(value)) + if val <= 0: + raise argparse.ArgumentTypeError( + "{} is invalid positive int value".format(val)) + return val + + def commandline(): """Parse command line""" import argparse @@ -31,6 +45,7 @@ def commandline(): import cdist.shell import shutil import os + import multiprocessing # Construct parser others can reuse parser = {} @@ -105,6 +120,11 @@ def commandline(): '(should behave like ssh)'), action='store', dest='remote_exec', default=os.environ.get('CDIST_REMOTE_EXEC')) + parser['config'].add_argument( + '-j', '--jobs', nargs='?', type=check_positive_int, + help='Specify the maximum number of parallel jobs', + action='store', dest='jobs', + const=multiprocessing.cpu_count()) parser['config'].set_defaults(func=cdist.config.Config.commandline) # Shell From 5f436f21b8a33d56d9d7e5d2ea24ea76c73819d4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Aug 2016 21:14:56 +0200 Subject: [PATCH 0266/1332] Transfer and run global explorers in parallel. --- cdist/core/explorer.py | 43 ++++++++++++++++++++------ cdist/exec/local.py | 12 ++++++++ cdist/exec/remote.py | 54 +++++++++++++++++++++++++++++++-- cdist/test/exec/remote.py | 17 +++++++++++ cdist/test/explorer/__init__.py | 14 +++++++++ docs/changelog | 4 +-- 6 files changed, 131 insertions(+), 13 deletions(-) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index ac2a45ca..efffb6ed 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -69,7 +69,7 @@ class Explorer(object): def __init__(self, target_host, local, remote, jobs=None): self.target_host = target_host - self.log = logging.getLogger(target_host) + self._open_logger() self.local = local self.remote = remote @@ -80,6 +80,9 @@ class Explorer(object): self._type_explorers_transferred = [] self.jobs = jobs + def _open_logger(self): + self.log = logging.getLogger(self.target_host) + # global def list_global_explorer_names(self): @@ -112,24 +115,46 @@ class Explorer(object): def _run_global_explorers_parallel(self, out_path): self.log.info("Running global explorers in {} parallel jobs".format( self.jobs)) - self.log.info("Starting multiprocessing Pool") + self.log.debug("Multiprocessing start method is {}".format( + multiprocessing.get_start_method())) + self.log.info(("Starting multiprocessing Pool for global " + "explorers run")) with multiprocessing.Pool(self.jobs) as pool: - self.log.info("Starting async global explorer run") + self.log.info("Starting async for global explorer run") results = [ pool.apply_async(self._run_global_explorer, (e, out_path,)) for e in self.list_global_explorer_names() ] - self.log.info("Waiting async global explorer run results") + + self.log.info("Waiting async results for global explorer runs") for r in results: - r.get() - self.log.info("Async global explorer run finished") - self.log.info("Multiprocessing Pool finished") + r.get() # self._run_global_explorer returns None + self.log.info(("Multiprocessing run for global explorers " + "finished")) + + # logger is not pickable, so remove it when we pickle + def __getstate__(self): + state = self.__dict__.copy() + if 'log' in state: + del state['log'] + return state + + # recreate logger when we unpickle + def __setstate__(self, state): + self.__dict__.update(state) + self._open_logger() def transfer_global_explorers(self): """Transfer the global explorers to the remote side.""" self.remote.mkdir(self.remote.global_explorer_path) - self.remote.transfer(self.local.global_explorer_path, - self.remote.global_explorer_path) + if self.jobs is None: + self.remote.transfer(self.local.global_explorer_path, + self.remote.global_explorer_path) + else: + self.remote.transfer_dir_parallel( + self.local.global_explorer_path, + self.remote.global_explorer_path, + self.jobs) self.remote.run(["chmod", "0700", "%s/*" % (self.remote.global_explorer_path)]) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 4fdb5170..34826bfb 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -85,6 +85,18 @@ class Local(object): def _init_log(self): self.log = logging.getLogger(self.target_host) + # logger is not pickable, so remove it when we pickle + def __getstate__(self): + state = self.__dict__.copy() + if 'log' in state: + del state['log'] + return state + + # recreate logger when we unpickle + def __setstate__(self, state): + self.__dict__.update(state) + self._init_log() + def _init_permissions(self): # Setup file permissions using umask os.umask(0o077) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index b6ff8c1f..389c0da1 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -26,9 +26,10 @@ import sys import glob import subprocess import logging -import cdist.exec.util as exec_util +import multiprocessing import cdist +import cdist.exec.util as exec_util class DecodeError(cdist.Error): @@ -66,10 +67,25 @@ class Remote(object): self.type_path = os.path.join(self.conf_path, "type") self.global_explorer_path = os.path.join(self.conf_path, "explorer") - self.log = logging.getLogger(self.target_host) + self._open_logger() self._init_env() + def _open_logger(self): + self.log = logging.getLogger(self.target_host) + + # logger is not pickable, so remove it when we pickle + def __getstate__(self): + state = self.__dict__.copy() + if 'log' in state: + del state['log'] + return state + + # recreate logger when we unpickle + def __setstate__(self, state): + self.__dict__.update(state) + self._open_logger() + def _init_env(self): """Setup environment for scripts - HERE????""" # FIXME: better do so in exec functions that require it! @@ -110,6 +126,40 @@ class Remote(object): self.target_host, destination)]) self._run_command(command) + def transfer_dir_parallel(self, source, destination, jobs): + """Transfer a directory to the remote side in parallel mode.""" + self.log.debug("Remote transfer: %s -> %s", source, destination) + self.rmdir(destination) + if os.path.isdir(source): + self.mkdir(destination) + self.log.info("Remote transfer in {} parallel jobs".format( + jobs)) + self.log.debug("Multiprocessing start method is {}".format( + multiprocessing.get_start_method())) + self.log.info(("Starting multiprocessing Pool for parallel " + "remote transfer")) + with multiprocessing.Pool(jobs) as pool: + self.log.info("Starting async for parallel transfer") + commands = [] + for f in glob.glob1(source, '*'): + command = self._copy.split() + path = os.path.join(source, f) + command.extend([path, '{0}:{1}'.format( + self.target_host, destination)]) + commands.append(command) + results = [ + pool.apply_async(self._run_command, (cmd,)) + for cmd in commands + ] + + self.log.info("Waiting async results for parallel transfer") + for r in results: + r.get() # self._run_command returns None + self.log.info(("Multiprocessing for parallel transfer " + "finished")) + else: + raise cdist.Error("Source {} is not a directory".format(source)) + def run_script(self, script, env=None, return_output=False): """Run the given script with the given environment on the remote side. Return the output as a string. diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 121ec4ac..f498c285 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -24,6 +24,7 @@ import getpass import shutil import string import random +import multiprocessing import cdist from cdist import test @@ -121,6 +122,22 @@ class RemoteTestCase(test.CdistTestCase): # test if the payload file is in the target directory self.assertTrue(os.path.isfile(os.path.join(target, source_file_name))) + def test_transfer_dir_parallel(self): + source = self.mkdtemp(dir=self.temp_dir) + # put 8 files in the directory as payload + filenames = [] + for x in range(8): + handle, source_file = self.mkstemp(dir=source) + os.close(handle) + source_file_name = os.path.split(source_file)[-1] + filenames.append(source_file_name) + target = self.mkdtemp(dir=self.temp_dir) + self.remote.transfer_dir_parallel(source, target, + multiprocessing.cpu_count()) + # test if the payload files are in the target directory + for filename in filenames: + self.assertTrue(os.path.isfile(os.path.join(target, filename))) + def test_create_files_dirs(self): self.remote.create_files_dirs() self.assertTrue(os.path.isdir(self.remote.base_path)) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 27820292..8ac9975e 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -179,6 +179,20 @@ class ExplorerClassTestCase(test.CdistTestCase): jobs=8) self.assertEqual(expl.jobs, 8) + def test_transfer_global_explorers_parallel(self): + expl = explorer.Explorer( + self.target_host, + self.local, + self.remote, + jobs=multiprocessing.cpu_count()) + self.assertIsNotNone(expl.jobs) + + expl.transfer_global_explorers() + source = self.local.global_explorer_path + destination = self.remote.global_explorer_path + self.assertEqual(sorted(os.listdir(source)), + sorted(os.listdir(destination))) + def test_run_parallel_jobs(self): expl = explorer.Explorer( self.target_host, diff --git a/docs/changelog b/docs/changelog index 5dd49ef5..13cde84b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,8 +1,8 @@ Changelog --------- next: - * New type __filesystem: manage filesystems on devices ( Daniel Heule ) - + * Core: Add -j, --jobs option for parallel execution and add parallel support for global explorers (Darko Poljak) + * New type __filesystem: manage filesystems on devices (Daniel Heule) * New type: __locale_system (Steven Armstrong, Carlos Ortigoza, Nico Schottelius) * New type: __sysctl (Steven Armstrong) From 55b134597a941f604334386bc4675bbcc50105ed Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Aug 2016 21:20:37 +0200 Subject: [PATCH 0267/1332] Update cdist docs with -j, --jobs option. --- docs/src/man1/cdist.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 5a4873f7..b4dd2c33 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -15,7 +15,10 @@ SYNOPSIS cdist banner [-h] [-d] [-v] - cdist config [-h] [-d] [-V] [-c CONF_DIR] [-f HOSTFILE] [-i MANIFEST] [-p] [-s] [host [host ...]] + config [-h] [-d] [-v] [-c CONF_DIR] [-f HOSTFILE] [-i MANIFEST] + [-n] [-o OUT_PATH] [-p] [-s] [--remote-copy REMOTE_COPY] + [--remote-exec REMOTE_EXEC] [-j [JOBS]] + [host [host ...]] cdist shell [-h] [-d] [-v] [-s SHELL] @@ -96,6 +99,11 @@ Configure one or more hosts. Command to use for remote execution (should behave like ssh) +.. option:: -j [JOBS], --jobs [JOBS] + + Specify the maximum number of parallel jobs; currently only + global explorers are supported + SHELL ----- This command allows you to spawn a shell that enables access From 90454c4e6baaad3d51b34a0add78cad4e7d35ec4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Aug 2016 21:34:10 +0200 Subject: [PATCH 0268/1332] Update jobs option description. --- scripts/cdist | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/cdist b/scripts/cdist index b7e3a805..d6afbeab 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -122,7 +122,8 @@ def commandline(): default=os.environ.get('CDIST_REMOTE_EXEC')) parser['config'].add_argument( '-j', '--jobs', nargs='?', type=check_positive_int, - help='Specify the maximum number of parallel jobs', + help=('Specify the maximum number of parallel jobs; currently ' + 'only global explorers are supported'), action='store', dest='jobs', const=multiprocessing.cpu_count()) parser['config'].set_defaults(func=cdist.config.Config.commandline) From 33b6545a16e3bce2c9426f3fe2f2c4a8a269f8d1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Aug 2016 21:58:44 +0200 Subject: [PATCH 0269/1332] GPLv3+ relicensing. --- cdist/conf/type/__jail/man.rst | 6 +- cdist/conf/type/__jail_freebsd10/man.rst | 6 +- cdist/conf/type/__jail_freebsd9/man.rst | 6 +- cdist/conf/type/__mysql_database/man.rst | 6 +- cdist/conf/type/__package_emerge/man.rst | 6 +- .../__package_emerge_dependencies/man.rst | 6 +- cdist/conf/type/__package_pkg_freebsd/man.rst | 6 +- .../conf/type/__package_pkgng_freebsd/man.rst | 6 +- cdist/conf/type/__pacman_conf/man.rst | 6 +- .../conf/type/__pacman_conf_integrate/man.rst | 6 +- cdist/conf/type/__pf_apply/man.rst | 6 +- cdist/conf/type/__pf_ruleset/man.rst | 6 +- cdist/conf/type/__zypper_repo/man.rst | 6 +- cdist/conf/type/__zypper_service/man.rst | 6 +- docs/legal/Benedikt_Koeppel.email | 185 ++++++++++ docs/legal/Daniel_Heule.email | 97 +++++ docs/legal/Jacob_Guffey.email | 64 ++++ docs/legal/Thomas_Oettli.email | 342 ++++++++++++++++++ 18 files changed, 744 insertions(+), 28 deletions(-) create mode 100644 docs/legal/Benedikt_Koeppel.email create mode 100644 docs/legal/Daniel_Heule.email create mode 100644 docs/legal/Jacob_Guffey.email create mode 100644 docs/legal/Thomas_Oettli.email diff --git a/cdist/conf/type/__jail/man.rst b/cdist/conf/type/__jail/man.rst index bd9826e4..7fc8f455 100644 --- a/cdist/conf/type/__jail/man.rst +++ b/cdist/conf/type/__jail/man.rst @@ -118,5 +118,7 @@ Jake Guffey COPYING ------- -Copyright \(C) 2012,2016 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012,2016 Jake Guffey. 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/__jail_freebsd10/man.rst b/cdist/conf/type/__jail_freebsd10/man.rst index 9efd7c2a..9063f339 100644 --- a/cdist/conf/type/__jail_freebsd10/man.rst +++ b/cdist/conf/type/__jail_freebsd10/man.rst @@ -117,5 +117,7 @@ Jake Guffey COPYING ------- -Copyright \(C) 2012-2016 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012-2016 Jake Guffey. 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/__jail_freebsd9/man.rst b/cdist/conf/type/__jail_freebsd9/man.rst index fe32010d..cc79c785 100644 --- a/cdist/conf/type/__jail_freebsd9/man.rst +++ b/cdist/conf/type/__jail_freebsd9/man.rst @@ -118,5 +118,7 @@ Jake Guffey COPYING ------- -Copyright \(C) 2012-2016 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012-2016 Jake Guffey. 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/__mysql_database/man.rst b/cdist/conf/type/__mysql_database/man.rst index 0e21a8a1..1e245a08 100644 --- a/cdist/conf/type/__mysql_database/man.rst +++ b/cdist/conf/type/__mysql_database/man.rst @@ -43,5 +43,7 @@ Benedikt Koeppel COPYING ------- -Copyright \(C) 2012 Benedikt Koeppel. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Benedikt Koeppel. 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/__package_emerge/man.rst b/cdist/conf/type/__package_emerge/man.rst index 839b647e..88adaff0 100644 --- a/cdist/conf/type/__package_emerge/man.rst +++ b/cdist/conf/type/__package_emerge/man.rst @@ -57,5 +57,7 @@ Thomas Oettli COPYING ------- -Copyright \(C) 2013 Thomas Oettli. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 Thomas Oettli. 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/__package_emerge_dependencies/man.rst b/cdist/conf/type/__package_emerge_dependencies/man.rst index 11531b34..598d31f1 100644 --- a/cdist/conf/type/__package_emerge_dependencies/man.rst +++ b/cdist/conf/type/__package_emerge_dependencies/man.rst @@ -46,5 +46,7 @@ Thomas Oettli COPYING ------- -Copyright \(C) 2013 Thomas Oettli. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 Thomas Oettli. 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/__package_pkg_freebsd/man.rst b/cdist/conf/type/__package_pkg_freebsd/man.rst index 4b210356..b06c7faf 100644 --- a/cdist/conf/type/__package_pkg_freebsd/man.rst +++ b/cdist/conf/type/__package_pkg_freebsd/man.rst @@ -64,5 +64,7 @@ Jake Guffey COPYING ------- -Copyright \(C) 2012 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Jake Guffey. 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/__package_pkgng_freebsd/man.rst b/cdist/conf/type/__package_pkgng_freebsd/man.rst index bdc268af..251e2c5f 100644 --- a/cdist/conf/type/__package_pkgng_freebsd/man.rst +++ b/cdist/conf/type/__package_pkgng_freebsd/man.rst @@ -95,5 +95,7 @@ Jake Guffey COPYING ------- -Copyright \(C) 2014 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2014 Jake Guffey. 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/__pacman_conf/man.rst b/cdist/conf/type/__pacman_conf/man.rst index 931f8812..6b8adfc9 100644 --- a/cdist/conf/type/__pacman_conf/man.rst +++ b/cdist/conf/type/__pacman_conf/man.rst @@ -69,5 +69,7 @@ Dominique Roux COPYING ------- -Copyright \(C) 2015 Dominique Roux. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Dominique Roux. 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/__pacman_conf_integrate/man.rst b/cdist/conf/type/__pacman_conf_integrate/man.rst index f36dca45..c21b56d8 100644 --- a/cdist/conf/type/__pacman_conf_integrate/man.rst +++ b/cdist/conf/type/__pacman_conf_integrate/man.rst @@ -45,5 +45,7 @@ Dominique Roux COPYING ------- -Copyright \(C) 2015 Dominique Roux. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2015 Dominique Roux. 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/__pf_apply/man.rst b/cdist/conf/type/__pf_apply/man.rst index 1b7f4e3b..eee345e7 100644 --- a/cdist/conf/type/__pf_apply/man.rst +++ b/cdist/conf/type/__pf_apply/man.rst @@ -49,5 +49,7 @@ Jake Guffey COPYING ------- -Copyright \(C) 2012 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Jake Guffey. 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/__pf_ruleset/man.rst b/cdist/conf/type/__pf_ruleset/man.rst index 756a9e30..5719e94e 100644 --- a/cdist/conf/type/__pf_ruleset/man.rst +++ b/cdist/conf/type/__pf_ruleset/man.rst @@ -49,5 +49,7 @@ Jake Guffey COPYING ------- -Copyright \(C) 2012 Jake Guffey. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Jake Guffey. 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/__zypper_repo/man.rst b/cdist/conf/type/__zypper_repo/man.rst index 9cc5e1c3..73799d91 100644 --- a/cdist/conf/type/__zypper_repo/man.rst +++ b/cdist/conf/type/__zypper_repo/man.rst @@ -67,5 +67,7 @@ Daniel Heule COPYING ------- -Copyright \(C) 2013 Daniel Heule. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 Daniel Heule. 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/__zypper_service/man.rst b/cdist/conf/type/__zypper_service/man.rst index c76a5ffc..ea48aebb 100644 --- a/cdist/conf/type/__zypper_service/man.rst +++ b/cdist/conf/type/__zypper_service/man.rst @@ -60,5 +60,7 @@ Daniel Heule COPYING ------- -Copyright \(C) 2013 Daniel Heule. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 Daniel Heule. 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/docs/legal/Benedikt_Koeppel.email b/docs/legal/Benedikt_Koeppel.email new file mode 100644 index 00000000..71fb39e9 --- /dev/null +++ b/docs/legal/Benedikt_Koeppel.email @@ -0,0 +1,185 @@ +From kaction Fri Jul 22 10:45:09 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Fri, 22 Jul 2016 03:42:02 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Fri, 22 Jul 2016 10:45:09 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:42146) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bQV5t-0001Ct-WA + for KAction@gnu.org; Fri, 22 Jul 2016 03:42:02 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bQV5r-000365-7C + for KAction@gnu.org; Fri, 22 Jul 2016 03:42:00 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: +X-Spam-Status: No, score=0.8 required=5.0 tests=BAYES_50,HTML_MESSAGE, + T_DKIM_INVALID autolearn=disabled version=3.3.2 +Received: from mail-oi0-x22f.google.com ([2607:f8b0:4003:c06::22f]:32858) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bQV5q-00035k-WC + for KAction@gnu.org; Fri, 22 Jul 2016 03:41:59 -0400 +Received: by mail-oi0-x22f.google.com with SMTP id j185so152015483oih.0 + for ; Fri, 22 Jul 2016 00:41:58 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=benediktkoeppel.ch; s=google; + h=mime-version:in-reply-to:references:from:date:message-id:subject:to; + bh=blJePxf1Q0zVh1kUkaKI6tKoOKbPV9CkRqLrYN8tz+4=; + b=VSpfcDF2tO+mgrTfZGlhHaqbtfYNe/QCbkSH5jWx8CVaItTuu88pTzdHuNZPtYrlQO + KZ6R/7xJrqGdWnKFCUibDAKI1Pd9OAx+ahQsYT5M7eKQt+nM9cMxaiyBjTTPfpF9UVa/ + /anpDGs/Bs6Z/p6c3ElNJOunfeEeS7kscr+Do= +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20130820; + h=x-gm-message-state:mime-version:in-reply-to:references:from:date + :message-id:subject:to; + bh=blJePxf1Q0zVh1kUkaKI6tKoOKbPV9CkRqLrYN8tz+4=; + b=azAT/E+JYRP5bGvTI3t2BGCNsNfHxSWK+NKOtaWNYo1lyATKw9nJsSl1g6osLeanFr + JjpwlqHUN7v18z5ETqI+kvrmUShZjrgzGYE+yQuq++E4z/0C2YOUf+XZkGFVACguKRNt + HmOufiJNmkB2fYsIRMw3R21hLnM5QkIBlujmwbdxrtWyQSQ8Mfr4+sOnfp1ltHKaixIe + phfyJ6K6qP2h71VShDZmopg8Sg9rz6DSHbFDy8Ka9UTT3DXC+sLpdKFAfSebl0Tgd0eE + r0JND1fwL3pDQCxo4uK+GVM3q/usdTgzBwLnlg22clN1eca2oqrqdQdLQzgGuWYOmQg9 + +tTg== +X-Gm-Message-State: AEkoous0GycxMsszEEqNZrxNJGSADUJISKsdXl4E3+tACC8xUjLdUl3dFeAjSq6rGKkDeLMDrrfVceDa+nAo8A== +X-Received: by 10.157.19.98 with SMTP id q31mr1158747otq.125.1469173317562; + Fri, 22 Jul 2016 00:41:57 -0700 (PDT) +MIME-Version: 1.0 +Received: by 10.202.93.135 with HTTP; Fri, 22 Jul 2016 00:41:38 -0700 (PDT) +In-Reply-To: +References: +From: =?UTF-8?Q?Benedikt_K=C3=B6ppel?= +Date: Fri, 22 Jul 2016 09:41:38 +0200 +Message-ID: +Subject: Re: cdist contribution relicensing +To: Dmitry Bogatov +Content-Type: multipart/alternative; boundary=001a1135177ab4fbf60538349102 +X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] +X-Received-From: 2607:f8b0:4003:c06::22f +X-UIDL: S)T"!() wrote: + +> +> Hello, dear contributors of cdist project! +> +> Recently we discovered licensing issue with your contribution. Namely, +> while most of code is GPLv3+, including some of code written by you, +> manpages (man.txt, now man.rst) are GPLv3 only licensed. +> +> On behalf of cdist releasers (Darko and Nico), I (another cdist +> contributor and cdist Debian maintainer) ask you to permit relicense +> your contribution from GPLv3 to GPLv3+. Without your permission, we +> would be stuck the day when GPLv4 come (hope it will never come, but +> still), or have to reimplement your contribution. +> +> If you agree, please respond with something like +> +> I, #name# <#email#> permit to relicense all my contribution to +> cdist project, source code https://github.com/ungleich/cdist +> to GNU General Public license, version 3 or (at your option) +> any later version, as published by Free Software Foundation. +> +> #day# Jule 2016 year. +> +> If possible, GPG-sign such email. Do not include anything else +> valuable in this email that you do not want to be stored forever in +> public. +> +> Dear contributors, when replying to this email, please do not send +> copy to other contributors -- save their inbox storage. +> +> Thank you in advance for one more contribution. +> +> -- +> Accept: text/plain, text/x-diff +> Accept-Language: eo,en,ru +> X-Web-Site: sinsekvu.github.io +> + +--001a1135177ab4fbf60538349102 +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + +

On Wed, Jul 20, 2016 at 5:09 PM, = +Dmitry Bogatov <KAction@gnu.org> wrote:

+Hello, dear contributors of cdist project!
+
+Recently we discovered licensing issue with your contribution. Namely,
+while most of code is GPLv3+, including some of code written by you,
+manpages (man.txt, now man.rst) are GPLv3 only licensed.
+
+On behalf of cdist releasers (Darko and Nico), I (another cdist
+contributor and cdist Debian maintainer) ask you to permit relicense
+your contribution from GPLv3 to GPLv3+. Without your permission, we
+would be stuck the day when GPLv4 come (hope it will never come, but
+still), or have to reimplement your contribution.
+
+If you agree, please respond with something like
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 I, #name# <#email#> permit to relicense a= +ll my contribution to
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 cdist project, source code https://gith= +ub.com/ungleich/cdist
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 to GNU General Public license, version 3 or (at= + your option)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 any later version, as published by Free Softwar= +e Foundation.
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 #day# Jule 2016 year.
+
+If possible, GPG-sign such email. Do not include anything else
+valuable in this email that you do not want to be stored forever in
+public.
+
+Dear contributors, when replying to this email, please do not send
+copy to other contributors -- save their inbox storage.
+
+Thank you in advance for one more contribution.
+
+--
+Accept: text/plain, text/x-diff
+Accept-Language: eo,en,ru
+X-Web-Site: sinsekvu.github.io
+

+ +--001a1135177ab4fbf60538349102-- + diff --git a/docs/legal/Daniel_Heule.email b/docs/legal/Daniel_Heule.email new file mode 100644 index 00000000..a66e468c --- /dev/null +++ b/docs/legal/Daniel_Heule.email @@ -0,0 +1,97 @@ +From kaction Thu Jul 21 09:20:03 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Thu, 21 Jul 2016 02:15:43 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Thu, 21 Jul 2016 09:20:03 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:60463) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bQ7Go-0005is-V4 + for KAction@gnu.org; Thu, 21 Jul 2016 02:15:43 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bQ7Gk-0006QB-Hy + for KAction@gnu.org; Thu, 21 Jul 2016 02:15:41 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: +X-Spam-Status: No, score=0.8 required=5.0 tests=BAYES_50,HTML_MESSAGE, + RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.2 +Received: from mail3.sfsservices.biz ([194.93.112.48]:32812) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bQ7Gk-0006Pg-Ay + for KAction@gnu.org; Thu, 21 Jul 2016 02:15:38 -0400 +X-Received: from localhost (localhost [127.0.0.1]) + by mail3.sfsservices.biz (Postfix) with ESMTP id 4F7C37E219FD + for ; Thu, 21 Jul 2016 08:15:33 +0200 (CEST) +X-Virus-Scanned: amavisd-new at sfsservices.biz +X-Received: from mail3.sfsservices.biz ([127.0.0.1]) + by localhost (mail3.sfsservices.biz [127.0.0.1]) (amavisd-new, port 10023) + with ESMTP id 42FFY6pT6H_v for ; + Thu, 21 Jul 2016 08:15:33 +0200 (CEST) +X-Received: from chsfsd14.sfs-intra.net (chsfsln0001.sfs-intra.net [INTERNAL-IP]) + by mail3.sfsservices.biz (Postfix) with ESMTP + for ; Thu, 21 Jul 2016 08:15:33 +0200 (CEST) +In-Reply-To: +References: +To: Dmitry Bogatov +MIME-Version: 1.0 +Subject: Antwort: cdist contribution relicensing +X-KeepSent: 3BCE55E5:113E83E4-C1257FF7:002232C0; + type=4; name=$KeepSent +X-Mailer: IBM Notes Release 9.0.1FP3 January 13, 2015 +Message-ID: +From: Daniel Heule +Date: Thu, 21 Jul 2016 08:15:32 +0200 +X-MIMETrack: Serialize by Router on chsfsd14/SFS(Release 9.0.1FP6|April 20, 2016) at + 21.07.2016 08:15:32, + Serialize complete at 21.07.2016 08:15:32 +Content-Type: multipart/alternative; boundary="=_alternative 00226206C1257FF7_=" +X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] +X-Received-From: 194.93.112.48 +X-UIDL: LCD"!0Gb!!dH-"!0ma"! + +Dies ist eine mehrteilige Nachricht im MIME-Format. +--=_alternative 00226206C1257FF7_= +Content-Type: text/plain; charset="ISO-8859-1" +Content-Transfer-Encoding: quoted-printable + +I, Daniel Heule, hda@sfs.biz permit to relicense all my contribution to +cdist project, source code https://github.com/ungleich/cdist +to GNU General Public license, version 3 or (at your option) +any later version, as published by Free Software Foundation. + +21 Jule 2016. + + + +Mit freundlichen Gr=FCssen / Kind regards + +Daniel Heule + +--=_alternative 00226206C1257FF7_= +Content-Type: text/html; charset="ISO-8859-1" +Content-Transfer-Encoding: quoted-printable + +I, Daniel Heule, hda@sfs.biz permit to relicense all +my contribution to
+cdist project, source code
https://github.com/ungleich/cdist
+to GNU General Public license, version 3 or (at your option)
+any later version, as published by Free Software Foundation.
+
+21 Jule 2016.
+
+
+
+
Mit freundlichen Gr=FCssen / Kind re= +gards
+
+
Daniel Heule +
+--=_alternative 00226206C1257FF7_=-- + diff --git a/docs/legal/Jacob_Guffey.email b/docs/legal/Jacob_Guffey.email new file mode 100644 index 00000000..a9892deb --- /dev/null +++ b/docs/legal/Jacob_Guffey.email @@ -0,0 +1,64 @@ +From kaction Sat Jul 23 01:20:04 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Fri, 22 Jul 2016 18:19:30 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Sat, 23 Jul 2016 01:20:04 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:57472) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bQin4-0006js-EH + for KAction@gnu.org; Fri, 22 Jul 2016 18:19:30 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bQin0-00078i-0H + for KAction@gnu.org; Fri, 22 Jul 2016 18:19:29 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: +X-Spam-Status: No, score=-3.2 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD + autolearn=disabled version=3.3.2 +Received: from jhsmtdmz01x.jointheirstm.org ([69.28.94.113]:64009) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bQimz-00078K-Rx + for KAction@gnu.org; Fri, 22 Jul 2016 18:19:25 -0400 +Received: from moshe.jointheirstm.org (c-98-253-78-203.hsd1.in.comcast.net [98.253.78.203]) + by JHSMTDMZ01X.jointheirstm.org (Postfix) with ESMTPSA id 922972AE606 + for ; Fri, 22 Jul 2016 18:19:23 -0400 (EDT) +Subject: Re: cdist contribution relicensing +To: Dmitry Bogatov +References: +From: Jake Guffey +Message-ID: <57929BB9.1080104@Jointheirstm.org> +Date: Fri, 22 Jul 2016 18:18:33 -0400 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 + Thunderbird/38.5.0 +MIME-Version: 1.0 +In-Reply-To: +Content-Type: text/plain; charset=windows-1252 +Content-Transfer-Encoding: 7bit +X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x +X-Received-From: 69.28.94.113 +X-UIDL: B!'#!_Z2!![?h"!'Ij"! + +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +I, Jacob Guffey , permit to relicense +all my contributions to the cdist project, source code +https://github.com/ungleich/cdist to GNU General Public license, +version 3 or (at the maintainer's option) any later version, as +published by Free Software Foundation. + +2016-07-22 + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2 + +iF4EAREIAAYFAleSm7YACgkQT+o/hrTzJc0NQwD/b2hjXG6UCJXnVUANmWnVy+/L +ae+7lZhFL8UklI5cb/0BAOC7jjH8FfKz1lL/Arqw4SM64yy3wiwvJjqJDtmuumWl +=VLlV +-----END PGP SIGNATURE----- + diff --git a/docs/legal/Thomas_Oettli.email b/docs/legal/Thomas_Oettli.email new file mode 100644 index 00000000..eb515a59 --- /dev/null +++ b/docs/legal/Thomas_Oettli.email @@ -0,0 +1,342 @@ +From kaction Tue Aug 2 13:59:41 2016 +Return-path: +Envelope-to: KAction@gnu.org +Delivery-date: Tue, 02 Aug 2016 05:50:23 -0400 +Received: from fencepost.gnu.org [208.118.235.10] + by searing with POP3 (fetchmail-6.3.26) + for (single-drop); Tue, 02 Aug 2016 13:59:41 +0300 (MSK) +Received: from eggs.gnu.org ([2001:4830:134:3::10]:41424) + by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) + (Exim 4.82) + (envelope-from ) + id 1bUWL9-0006S9-Ft + for KAction@gnu.org; Tue, 02 Aug 2016 05:50:23 -0400 +Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) + (envelope-from ) + id 1bUWL1-0007oE-Eo + for KAction@gnu.org; Tue, 02 Aug 2016 05:50:21 -0400 +X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org +X-Spam-Level: +X-Spam-Status: No, score=0.9 required=5.0 tests=BAYES_50,HTML_MESSAGE, + RCVD_IN_DNSWL_NONE,TVD_FW_GRAPHIC_NAME_MID autolearn=disabled version=3.3.2 +Received: from mail2.sfsservices.biz ([194.93.112.42]:43385) + by eggs.gnu.org with esmtp (Exim 4.71) + (envelope-from ) + id 1bUWKe-0007eL-5Z + for KAction@gnu.org; Tue, 02 Aug 2016 05:50:15 -0400 +X-Received: from localhost (localhost [127.0.0.1]) + by mail2.sfsservices.biz (Postfix) with ESMTP id B80B68BEA15B + for ; Tue, 2 Aug 2016 11:49:19 +0200 (CEST) +X-Virus-Scanned: amavisd-new at sfsservices.biz +X-Received: from mail2.sfsservices.biz ([127.0.0.1]) + by localhost (mail2.sfsservices.biz [127.0.0.1]) (amavisd-new, port 10023) + with ESMTP id Kq9SpRTVO-tm for ; + Tue, 2 Aug 2016 11:49:19 +0200 (CEST) +X-Received: from chsfsd15.sfs-intra.net (chsfsln0002.sfs-intra.net [INTERNAL-IP]) + by mail2.sfsservices.biz (Postfix) with ESMTP + for ; Tue, 2 Aug 2016 11:49:19 +0200 (CEST) +In-Reply-To: +References: +Subject: Antwort: cdist contribution relicensing +X-KeepSent: A672E59F:C63BD8B2-C1258003:0035E697; + type=4; name=$KeepSent +To: Dmitry Bogatov +X-Mailer: IBM Notes Release 9.0.1 October 14, 2013 +Message-ID: +From: Thomas Oettli +Date: Tue, 2 Aug 2016 11:49:18 +0200 +X-MIMETrack: Serialize by Router on chsfsd15/SFS(Release 9.0.1FP6|April 20, 2016) at + 02.08.2016 11:49:19 +MIME-Version: 1.0 +Content-type: multipart/related; + Boundary="0__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007" +X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] +X-Received-From: 194.93.112.42 +X-UIDL: Jb%#!^\~!!pT3"!DD="! + +--0__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007 +Content-type: multipart/alternative; + Boundary="1__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007" + +--1__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007 +Content-type: text/plain; charset=UTF-8 +Content-transfer-encoding: quoted-printable + + +I, Thomas Oettli permit to relicense all my contribution= + to +cdist project, source code https://github.com/ungleich/cdist +to GNU General Public license, version 3 or (at your option) +any later version, as published by Free Software Foundation. + + + +Thomas Oettli +Systemengineer SAP & Linux + +SFS services AG, Corporate IT +Rosenbergsaustrasse 8, CH-9435 Heerbrugg +T +41 71 72 75269 F +41 71 72 75237 +thomas.oettli@sfs.biz www.sfs.biz + + + +Denken Sie an die Umwelt bevor Sie drucken. - Please consider your +environment before printing. + + + + +Von: Dmitry Bogatov +An: Andi Br=C3=B6nnimann , Benedikt Koeppel + , Chase Allen James + , Christian G. Warden , + Daniel Heule , Daniel Maher , Dominique Roux , + Evax Software , Giel van Schijndel , Jake Guffey , J= +ake + Guffey , Nico Schottelius + , Ramon Salvad=C3=B3 + , Ricardo Catalinas Jim=C3=A9nez + , Steven Armstrong + , Thomas Oettli +Kopie: Darko Poljak , Nico Schottelius + +Datum: 20.07.2016 17:11 +Betreff: cdist contribution relicensing + + + + +Hello, dear contributors of cdist project! + +Recently we discovered licensing issue with your contribution. Namely, +while most of code is GPLv3+, including some of code written by you, +manpages (man.txt, now man.rst) are GPLv3 only licensed. + +On behalf of cdist releasers (Darko and Nico), I (another cdist +contributor and cdist Debian maintainer) ask you to permit relicense +your contribution from GPLv3 to GPLv3+. Without your permission, we +would be stuck the day when GPLv4 come (hope it will never come, but +still), or have to reimplement your contribution. + +If you agree, please respond with something like + + I, #name# <#email#> permit to relicense all my contribution to + cdist project, source code https://github.com/ungleich/cdist + to GNU General Public license, version 3 or (at your option) + any later version, as published by Free Software Foundation. + + #day# Jule 2016 year. + +If possible, GPG-sign such email. Do not include anything else +valuable in this email that you do not want to be stored forever in +public. + +Dear contributors, when replying to this email, please do not send +copy to other contributors -- save their inbox storage. + +Thank you in advance for one more contribution. + +-- +Accept: text/plain, text/x-diff +Accept-Language: eo,en,ru +X-Web-Site: sinsekvu.github.io +[Anhang "attsga4c.dat" gel=C3=B6scht von Thomas Oettli/otho/SFS]= + +--1__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007 +Content-type: text/html; charset=UTF-8 +Content-Disposition: inline +Content-transfer-encoding: quoted-printable + + +

I, Thomas Oettli <otho@sfs.biz> permit to= + relicense all my contribution to
+cdist project, source code
https://github.com/ungleich/cdist
+to GNU General Public license, version 3 or (at your option)
+any later version, as published by Free Software Foundation.

+
+
+
+Thomas Oettli
+Systemengineer SAP & Linux

+
+SFS services AG, Corporate IT
+Rosenbergsaustrasse 8, CH-9435 Heerbrugg
+T +41 71 72 75269   F +41 71 72 75237  

+
thomas.oettli@sfs.biz      www.sfs.biz
+
+
+
+3D"Denken
+
+
+3D"InactiveDmitry Bogatov ---20.07.2016 17:11:48---Hello, dear contribu= +tors of cdist project! Recently we discovered licensing issue with your= + contribu
+
+Von: Dmitry Bogatov <KAction@gnu.org>= +
+An: Andi Br=C3=B6nnimann <andi-cdist@v-n= +et.ch>, Benedikt Koeppel <code@benediktkoeppel.ch>, Chase Alle= +n James <nx-cdist@nu-ex.com>, Christian G. Warden <cwarden@xer= +us.org>, Daniel Heule <hda@sfs.biz>, Daniel Maher <phrawzty= ++cdist@gmail.com>, Dominique Roux <dominique.roux4@gmail.com>,= + Evax Software <contact@evax.fr>, Giel van Schijndel <giel+cdi= +st@mortis.eu>, Jake Guffey <jake.guffey@eprotex.com>, Jake Guf= +fey <jake.guffey@jointheirstm.org>, Nico Schottelius <nico-cdi= +st@schottelius.org>, Ramon Salvad=C3=B3 <rsalvado@gnuine.com>,= + Ricardo Catalinas Jim=C3=A9nez <jimenezrick@gmail.com>, Steven A= +rmstrong <steven-cdist@armstrong.cc>, Thomas Oettli <otho@sfs.= +biz>
+Kopie: Darko Poljak <darko.poljak@gmail.= +com>, Nico Schottelius <nico.schottelius@ungleich.ch> +Datum: 20.07.2016 17:11
+Betreff: = +cdist contribution relicensing
+



+
+
+
+Hello, dear contributors of cdist project!
+
+Recently we discovered licensing issue with your contribution. Namely,<= +br> +while most of code is GPLv3+, including some of code written by you, +manpages (man.txt, now man.rst) are GPLv3 only licensed.
+
+On behalf of cdist releasers (Darko and Nico), I (another cdist
+contributor and cdist Debian maintainer) ask you to permit relicense +your contribution from GPLv3 to GPLv3+. Without your permission, we
= + +would be stuck the day when GPLv4 come (hope it will never come, but +still), or have to reimplement your contribution.
+
+If you agree, please respond with something like
+
+ I, #name# <#email#> permit to relicense all my contribution to= +
+ cdist project, source code
https://github.com/ungleich/cdist
+ to GNU General Public license, version 3 or (at your option)
+ any later version, as published by Free Software Foundation.
+
+        #day# Jule 2016 year.
+
+If possible, GPG-sign such email. Do not include anything else
+valuable in this email that you do not want to be stored forever in
= + +public.
+
+Dear contributors, when replying to this email, please do not send
+copy to other contributors -- save their inbox storage.
+
+Thank you in advance for one more contribution.
+
+--
+Accept: text/plain, text/x-diff
+Accept-Language: eo,en,ru
+X-Web-Site: sinsekvu.github.io
+[Anhang "attsga4c.dat" gel=C3=B6scht von Thomas Oettli/otho/S= +FS]

+= + + +--1__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007-- + + +--0__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007 +Content-type: image/gif; + name="16993833.gif" +Content-Disposition: inline; filename="16993833.gif" +Content-ID: <1__=4EBB0A90DFA660078f9e8a93df@sfs-intra.net> +Content-transfer-encoding: base64 + +R0lGODlhVgAqAOUAAPA4IP////AwGPAoEPi4sPBIMPAwEPCAcPiYkPA4GPBwYPjAuPCQgPiooOgg +CPBYSOggAPBAKPAoCPBQOPCIePCIgPiYiPjQyPB4aPigkOgYAPBoWOgoCPBgSPBgUPBoUPCYiPjw +8PBYQPCYkPigmPjAsPjIwPjg2Pjo4Pjw6OgoEPAgCPBIOPjY0PjY2Pjg4PBQQPB4YPCAePCQiPio +mPiwqPjo6PAgAPBAMPBwWPCAaPiQiPiwoPjIyPjQ0Pj48CwAAAAAVgAqAEAI/wADCBTogwIMAAgT +KlwIIAKDgRApTChAsaLFixU9uIAIEYUFDxhDVpyQQWABhgAEbJjBoKXLly4RhIC4YADDBB1kHNjJ +s+fOGhBRpnzgsyhPCicGpoAgtClDBy8E1nRKFSGHgSiYVnUKwQYCm1udCjggFaxCAyU5qlWLgENY +sRTWyp1Lt67du3gHOhDwtq/fv2EFqBA4gS9ghQ7KHk6YWOADw4sRehAqoLLlywIMDJAgQ+0CFSgT +WDaQOTNpA6htDpxAGfVo05k5DNiRV+4ByAklKF5ooEHt3xAx4E54e3ECCCY4amAIoQXwDcP9aiAg +8EOCyNizbxVgQeAFrYcFKP8Y6DZyAYgn9i42QAFE9L8rfAeYuh6DQAbv/UogIZQF8IH0nUUDcBKg +NMF/LjiAnW4AmnUYgxesEFkCA6i1AQQDYKbhewnAsBtDG2poAAc/cBTCAxCQFmJl16H0gUAnZACC +BSOMQKMFCOCIwIwIYOBgQgZ8CCQJ/wUQQg0NJKnkkkrywMCPCEWgXUMNMoQWgVMOBEIHD3TpJZcP +dAAmmBuAEJVcFyjAQgEfUFdkABKJJJIIFFygFgEODKDnnnz26eefgAYq6KCE6nkDdSdNqeiiKZEl +kA04cJCfU6RB9N2kTiWggZ0ciaCeX6oZCd5iFQbQA2iRNSaQgthF8AKrrQr/CViQAaAAa2QsWIfS +iiJqEJesCfFq2QARDCRCiwuJJqxlEIwn1IFFBgikfLUVyNB5wCW6kEoMVODtt95SYEFya0mLkAA5 +kIDAuuy2m6ObAr1nAAYZuNtuA85xhN96A6RAE5R9qSRQcYdVOlAByAImwANVRrbCQFJGJoAHA7Xw +qcIVABswxQOZAAGmVAkwwp0MGMWTj7tqLEIMCrTs8sstzzBXCDQcADPMHxiAEra/QccQg+YCYACR +b+YVw3sBeJBiZafx+iywVwKHAYaoVW311fk9wFp2DnAadNS1RbzgBWIvBgEKAxEAJdh56YydBhsF +IECGCdRttwCi2a13Zg5MUOAvRwh8fK4D4/03gNtvieZABEkV7fjjRZtAwOSUV2755SVcrjnmmxOQ +eeecb77AQBcsx+jpkWmQQtmotx4wBsK5LvtbA8inA+uz555Q4QEBADs= + +--0__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007 +Content-type: image/gif; + name="16816884.gif" +Content-Disposition: inline; filename="16816884.gif" +Content-ID: <2__=4EBB0A90DFA660078f9e8a93df@sfs-intra.net> +Content-transfer-encoding: base64 + +R0lGODlhNgEiAOQAAP///wCAAACIAJiIAACImACguOj4+Pj40HDI6PjgmND4+Pj46ACIcLigALjw ++OjIcAC40NC4APjw0NDw+HCIAJigAJjg+LjI0LjI6NDIuOjIuOj40PjwuAAAAAAAAAAAACwAAAAA +NgEiAEAI/wABCBxIsKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzClzQQIDHjx4LGFAYoGBJACdRCgxw +suXKlzBZwhyYkqDLmTNb3qS58mbKmipt9hyq8idPo0GBykx6tGlMpQd3QkWpM2fMq0GT7tQo8YFH +BFzDih1LtqzZs2gRDgDJtq0ABg4SJvBIwCTLpUxxYhWqd2revzyzStVb1KpgwkgT50X6d/Bex34h +G2YceXJgn5cDp93MubPnz6BDP5zL1oLo06hTq15d0avbryT5Hp6N+bFJvo4v57Y8WzZlzb+xKq3d +W/HtzL150xauHOjFtWAFSqjwunrbujbvMmYd1aBz7rJB+/9diFfs970R11r3CHchaQHYNfsuL/Mn +/fI0a94Fnp/y/p7byfcfgFv1x59yVAUXXIIH0kdVdv5tN+BRCurWWH6ATRQBBOB16OGHIKJ1gHoh +jUReeA2d55B+aano3XFcFeiiRSxKNCNCN6YmwQQAjAgSAQoAsGNCU2kHGV5GGobjUxMSqCRvSaKY +m0slVUkgcZNp95JksWnVpHHLQdjfUgGKSOJ6QIao5ppsonbmRwVs8OZ6P7Zp5514hjXnW3E15GOd +4Ul1n36DRkWoUYXmZCWATtGGZGbDIToYlYxuKSlRlRalE4uJ/jfgok1q2hSVmzJ1X1YD7VldmgiR +Fh9hGSb/hx6Mzb14IaqI3QqmfJYRB+aUuc66q22y+lbrYsjhCoCqIjnk2kev5mmetNQqG2Oo1War +7bbc/ckqt+CGK65BC1zgrQIZmEiklhHlSNKnZhXYHYoYyRgvvA+5S2uIHLXVbJfAPfookxTa+hh+ +mVb5XX2KOlfkgxArKLCDneqGaKANG2pqcRJfClq/1f07b7KSVYgYvmWSDKOv+wJbGKjIVbYcl3YN +HOCvyW7ZIK+dvQdSewDPGqa8N+MG67E7W9uXkpTCfJzMDutqMLJLEpshlk9uBrJ1HOLIroHH4qvs +1/Yt7PTYnoLtnYNMC2gzp4cGOnDNERpKJoT2NTi3vGRp1hAkQa5FN9ABGIxr+OHVBo744oyntta/ +W9P5WrSNV245Rup1rdCfaNLKN5v6Xj7y0ft2FvpBqrol+EHvRVsjzbA/nSWxPh1pLM4Q663z7nc/ +5XvEs1/Nsq67AW9877UL51zqr61eEAcUwFe6l0h+Wv2XKzNts8W9CxU72mlfNbzUWYZ/NffDl40f +7sZ9TxDzbIl8UAR0Tc9l98WnrzL5sRaHINK44x/7cna8mO0PV8jbn/5yl6r1yK9VgBLdiSR4mtNR +ZHk/65ND6HcdCnrwgyAMoQhDExAAOw== + +--0__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007 +Content-type: image/gif; + name="graycol.gif" +Content-Disposition: inline; filename="graycol.gif" +Content-ID: <3__=4EBB0A90DFA660078f9e8a93df@sfs-intra.net> +Content-transfer-encoding: base64 + +R0lGODlhEAAQAKECAMzMzAAAAP///wAAACH5BAEAAAIALAAAAAAQABAAAAIXlI+py+0PopwxUbpu +ZRfKZ2zgSJbmSRYAIf4fT3B0aW1pemVkIGJ5IFVsZWFkIFNtYXJ0U2F2ZXIhAAA7 + +--0__=4EBB0A90DFA660078f9e8a93df938690918c4EBB0A90DFA66007-- + + From 7707d3dc7238329a40714c1e0501add8e74c61d8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 13 Aug 2016 10:25:13 +0200 Subject: [PATCH 0270/1332] Update changelog for GPLv3+ re-licensing. --- docs/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 5dd49ef5..f5b59eed 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,8 +1,8 @@ Changelog --------- next: - * New type __filesystem: manage filesystems on devices ( Daniel Heule ) - + * Documentation: Re-license types' man pages to GPLV3+ (Dmitry Bogatov, Darko Poljak) + * New type __filesystem: manage filesystems on devices (Daniel Heule) * New type: __locale_system (Steven Armstrong, Carlos Ortigoza, Nico Schottelius) * New type: __sysctl (Steven Armstrong) From a9001fa9cef1116448a41653ef2fd0c936eb7661 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 14 Aug 2016 20:10:41 +0200 Subject: [PATCH 0271/1332] Additional note for SHELL: should be POSIX compatible shell. --- scripts/cdist | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/cdist b/scripts/cdist index 953cad78..96bd0462 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -112,7 +112,8 @@ def commandline(): 'shell', parents=[parser['loglevel']]) parser['shell'].add_argument( '-s', '--shell', - help='Select shell to use, defaults to current shell') + help=('Select shell to use, defaults to current shell. Used shell' + ' should be POSIX compatible shell.')) parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) for p in parser: From 0691f1da32964781d7c79dc96168d7520e80c8fb Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 14 Aug 2016 20:11:45 +0200 Subject: [PATCH 0272/1332] Add missing, fix existing in cdist man page. --- docs/src/man1/cdist.rst | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 5a4873f7..c6f08110 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -15,7 +15,10 @@ SYNOPSIS cdist banner [-h] [-d] [-v] - cdist config [-h] [-d] [-V] [-c CONF_DIR] [-f HOSTFILE] [-i MANIFEST] [-p] [-s] [host [host ...]] + cdist config [-h] [-d] [-v] [-c CONF_DIR] [-f HOSTFILE] [-i MANIFEST] + [-n] [-o OUT_PATH] [-p] [-s] [--remote-copy REMOTE_COPY] + [--remote-exec REMOTE_EXEC] + [host [host ...]] cdist shell [-h] [-d] [-v] [-s SHELL] @@ -32,14 +35,14 @@ GENERAL ------- All commands accept the following options: +.. option:: -h, --help + + Show the help screen + .. option:: -d, --debug Set log level to debug -.. option:: -h, --help - - Show the help screen - .. option:: -v, --verbose Set log level to info, be more verbose @@ -80,13 +83,21 @@ Configure one or more hosts. Path to a cdist manifest or - to read from stdin +.. option:: -n, --dry-run + + Do not execute code + +.. option:: -o OUT_PATH, --out-dir OUT_PATH + + Directory to save cdist output in + .. option:: -p, --parallel Operate on multiple hosts in parallel .. option:: -s, --sequential - Operate on multiple hosts sequentially + Operate on multiple hosts sequentially (default) .. option:: --remote-copy REMOTE_COPY @@ -103,7 +114,7 @@ to the types as commands. It can be thought as an "interactive manifest" environment. See below for example usage. Its primary use is for debugging type parameters. -.. option:: -s/--shell +.. option:: -s SHELL, --shell SHELL Select shell to use, defaults to current shell. Used shell should be POSIX compatible shell. From 51ffc0f0377278cb455ee037f8e8cc21d218f328 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 14 Aug 2016 21:30:09 +0200 Subject: [PATCH 0273/1332] log.info -> log.debug for debug messages --- cdist/core/explorer.py | 8 ++++---- cdist/exec/remote.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index efffb6ed..17d6f46e 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -117,19 +117,19 @@ class Explorer(object): self.jobs)) self.log.debug("Multiprocessing start method is {}".format( multiprocessing.get_start_method())) - self.log.info(("Starting multiprocessing Pool for global " + self.log.debug(("Starting multiprocessing Pool for global " "explorers run")) with multiprocessing.Pool(self.jobs) as pool: - self.log.info("Starting async for global explorer run") + self.log.debug("Starting async for global explorer run") results = [ pool.apply_async(self._run_global_explorer, (e, out_path,)) for e in self.list_global_explorer_names() ] - self.log.info("Waiting async results for global explorer runs") + self.log.debug("Waiting async results for global explorer runs") for r in results: r.get() # self._run_global_explorer returns None - self.log.info(("Multiprocessing run for global explorers " + self.log.debug(("Multiprocessing run for global explorers " "finished")) # logger is not pickable, so remove it when we pickle diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 389c0da1..72dc5840 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -136,10 +136,10 @@ class Remote(object): jobs)) self.log.debug("Multiprocessing start method is {}".format( multiprocessing.get_start_method())) - self.log.info(("Starting multiprocessing Pool for parallel " + self.log.debug(("Starting multiprocessing Pool for parallel " "remote transfer")) with multiprocessing.Pool(jobs) as pool: - self.log.info("Starting async for parallel transfer") + self.log.debug("Starting async for parallel transfer") commands = [] for f in glob.glob1(source, '*'): command = self._copy.split() @@ -152,10 +152,10 @@ class Remote(object): for cmd in commands ] - self.log.info("Waiting async results for parallel transfer") + self.log.debug("Waiting async results for parallel transfer") for r in results: r.get() # self._run_command returns None - self.log.info(("Multiprocessing for parallel transfer " + self.log.debug(("Multiprocessing for parallel transfer " "finished")) else: raise cdist.Error("Source {} is not a directory".format(source)) From d96be90f26647c394707c2e17aea3057977c513a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 14 Aug 2016 22:09:36 +0200 Subject: [PATCH 0274/1332] Fix self.target_host --- cdist/emulator.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 52dd6828..2c5e567b 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -64,9 +64,11 @@ class Emulator(object): try: self.global_path = self.env['__global'] - self.target_host = self.env['__target_host'] - self.target_hostname = self.env['__target_hostname'] - self.target_fqdn = self.env['__target_fqdn'] + self.target_host = ( + self.env['__target_host'], + self.env['__target_hostname'], + self.env['__target_fqdn'] + ) # Internal variables self.object_source = self.env['__cdist_manifest'] From 15d6524efde25f89a217539ff8b2c3469b346cf0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 14 Aug 2016 22:09:51 +0200 Subject: [PATCH 0275/1332] Fix cdist shell. --- cdist/shell.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cdist/shell.py b/cdist/shell.py index ffbc310a..9378efc3 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -22,6 +22,7 @@ import logging import os import subprocess +import tempfile # initialise cdist import cdist.exec.local @@ -44,8 +45,14 @@ class Shell(object): "cdist-shell-no-target-host", ) + host_dir_name = cdist.str_hash(self.target_host[0]) + base_root_path = tempfile.mkdtemp() + host_base_path = os.path.join(base_root_path, host_dir_name) + self.local = cdist.exec.local.Local( - target_host=self.target_host) + target_host=self.target_host, + base_root_path=host_base_path, + host_dir_name=host_dir_name) def _init_shell(self): """Select shell to execute, if not specified by user""" From 1c07b63f1d13bd7bce508eddcac184e63a8be85e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 15 Aug 2016 14:20:35 +0200 Subject: [PATCH 0276/1332] Add -b/--enable-beta option for enabling beta functionalities. --- cdist/config.py | 20 +++++++++++++++++++- docs/changelog | 3 ++- docs/src/man1/cdist.rst | 9 +++++++-- scripts/cdist | 9 +++++++-- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 6f3fde9b..ad256b12 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -71,6 +71,8 @@ def inspect_ssh_mux_opts(): class Config(object): """Cdist main class to hold arbitrary data""" + BETA_ARGS = ['jobs'] + def __init__(self, local, remote, dry_run=False, jobs=None): self.local = local @@ -109,6 +111,19 @@ class Config(object): for host in source: yield host + @classmethod + def _check_beta(cls, args_dict): + if 'beta' not in args_dict: + args_dict['beta'] = False + # Check only if beta is not enabled: if beta option is specified then + # raise error. + if not args_dict['beta']: + err_msg = ("\'{}\' is beta, but beta is not enabled. If you want " + "to use it please enable beta functionalities.") + for arg in cls.BETA_ARGS: + if arg in args_dict: + raise cdist.Error(err_msg.format(arg)) + @classmethod def commandline(cls, args): """Configure remote system""" @@ -120,6 +135,10 @@ class Config(object): if args.manifest == '-' and args.hostfile == '-': raise cdist.Error(("Cannot read both, manifest and host file, " "from stdin")) + + args_dict = vars(args) + cls._check_beta(args_dict) + # if no host source is specified then read hosts from stdin if not (args.hostfile or args.host): args.hostfile = '-' @@ -148,7 +167,6 @@ class Config(object): args.remote_exec_pattern = None args.remote_copy_pattern = None - args_dict = vars(args) # if remote-exec and/or remote-copy args are None then user # didn't specify command line options nor env vars: # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC diff --git a/docs/changelog b/docs/changelog index 21fee305..d0d2c157 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,8 @@ Changelog --------- next: - * Core: Add -j, --jobs option for parallel execution and add parallel support for global explorers (Darko Poljak) + * Core: Add -b, --enable-beta option for enabling beta functionalities (Darko Poljak) + * Core: Add -j, --jobs option for parallel execution and add parallel support for global explorers (currently in beta) (Darko Poljak) * Core: Add derived env vars for target hostname and fqdn (Darko Poljak) * New type: __keyboard: Set keyboard layout (Carlos Ortigoza) * Documentation: Re-license types' man pages to GPLV3+ (Dmitry Bogatov, Darko Poljak) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 7cac0afe..1eb57c12 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -17,7 +17,7 @@ SYNOPSIS cdist config [-h] [-d] [-v] [-c CONF_DIR] [-f HOSTFILE] [-i MANIFEST] [-n] [-o OUT_PATH] [-p] [-s] [--remote-copy REMOTE_COPY] - [--remote-exec REMOTE_EXEC] [-j [JOBS]] + [--remote-exec REMOTE_EXEC] [-j [JOBS]] [-b] [host [host ...]] cdist shell [-h] [-d] [-v] [-s SHELL] @@ -110,7 +110,12 @@ Configure one or more hosts. .. option:: -j [JOBS], --jobs [JOBS] Specify the maximum number of parallel jobs; currently only - global explorers are supported + global explorers are supported (currently in beta) + +.. option:: -b, --enable-beta + + Enable beta functionalities. Beta functionalities include the + following options: -j/--jobs. SHELL ----- diff --git a/scripts/cdist b/scripts/cdist index 557bf2b2..6c60ccb3 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -122,10 +122,15 @@ def commandline(): default=os.environ.get('CDIST_REMOTE_EXEC')) parser['config'].add_argument( '-j', '--jobs', nargs='?', type=check_positive_int, - help=('Specify the maximum number of parallel jobs; currently ' - 'only global explorers are supported'), + help=('Specify the maximum number of parallel jobs, currently ' + 'only global explorers are supported (currently in beta'), action='store', dest='jobs', const=multiprocessing.cpu_count()) + parser['config'].add_argument( + '-b', '--enable-beta', + help=('Enable beta functionalities. Beta functionalities ' + 'include the following options: -j/--jobs.'), + action='store_true', dest='beta', default=False) parser['config'].set_defaults(func=cdist.config.Config.commandline) # Shell From fdf6a6570c4342807525bf3b7401d491034e31f6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 15 Aug 2016 16:01:39 +0200 Subject: [PATCH 0277/1332] Check for beta in scripts/cdist. --- cdist/__init__.py | 14 ++++++++++++++ cdist/config.py | 19 +------------------ scripts/cdist | 21 +++++++++++++++++++++ 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index 74db1a13..d06ae28b 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -56,6 +56,20 @@ class UnresolvableRequirementsError(cdist.Error): pass +class CdistBetaRequired(cdist.Error): + """Beta functionality is used but beta is not enabled""" + + def __init__(self, command, arg): + self.command = command + self.arg = arg + + def __str__(self): + err_msg = ("\'{}\' argument of \'{}\' command is beta, but beta is " + "not enabled. If you want to use it please enable beta " + "functionalities.") + return err_msg.format(self.arg, self.command) + + class CdistObjectError(Error): """Something went wrong with an object""" diff --git a/cdist/config.py b/cdist/config.py index ad256b12..9d4c5c10 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -71,8 +71,6 @@ def inspect_ssh_mux_opts(): class Config(object): """Cdist main class to hold arbitrary data""" - BETA_ARGS = ['jobs'] - def __init__(self, local, remote, dry_run=False, jobs=None): self.local = local @@ -111,19 +109,6 @@ class Config(object): for host in source: yield host - @classmethod - def _check_beta(cls, args_dict): - if 'beta' not in args_dict: - args_dict['beta'] = False - # Check only if beta is not enabled: if beta option is specified then - # raise error. - if not args_dict['beta']: - err_msg = ("\'{}\' is beta, but beta is not enabled. If you want " - "to use it please enable beta functionalities.") - for arg in cls.BETA_ARGS: - if arg in args_dict: - raise cdist.Error(err_msg.format(arg)) - @classmethod def commandline(cls, args): """Configure remote system""" @@ -136,9 +121,6 @@ class Config(object): raise cdist.Error(("Cannot read both, manifest and host file, " "from stdin")) - args_dict = vars(args) - cls._check_beta(args_dict) - # if no host source is specified then read hosts from stdin if not (args.hostfile or args.host): args.hostfile = '-' @@ -167,6 +149,7 @@ class Config(object): args.remote_exec_pattern = None args.remote_copy_pattern = None + args_dict = vars(args) # if remote-exec and/or remote-copy args are None then user # didn't specify command line options nor env vars: # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC diff --git a/scripts/cdist b/scripts/cdist index 6c60ccb3..a2f5fbfb 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -22,6 +22,12 @@ # +# list of beta arguments for sub-commands +BETA_ARGS = { + 'config': ['jobs', ], +} + + def check_positive_int(value): import argparse @@ -36,6 +42,20 @@ def check_positive_int(value): return val +def check_beta(args_dict): + if 'beta' not in args_dict: + args_dict['beta'] = False + # Check only if beta is not enabled: if beta option is specified then + # raise error. + if not args_dict['beta']: + err_msg = ("\'{}\' is beta, but beta is not enabled. If you want " + "to use it please enable beta functionalities.") + cmd = args_dict['command'] + for arg in BETA_ARGS[cmd]: + if arg in args_dict: + raise cdist.CdistBetaRequired(cmd, arg) + + def commandline(): """Parse command line""" import argparse @@ -172,6 +192,7 @@ def commandline(): parser['main'].print_help() sys.exit(0) + check_beta(vars(args)) args.func(args) if __name__ == "__main__": From 7cc7c18e77dfeafb018ba12b3969d3be4fd47c5a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 15 Aug 2016 16:37:11 +0200 Subject: [PATCH 0278/1332] Add hint for command line flag for enable-beta. --- cdist/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index d06ae28b..9068ae69 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -66,7 +66,8 @@ class CdistBetaRequired(cdist.Error): def __str__(self): err_msg = ("\'{}\' argument of \'{}\' command is beta, but beta is " "not enabled. If you want to use it please enable beta " - "functionalities.") + "functionalities by using the -b/--enable-beta command " + "line flag.") return err_msg.format(self.arg, self.command) From adac0113c5690599ce2f247d7a6eceba103b22a3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 15 Aug 2016 16:37:38 +0200 Subject: [PATCH 0279/1332] Order options lexicographicaly. --- docs/src/man1/cdist.rst | 26 +++++++++++++------------- scripts/cdist | 24 +++++++++++------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 1eb57c12..a00a3ec0 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -15,9 +15,9 @@ SYNOPSIS cdist banner [-h] [-d] [-v] - cdist config [-h] [-d] [-v] [-c CONF_DIR] [-f HOSTFILE] [-i MANIFEST] - [-n] [-o OUT_PATH] [-p] [-s] [--remote-copy REMOTE_COPY] - [--remote-exec REMOTE_EXEC] [-j [JOBS]] [-b] + cdist config [-h] [-d] [-v] [-b] [-c CONF_DIR] [-f HOSTFILE] + [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-p] [-s] + [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [host [host ...]] cdist shell [-h] [-d] [-v] [-s SHELL] @@ -62,6 +62,11 @@ CONFIG ------ Configure one or more hosts. +.. option:: -b, --enable-beta + + Enable beta functionalities. Beta functionalities include the + following options: -j/--jobs. + .. option:: -c CONF_DIR, --conf-dir CONF_DIR Add a configuration directory. Can be specified multiple times. @@ -83,6 +88,11 @@ Configure one or more hosts. Path to a cdist manifest or - to read from stdin +.. option:: -j [JOBS], --jobs [JOBS] + + Specify the maximum number of parallel jobs; currently only + global explorers are supported (currently in beta) + .. option:: -n, --dry-run Do not execute code @@ -107,16 +117,6 @@ Configure one or more hosts. Command to use for remote execution (should behave like ssh) -.. option:: -j [JOBS], --jobs [JOBS] - - Specify the maximum number of parallel jobs; currently only - global explorers are supported (currently in beta) - -.. option:: -b, --enable-beta - - Enable beta functionalities. Beta functionalities include the - following options: -j/--jobs. - SHELL ----- This command allows you to spawn a shell that enables access diff --git a/scripts/cdist b/scripts/cdist index a2f5fbfb..d02f0a5f 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -48,8 +48,6 @@ def check_beta(args_dict): # Check only if beta is not enabled: if beta option is specified then # raise error. if not args_dict['beta']: - err_msg = ("\'{}\' is beta, but beta is not enabled. If you want " - "to use it please enable beta functionalities.") cmd = args_dict['command'] for arg in BETA_ARGS[cmd]: if arg in args_dict: @@ -97,6 +95,11 @@ def commandline(): 'config', parents=[parser['loglevel']]) parser['config'].add_argument( 'host', nargs='*', help='host(s) to operate on') + parser['config'].add_argument( + '-b', '--enable-beta', + help=('Enable beta functionalities. Beta functionalities ' + 'include the following options: -j/--jobs.'), + action='store_true', dest='beta', default=False) parser['config'].add_argument( '-c', '--conf-dir', help=('Add configuration directory (can be repeated, ' @@ -112,6 +115,12 @@ def commandline(): '-i', '--initial-manifest', help='Path to a cdist manifest or \'-\' to read from stdin.', dest='manifest', required=False) + parser['config'].add_argument( + '-j', '--jobs', nargs='?', type=check_positive_int, + help=('Specify the maximum number of parallel jobs, currently ' + 'only global explorers are supported (currently in beta'), + action='store', dest='jobs', + const=multiprocessing.cpu_count()) parser['config'].add_argument( '-n', '--dry-run', help='Do not execute code', action='store_true') @@ -140,17 +149,6 @@ def commandline(): '(should behave like ssh)'), action='store', dest='remote_exec', default=os.environ.get('CDIST_REMOTE_EXEC')) - parser['config'].add_argument( - '-j', '--jobs', nargs='?', type=check_positive_int, - help=('Specify the maximum number of parallel jobs, currently ' - 'only global explorers are supported (currently in beta'), - action='store', dest='jobs', - const=multiprocessing.cpu_count()) - parser['config'].add_argument( - '-b', '--enable-beta', - help=('Enable beta functionalities. Beta functionalities ' - 'include the following options: -j/--jobs.'), - action='store_true', dest='beta', default=False) parser['config'].set_defaults(func=cdist.config.Config.commandline) # Shell From c5e6ed041c41799e27637a4c8f57697b9b0be3f9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 15 Aug 2016 17:47:19 +0200 Subject: [PATCH 0280/1332] Update bash ans zsh completions with jobs and enable-beta opts. --- completions/bash/cdist-completion.bash | 8 ++++---- completions/zsh/_cdist | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/completions/bash/cdist-completion.bash b/completions/bash/cdist-completion.bash index 3d396bb4..c756fca8 100644 --- a/completions/bash/cdist-completion.bash +++ b/completions/bash/cdist-completion.bash @@ -36,10 +36,10 @@ _cdist() return 0 ;; config) - opts="-h --help -d --debug -v --verbose \ - -c --conf-dir -f --file -i --initial-manifest -n --dry-run \ - -o --out-dir -p --parallel -s --sequential --remote-copy \ - --remote-exec" + opts="-h --help -d --debug -v --verbose -b --enable-beta \ + -c --conf-dir -f --file -i --initial-manifest -j --jobs \ + -n --dry-run -o --out-dir -p --parallel -s --sequential \ + --remote-copy --remote-exec" COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 ;; diff --git a/completions/zsh/_cdist b/completions/zsh/_cdist index 2bf324a6..18fda0f0 100644 --- a/completions/zsh/_cdist +++ b/completions/zsh/_cdist @@ -36,7 +36,7 @@ _cdist() esac ;; config) - opts=(-h --help -d --debug -v --verbose -c --conf-dir -f --file -i --initial-manifest -n --dry-run -o --out-dir -p --parallel -s --sequential --remote-copy --remote-exec) + opts=(-h --help -d --debug -v --verbose -b --enable-beta -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -s --sequential --remote-copy --remote-exec) compadd "$@" -- $opts ;; *) From 5f825d1da9c1dcc3fa50f4df1ef5a7860453e3e5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 15 Aug 2016 18:04:57 +0200 Subject: [PATCH 0281/1332] Fix check_beta error if cmd is not in beta args dict. --- scripts/cdist | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index d02f0a5f..5f8fff9f 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -49,9 +49,10 @@ def check_beta(args_dict): # raise error. if not args_dict['beta']: cmd = args_dict['command'] - for arg in BETA_ARGS[cmd]: - if arg in args_dict: - raise cdist.CdistBetaRequired(cmd, arg) + if cmd in BETA_ARGS: + for arg in BETA_ARGS[cmd]: + if arg in args_dict: + raise cdist.CdistBetaRequired(cmd, arg) def commandline(): From 6ec30f509beefcc064c078d77bff1221ca90a944 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 17 Aug 2016 07:39:47 +0200 Subject: [PATCH 0282/1332] Fix default remote copy/exec flags in docs. --- docs/src/cdist-remote-exec-copy.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/cdist-remote-exec-copy.rst b/docs/src/cdist-remote-exec-copy.rst index 10a370c7..882f0bc2 100644 --- a/docs/src/cdist-remote-exec-copy.rst +++ b/docs/src/cdist-remote-exec-copy.rst @@ -9,8 +9,8 @@ Cdist interacts with the target host in two ways: By default this is accomplished with ssh and scp respectively. The default implementations used by cdist are:: - __remote_exec: ssh -o User=root -q - __remote_copy: scp -o User=root -q + __remote_exec: ssh -o User=root + __remote_copy: scp -o User=root The user can override these defaults by providing custom implementations and passing them to cdist with the --remote-exec and/or --remote-copy arguments. From 640b7f9613b058b99450d6c2331f9fb24ab1b10d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 17 Aug 2016 08:07:57 +0200 Subject: [PATCH 0283/1332] Add example for --jobs in cdist man page. --- docs/src/man1/cdist.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index a00a3ec0..89a2117e 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -158,6 +158,10 @@ EXAMPLES # Configure hosts read from file loadbalancers % cdist config -f loadbalancers + # Configure hosts read from file web.hosts using 16 parallel jobs + # (beta functionality) + % cdist config -b -j 16 -f web.hosts + # Display banner cdist banner From 80304d33407d27e0fd3f7ef36b95bbb7b352bbce Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 17 Aug 2016 19:32:16 +0200 Subject: [PATCH 0284/1332] Add 'Parallelization' chapter to docs. --- docs/changelog | 1 + docs/src/cdist-parallelization.rst | 73 ++++++++++++++++++++++++++++++ docs/src/index.rst | 1 + 3 files changed, 75 insertions(+) create mode 100644 docs/src/cdist-parallelization.rst diff --git a/docs/changelog b/docs/changelog index d0d2c157..db86de45 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,7 @@ Changelog --------- next: + * Documentation: Add Parallelization chapter (Darko Poljak) * Core: Add -b, --enable-beta option for enabling beta functionalities (Darko Poljak) * Core: Add -j, --jobs option for parallel execution and add parallel support for global explorers (currently in beta) (Darko Poljak) * Core: Add derived env vars for target hostname and fqdn (Darko Poljak) diff --git a/docs/src/cdist-parallelization.rst b/docs/src/cdist-parallelization.rst new file mode 100644 index 00000000..ce9f5bca --- /dev/null +++ b/docs/src/cdist-parallelization.rst @@ -0,0 +1,73 @@ +Parallelization +=============== + +Description +----------- +cdist has two modes of parallel operation. + +One of them is to operate on each host in separate process. This is enabled +with :strong:`-p/--parallel` option. + +The other way is to operate in parallel within one host where you specify +the number of jobs. This is enabled with :strong:`-j/--jobs` option where you +can specify the number of parallel jobs. By default, +:strong:`multiprocessing.cpu_count()` is used. For this mode only global +explorers are currently supported and this option is still in :strong:`beta`. + +You can, of course, use those two options together. This means that each host +will be processed by its own process. Within each process cdist will operate +using specified number of parallel jobs. + +For more info on those options see :strong:`cdist`\ (1). + + +Examples +-------- + +.. code-block:: sh + + # Configure hosts read from file hosts.file in parallel + $ cdist config -p -f hosts.file + + # Configure hosts read from file hosts.file sequentially but using default + # number of parallel jobs + $ cdist config -b -j -f hosts.file + + # Configure hosts read from file hosts.file in parallel using 16 + # parallel jobs + $ cdist config -b -j 16 -p -f hosts.file + + +Caveats +------- +When operating in parallel, either by operating in parallel for each host +(-p/--parallel) or by parallel jobs within a host (-j/--jobs), and depending +on target SSH server and its configuration you may encounter connection drops. +This is controlled with sshd :strong:MaxStartups configuration options. +You may also encounter session open refusal. This happens with ssh multiplexing +when you reach maximum number of open sessions permitted per network +connection. In this case ssh will disable multiplexing. +This limit is controlled with sshd :strong:MaxSessions configuration +options. For more details refer to :strong:`sshd_config`\ (5). + +For example, if you reach :strong:`MaxSessions` sessions you may get the +following output: + +.. code-block:: sh + + $ cdist config -b -j 11 -v 78.47.116.244 + INFO: cdist: version 4.2.2-55-g640b7f9 + INFO: 78.47.116.244: Running global explorers + INFO: 78.47.116.244: Remote transfer in 11 parallel jobs + channel 22: open failed: administratively prohibited: open failed + mux_client_request_session: session request failed: Session open refused by peer + ControlSocket /tmp/tmpuah6fw_t/d886d4b7e4425a102a54bfaff4d2288b/ssh-control-path already exists, disabling multiplexing + INFO: 78.47.116.244: Running global explorers in 11 parallel jobs + channel 22: open failed: administratively prohibited: open failed + mux_client_request_session: session request failed: Session open refused by peer + ControlSocket /tmp/tmpuah6fw_t/d886d4b7e4425a102a54bfaff4d2288b/ssh-control-path already exists, disabling multiplexing + INFO: 78.47.116.244: Running initial manifest /tmp/tmpuah6fw_t/d886d4b7e4425a102a54bfaff4d2288b/data/conf/manifest/init + INFO: 78.47.116.244: Running manifest and explorers for __file/root/host.file + INFO: 78.47.116.244: Generating code for __file/root/host.file + INFO: 78.47.116.244: Finished successful run in 18.655028820037842 seconds + INFO: cdist: Total processing time for 1 host(s): 19.159148693084717 diff --git a/docs/src/index.rst b/docs/src/index.rst index a34231f8..b33b707d 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -23,6 +23,7 @@ Contents: cdist-types cdist-explorer cdist-messaging + cdist-parallelization cdist-reference cdist-best-practice cdist-stages From cd62853019533538b13c8312205dd10ca01e13bc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 17 Aug 2016 19:32:43 +0200 Subject: [PATCH 0285/1332] Add CAVEATS section to cdist man page. --- docs/src/man1/cdist.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 89a2117e..47fe195c 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -220,6 +220,18 @@ AUTHORS ------- Nico Schottelius +CAVEATS +------- +When operating in parallel, either by operating in parallel for each host +(-p/--parallel) or by parallel jobs within a host (-j/--jobs), and depending +on target SSH server and its configuration you may encounter connection drops. +This is controlled with sshd :strong:`MaxStartups` configuration options. +You may also encounter session open refusal. This happens with ssh multiplexing +when you reach maximum number of open sessions permitted per network +connection. In this case ssh will disable multiplexing. +This limit is controlled with sshd :strong:`MaxSessions` configuration +options. For more details refer to :strong:`sshd_config`\ (5). + COPYING ------- Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is From 962839eb69ca5aa0b783bc421341479c807ba2c0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 17 Aug 2016 20:23:22 +0200 Subject: [PATCH 0286/1332] Fix beta check. --- scripts/cdist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/cdist b/scripts/cdist index 5f8fff9f..91dec2c9 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -51,7 +51,7 @@ def check_beta(args_dict): cmd = args_dict['command'] if cmd in BETA_ARGS: for arg in BETA_ARGS[cmd]: - if arg in args_dict: + if arg in args_dict and args_dict[arg]: raise cdist.CdistBetaRequired(cmd, arg) From 2fb551131e90f3d62051f490cc187c99ec767ba7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 17 Aug 2016 20:27:51 +0200 Subject: [PATCH 0287/1332] Fix error when non-existing host is used. --- cdist/config.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 9d4c5c10..a873089d 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -244,16 +244,16 @@ class Config(object): # (hostname, aliaslist, ipaddrlist) host_name = socket.gethostbyaddr(ip_addr)[0] except socket.gaierror as e: - log.error("{}: {}".format(e[0], e[1])) + log.warn("{}".format(e)) # in case of error provide empty value - host_name = None + host_name = '' try: host_fqdn = socket.getfqdn(host) except socket.herror as e: - log.error("{}: {}".format(e[0], e[1])) + log.warn("{}: {}".format(e[0], e[1])) # in case of error provide empty value - host_fqdn = None + host_fqdn = '' target_host = (host, host_name, host_fqdn) local = cdist.exec.local.Local( From 680806ce76ba39547f0f593f355b16b3aa704ae6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 17 Aug 2016 20:46:56 +0200 Subject: [PATCH 0288/1332] Fix getting host_name and host_fqdn. --- cdist/config.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index a873089d..31b41781 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -243,15 +243,23 @@ class Config(object): # gethostbyaddr returns triple # (hostname, aliaslist, ipaddrlist) host_name = socket.gethostbyaddr(ip_addr)[0] + log.debug("derived host_name for host \"{}\": {}".format( + host, host_name)) except socket.gaierror as e: - log.warn("{}".format(e)) + log.warn("host_name: {}".format(e)) + # in case of error provide empty value + host_name = '' + except socket.herror as e: + log.warn("host_name: {}".format(e)) # in case of error provide empty value host_name = '' try: host_fqdn = socket.getfqdn(host) + log.debug("derived host_fqdn for host \"{}\": {}".format( + host, host_fqdn)) except socket.herror as e: - log.warn("{}: {}".format(e[0], e[1])) + log.warn("host_fqdn: {}".format(e)) # in case of error provide empty value host_fqdn = '' target_host = (host, host_name, host_fqdn) From 52a2315cd160bf1b9bc597cccaccbca469fcbce8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 18 Aug 2016 10:40:39 +0200 Subject: [PATCH 0289/1332] Turn off sphinx html SmartyPants. --- docs/src/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/conf.py b/docs/src/conf.py index 463bcedd..a63a14ff 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -164,6 +164,7 @@ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True +html_use_smartypants = False # Custom sidebar templates, maps document names to template names. # html_sidebars = {} From f40e6659f7869221db22d1ab58623c48158b1c14 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 18 Aug 2016 10:41:58 +0200 Subject: [PATCH 0290/1332] Make man pages for new types to be by convention. Fix spellings. --- cdist/conf/type/__filesystem/man.rst | 33 +++++++++++++------------ cdist/conf/type/__locale_system/man.rst | 12 ++++----- cdist/conf/type/__sysctl/man.rst | 2 +- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/cdist/conf/type/__filesystem/man.rst b/cdist/conf/type/__filesystem/man.rst index c69cc839..d88e27c1 100644 --- a/cdist/conf/type/__filesystem/man.rst +++ b/cdist/conf/type/__filesystem/man.rst @@ -10,17 +10,17 @@ DESCRIPTION ----------- This cdist type allows you to create filesystems on devices. -If the device is mounted on target, it refuses to do someting. +If the device is mounted on target, it refuses to do anything. -If the device has a filesystem other as the specified and/or - the label is not correct, it only make a new filesystem - if you specified --force option +If the device has a filesystem other then the specified and/or +the label is not correct, it only makes a new filesystem +if you have specified --force option. REQUIRED PARAMETERS ------------------- fstype - Filesystem type, for example 'ext3', 'btrfs' or 'xfs' + Filesystem type, for example 'ext3', 'btrfs' or 'xfs'. @@ -28,15 +28,16 @@ OPTIONAL PARAMETERS ------------------- device Blockdevice for filesystem, Defaults to object_id. - On linux, it can be any by lsblk accepted device notation - - for example - /dev/sdx - or /dev/disk/by-xxxx/xxx - or /dev/mapper/xxxx + On linux, it can be any lsblk accepted device notation. + + | + | For example: + | /dev/sdx + | or /dev/disk/by-xxxx/xxx + | or /dev/mapper/xxxx label - Label which sould apply on the filesystem + Label which sould apply on the filesystem. mkfsoptions Additional options which are inserted to the mkfs.xxx call. @@ -46,13 +47,13 @@ BOOLEAN PARAMETERS ------------------ force Normaly, this type does nothing if a filesystem is found - on the target device. If you specify force, its formated - if the filesystem type or label differs from parameters - Warning: This option can easy lead into data loss ! + on the target device. If you specify force, it's formated + if the filesystem type or label differs from parameters. + Warning: This option can easily lead into data loss! MESSAGES -------- -filesystem on : created +filesystem on \: created Filesytem was created on diff --git a/cdist/conf/type/__locale_system/man.rst b/cdist/conf/type/__locale_system/man.rst index fe54c01c..03d36960 100644 --- a/cdist/conf/type/__locale_system/man.rst +++ b/cdist/conf/type/__locale_system/man.rst @@ -10,7 +10,7 @@ DESCRIPTION ----------- This cdist type allows you to modify system-wide locale. The name of the locale category is given as the object id -(usually you are probably interested in using LANG) +(usually you are probably interested in using LANG). OPTIONAL PARAMETERS @@ -47,16 +47,14 @@ EXAMPLES SEE ALSO -------- -:strong:`locale`\ (1) -:strong:`localedef`\ (1) -:strong:`cdist-type__locale`\ (7) +:strong:`locale`\ (1), :strong:`localedef`\ (1), :strong:`cdist-type__locale`\ (7) AUTHORS ------- -Steven Armstrong , -Carlos Ortigoza , -Nico Schottelius +| Steven Armstrong +| Carlos Ortigoza +| Nico Schottelius COPYING diff --git a/cdist/conf/type/__sysctl/man.rst b/cdist/conf/type/__sysctl/man.rst index d5c6495c..6873003e 100644 --- a/cdist/conf/type/__sysctl/man.rst +++ b/cdist/conf/type/__sysctl/man.rst @@ -15,7 +15,7 @@ Runtime settings are set by directly calling the sysctl executable. REQUIRED PARAMETERS ------------------- -value:: +value The value to set for the given key (object_id) From 9f1e99e613458e3f8fb68ddec7b282bbacfd79f3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 19 Aug 2016 10:37:24 +0200 Subject: [PATCH 0291/1332] Add 2015-10-21 OpenNebulaConf-cdist ODP. --- .../2015-10-21-opennebulaconf-cdist.odp | Bin 0 -> 1579388 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/speeches/2015-10-21-opennebulaconf-cdist.odp diff --git a/docs/speeches/2015-10-21-opennebulaconf-cdist.odp b/docs/speeches/2015-10-21-opennebulaconf-cdist.odp new file mode 100644 index 0000000000000000000000000000000000000000..f76ba9c3d1cf9ca499cfaea3d40c2111e0ef1ad3 GIT binary patch literal 1579388 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
6MWh!~h%?d=DI+AzRn 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%0D7PBptz%?%>Y?#i~RplwTk^) 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

n>dG5Aech3BW9N z0nY`XrWSTSIg8VjT4i48b$*{ZYc@se_KA+oR2WJJCt$Q>Vj)mWMhW6S1K{ii7bFC%=CQD;l|X$6_O6+xw=U_ zoHEhQXUscbm!63hyI7rvCAq>nGj_tk869)Uuc?ChSf%7Bua=5t6w>WJFoI8Gjcwzh z@9z)>BwB=I-g$xwq`EWZ@@L@cgwZX?Cg@FYat1_Ju=l6I+>Lh1GkC8~cY(gftLuO3 zp5nA6*4vo=tUh8d*IgM%FGDW)_6HjjVeb{jLR^9L(KA#jzYuDLzPi`=5LY=4r<#({qhjWSd8y#PrNqvEZ3P?BMmitB!=wjr z7NgS$Re}F?491)K2a&%UBpyDS~-QFqC&vxG~_Uv1hj7L0+I z20-u{q|_JuoVr#kS$=pwjBHJ?>)()8t`V(X;*SX-3?&F(VD7!Gee~_KFgO3<&J|Cl zw(5BQPUqBWq&LzzpSFe1##O+<*+?zI*k~N;-0p<_MLF=zy8H! zE`aY#ua_?BzVUkIR(yGYRWRn9lUZbX1LrTnw@@ykoC)#_qd=gxNIlEirQ$>#{ctWc zg1?+OeKXISC&RK&>YC$>W`pExyMw=)JDcg6NssCA9@)%&$&tHj8+$`b0T?)6zS2&I zn!X3`p9Pewrl)G?)5M}ir^`|gPxiYdd(y7B`Vvdul|`uQ3vVHn?ba!4(%@|fqqpk% zjwSC*S@s3X{g6wJH6IM{3{;-u5I{(-k&7CGqWvu`zRcBAoi_?O$nbBbv>W&X0bqZ|L$OGe!#76TOjw=~4dm14Q5n9zK24y3Y$x2E(^bqwVrLfV|C_fwxUcD%goEGl5j! zQJ7sRF{2H5CkP$&mxd;LPI0{7oiK1YmUm#XRCZRq}S-VBaMt z)vY`N2B_7_9dg0(?8})vOzZ5v88t=QpxN*1B%+wP_YPn|T#I+)jPEbV|A$|+S!M_& z?A`;a^FUDj`>6n3Ab7p_=t8dLkqBJ|@>!-D7)WqOp2nLeg3H9W=f8tkE78GST*ase zg>+Yqz}y0PF^rfQqsYFKu<=ZQ@XwBd5b3I;v+UXc!R)D(``jRvGMm>$@1D8y*>0OE zyzeBHx9Zb@+3VF`IeSK2k(@ge{1$-j#KrdC2(y3r+EQAk9r*V28&eks@i}7#N0$V` zYn_T`yl;>>O*w9Dtnq`s*G07R3xU|TR0Cu-Yh*Zk?wh35)UrZGMLZ2RCWN~LZB|ao z!+3}Db3`uhPcDr9bS$pW*?MfsXGL|HRzV)Em;EzkP!E@)Z%8D}248}=p0+?ct|U$^ zBj-mKlLHrro(NV4=0aX!e^; zCIS5R%OZ+JMopnnXmN6;7l3xqJy_N|lCj9O8$qIDJdKE2>R=M?gR`cf^n|?dqcQn=$EO8q5XiJj>>X&-8bPjkxCt?d`vgzxfSCDd3mF$@7D1fLj8yfd zR0kwg6WyTcV8%0&zG=;Lb8kls`~HyT&Vq=$qa7eM&8B8mH2!^FU8fG%pvcV*MMw$l zgRtPuw-HweS}{zc|Lm)!kpH=kd&Xf`lGA`_nR@t~ql4zTK=}!~S=B?P*dO2+BGVnF2enrtV(T%4acof9yl9S%9hn3-m zo~XS)m|RHIDQZR2={meQV3XX{D9)MSK0@JqMvl%L0uMaCy+Kipa-Ww?dwF9nH#X*g zt1xNmiHU1^{q7n-3Fjat4cgLGLJJ><@Zkg`tpnY-rAw%td9gosA1u8h?;U>nbKcc| zv30|dE_9Y>a=!d>Z1#~5VNEkim;4Iw_X($bXUE4WAs0))JqyQ|i}S}nl)8LQ0HcB_ zn^#|~iqCh9uP-rz*(FjB<0~Azvi(50C)}e%yXD1^(e|-oMG{I$L)& z$js90FFhc3HivyvGooG>kbO~Juvt)2yyxss48ch8nOd7fzIq2S6Og#lJaQ5IL0!mq zkYecc9|LMZ*J?}pk+{OtZ0XjzXzWgZiRNhw@9LjxXg>3j#{I&tTtk-RWtj_1KBPW+ z8u#M-BS8D_l&!n~a;<%CcF|0y0|TDaJz zTHo)2~ssPjZmg16{}CeiRAr(!<^Z+Qb{NC=aGmW@}dy3|dEumpm0 zsSbvnmGP3z!h^%ju%{7b)?C4l$Ih}wKhXxM|0OZAv_lw}AbIx&*+tB6enqI^(M&JO z-`i!WF>1*k=<1DVWatr&SncGMMk|{-l@hMPYwx^2IRm4{e&%hqb`PX?2Hgo!iL{*K0h5& zXCXJ|L#EIW*<86$vI<^V z>mmP0k-k8tzTXOgsP*47)6(dto?&U<@0t9iC#&F}`$b7_Qdm!2w>hl)QNcKkI2a8a zptx)p)srbF3QNFHMj4U@mW7I;8tBQjd?xE&up;mqwZ`8Er2{+wr zFI)8}6=69o4XX?AwUxDZ97{DMbna)df^|n_JEa_AnFC?PMH|e9*Rg^mEVxBUnwi7O zWJ-CXAwvikw7C#%MB-u*JX{&HoRF91!+VBypnCvd!kUiHG%XY zS}1xGWB2U?%)q9U2WHC5t;z-}wAMzA+Vp$_(05cMuAlBeaBhad@^}8<0?$;Dm)Sfc9 zKAq3c6FZuFp#1ZM3g9Q@dXBaMf$m$IEo-JUIO@pq@fIAh@Al7w0g;>(S+Pge_{sO& z%esbrmo90J= zve;~K{g3lf);1NNb{@i188M@wX&3_6i1~ca;kd9diGRxAvc$w)Hn;8?++vU?BJ%4d z9;R6Cd#r5hcZGB=E3wsi8CTML!Gl(B{ot#896T8UZ7JR{k&toB*fLnx4Q+P zZ@@K0_b)tjzZ$eWAv7rzQ_mrgE=K8#MV2ZslHgLU?v>_AsRnSAzt4QgORMXB`Au@a zJ%VD+zqBP9xQIl^I4{e;0&_x2sevf5`8TJ?M_*kOOW14Odf6+=$;E|8V*(5QIg2#%nrv4~C z$OD|m-ui*EdZm**u!9*ow_R3a3Dj%TNPO$c+0_d-d+@I34qu1=+CH-puwuxWk8heB z2~*e&WVP7J9;j%%aBv}Y#us-1+-@NXAMgM+6a08#$Y$aLlfhKY`+xHYr1O6??L75F z7CqeBVo9Zc7JUX4zkvjw7JSX6N%bLQE#259UXh1Bm>-h{ey4+UI? zM6r`(TvBk7ki|2m==*q7@Bp1sM)~cWpov=1WaXv9D}Z;)s<>#y)<<#4uc=3QAuF)N z&7s!afU}d{;&~vg0y0;N+U7|E2^KNUWP^c~LB*JS{DvHFLan3|&4F*NG26eZrfU_s zpP+pC@H3|XDT>)a32TIBB{51ifwrN%Sz^*rgkJKfT?P8*#!5W`7n9@~gv>(MzN)L# z_M879geyT|JkCWNjzYVpR`kP%9b{drYH1xZw&XTF93t@uzA>IRLo{a0Fynsg=} z5a5#&XS6~`yMBxf?2e`2fuIsXYx&y&*Sw3ny zlpVXL4TMhsc8{Pl$*)z@I#gY`QM(&YHv9}zYES?L!_u_O$(&D$C6%ZusD69vIbX*P zAYj?zo&yrr*F$Nb*7~`BoINE`EK-Z~^vekfbdcwj<1~+~4RrQ{@5Rr%ZoDXYY-anC zHoB}>%U-)j$&)z;LYaHj%Y`y$azJ8)XYij%rJwSy3zWZ0zELKOemI4TKmYx3?!^Bj zc9v{VZh3W?sHl4uZg3n{E(>XFhaQ?qg&mn1pE0hJ3hTS3|?se9nLXe-}>pa%{Jg z%1fMxg!tBv`0ad^!^1`TX_uTks6mxHwII+*xKOtg*V>tnF=oalB5Pg66M2NN zNxWCFy!W}#t*+*^eO-;~&e^V(o@p1u2`#V8X3yGDR`&L`B8ULa#CG$CrZ^{)2GE*# z$?6JFhew#`YY0=swhxdxvN5FXE_g=IN!PqnJ@#bIvp^$>a;~}Jr{*~lOSSs9whb}T zoSCD@24d8@*(-$U*O!-ssZ9-Qc)O{o8gjPE>TqYc|@x$!FD-{;crr z1`Rw%-|TN75K{Ln326sUI`T$y|7y1fXP85KQjAe%!?Z7LPDR=Qlud6Mg8jtl1A4eP zByTZI#||x{A|Hz?Q(;;LseA*5zf_-WY;1jL%@^*ZDTK#2p=FeR@HunX_&CVQ^-*i% zZE<%}k(^5xIPAp4QPf^McLF8AEg&ZVm(jxj*oWG{ zPO%E}&U_j*lQ#cYCoFnu(b-#RA~ye?O5VNMK^Z^dNUJXs+e=zs2ihN}y|l*D*~QVx z!L>-yIk`JvQibEz&Nq)FMx%uvk-P(%fBZ}`2_fOkM`tDo8T!E2`X{E$~Z&@@Et zL=}~I_cq6>a6ubWdd-uyO(#CDe~BlJul1lLFhR<5v5iDb2FWkz_x8l~e3vy2w}73M z9TFbjx$>C_ezlMJWvd>$AOmBdtt?Sx`QBFNL`?u z1GdDG7wbQEm%V9yD;>UVS8|sc~iN=gT>>Q4LkKFB^xU^05P~@Oqewp86 z!t`1WnIpCocb{#nRFW90%H$v5AbZlnJFT@lmf`R<-=G>hY`~(%#;%FNv3t;fC4B1Mbgf=_n90U#;vB(UUzIIkjbY^?&jtT&zEGyynZN)A@q#{g@X@URA1B$Sj zW)|gP7PSAS8cv&phzVIlKJwEFawm&}CDR$cq!A`jJ99eKd_L5G8qQeZw0}{SNN#r@ zSb2fCU{?zYtYrdbHPKyyU#*^-2h@=IW>*r2DHdm?Gg}K?^?Gg+KMly2Hsh^5GLj-F zpt5FILm|h*_#?WTy|Np%`OD9Twk&N1sW;*3ge%1RF?nm`2|$Vd*An6t2w+I%F0SW) zb2fQ>IZJ(rM>@RI-+9LXWl2C%Nav!FYZ<74bf?!qB6g8JRPlgmKNlQ_VeP%C3mA#I z3x|!yd(g)!V6s83^?O17{({@P2F|j~?pCgReoL?8M+kr@;7W2EX7GF=40_2uD4VroKax!so4Ec8dC(L3I8iGBc_w@GJ6`C%BX zETx1dv8Me8K#QPS3!0IC`YGVO;r@HqPqH^H_3>}xl9H%AhDA!8LR@u+MlQ7*4L@Ky z6*jO6#aAjp(|0zOIP$|yD$d14ooKXvnV&Qb#0^6uQr!nUOktK)>q@v1s5Q_#@;*+Y z6@{w75AVHdtz_^$8nM$WEMAo$1k#yOy@OT-d0?l}Tb+#n{m=%3?&r;K_xg1Ol+AMn zfFP4k&mPtp5z73kz}X&@;Y~X`?pZDuN;i zyHC#7<~`c`3N`-MBUr*~x}?WD?3FF_im2>3qm=!KZu7IBAorkezfb&NM2q~gF*cvys zbhl=+Q#4Czg0`378&Tfl7dskX)Mo;7*FPej7Cho3y<`HwR2N#ja_%@>d~u#Jy^;r7 zK+}tK?&@>Nb>DAjvNkeHi@Z=8y4f@I<>mO4M)iuY*Z+19mW<-tb~HFS)5Pt)RdhWv zZul&h+de6ErsRzfK9?g^Q=LuXpImnO*Gc`L`n}sVK;-tI|oSy~B7f?fd_@mB$bSkT) zWs#z+(y;|4pP_mSSY6m?w?SzZe=f9&2Byz9#3oh<4PR;6F2rz^iUETo!H0f{5l9R{ zWpa#{!-`g;GtrG@yhb|D-MP$BTivNQrRoL<30I3(qHmn%jHj`OFz;>cgpdH)U2??k zo9Vfu)7{W=mMZt%CwhbCLhPLR2EKE9P9J2|q7(jGP2oSQ*?Y%m7V-YEzQM-(uIjQ} z`d+P5&3@zICSyJda_+K0DxO_i>Z)bp1?aCb7h_y?%LRzDkYaesO9XrmjLR5Wo&D!kdNd0Q>K9 zm+kt-=kC2hSC#mh96;GdT|lJ{lwWf)gHnu8o76?bL4^^5g=phZy)YIY>rIeh`|FPg zkeGgVOf4yQsa6A4w@IsKpjlGwKAkvziuTvxqtz0Zw21!BtovWX5`}rmdu6C3UfS{+ zTgcTF2;kbgY{Fz2AhR2mML0~T`p;-kbzOp(1Wvzf&+NK}N3QIYd3Bxy_l5C2)AT(d z@l&e%29~Q*6j&lz`2XyTjlGd7G+$eHqgJO&ihQQC*&t>BbM^PjyUZeq#kaW&=W;F_ ziX>vlsK^lM!y1sFAJW(V*>&npavuHWX*#x>oD0 z*RVRb)Hswc>h$hZ?g2~0`C6YEw%S7d(@g>!Wy{5Ew|j=WJl)MCuGp@gYD86In1T6k zzWaQj`3*TCi&7pAHVa;3igA zJAJr1EM_1-z?Ab6%1yyoyOI6lCX^n;J`48Mut=1v=2J}0G^1J&zNV4UMAnaHs4Wf? zuF40xiStm7rT-Z;+V}jA{Z%6`I=+x}v!96We&$?H+Vfp5u6sHC28-WY$KVG}H7@f~ z4(->RoW|eSz)lQ%9&b=>sV%~?fjqPDE4w$Uxy4l%|It`1`YuEDiIYEUzUY=3 zZ=G9g# z&QJqozL$}k)4J&INdI<6M{+pYLG2A7b(wWbtC&$j%DcqhBj&~Uk3m-sU&=}_9wgCv zT*AcQE=NNc(cj)Sx;W+@nL2f;ASpMA&`v=5DbJ`r_I0IDR<568ylc-xN_Ux94t3eJ zO(Tm`Z71)oqrJ3xKr~lpHOA#B^BI~Ns0m9>dx9UyNjuil=Y&)>OC-(V!!nUqlro@W z1~67Ll{~)bGV2e z)53%@!>kZS@PJQe;Ew#y$`67m7fj`S)J2Z1ouzH9!TC{quGlhJYJvtKICk}kw}+pj z54BgNLIhudgX}StT&C7d1;rao?QuD#n*P~upsqlTJ$@Cc%j>?cAK9Ps8Ch_Tmdrsp z;|u+l1$`j~SzOu3lLE zz3mXe#GB>(wuijRD1Hs));*S#39XIXrENc^~Y^~9;40=|^?HTVot z?F8RnDu=fVt{yQTu?sb?7-CvkQ&j!oq`iC@JG?B1JisEbr?}81;|+CKxW#zZ8(ox(@|q?ks{K%>Ym5BdjE(o#tyUUE zHG=IXAa%vY^1%_5SIw90xi>qT-EH>YNh-;3a|L$OYDN6^uzywBG5n+7)XSUW+e=7l zann**SNNvUb+BrkhF_KQu$>YIN@yGL4t@Ml?5=#?aefL|?F>4(>&!r!sw~*r zmq-VyAAmi^161-^j>eF*(~L{Lt>1b=?I-QkcpE->#mi!I1+N7p#}1p0{;DRD9W{##z?M~C^QuaH>z zLn|2*-}5@k31q7qHgk2pZJK7N-Ju&k-}R2~4chAS5N03BD~W9*s_;;VxBarDxUAMh zed#~*RDc;GxrPca>2y8 zeQ~#Hzj?wfNb#9NH%PCxp6=zvPO|JhpqVXk#*ln~Oif>6CxVACIP($LQ`sW4q+(3%Op;qM*`2<--;CbFG47g=V zRi@1Haah5%Ch!_D zSF9gN6co~Dqi?hsxc(Iz1@)cD7r3^sQZS3s)zxQwUWai)+|i_Fg2>Zt)+n_Dr1ZxX ztjOh}B+DA*vHYgrvzg1a{yu)ZC}4Kv+$ZIIIiU_Bs<%T2Ze}^C8;zh}R*&+88JJ^_ zqC7nXw%bd-zL|^g&^M&EuWfh%3;g|QW{wy#fN$a$a=-xtbjx7uU;2Ur3%OBm*|Wos z_}+a?Gk%yYsfPzV7(C*K9BBOLNMb{8l57-lo8$LEVD?fpbm#=4WDHS8|x3_szwe6&@x znlnwVm|w4_tjULuwB_fM9onk-jbC5{&HaUPlIm-k>;mMq$>^v7azs;qR4K{i7%5_sUQ;wt3ZoJCDK5di%*Jov}(5VkD19{;Ci`jLf}6+;rApfS~5 znCFl7a(bihFe3Z9I zPwhrM22X12zHSe|jdXW)xt-b`AE)z{>GMBW(WyYk3e!lfaXW*HcIuK^e1(8fD@7D#eOIVjcmj}UN5$OR8w0XyZaTdUJh>b<6BJWH0!Hd z5@h8xEAB=tigotT{5?#^*Y|5nGJft^Sk}~;4MTPCd)Me4jn*)dW%khf4yAnKAUW4fsUQ3 zPd8PPpnL1O3+);@m2tmVQaMu{ftQOE5PK_Y@@vajmwC@3gEzHC*Zg_^v!aH|ve+&6 z8pN8+viH4T&$hNq7;aA9>W<0mOfcd=PtRt%pa%5aNJr4(d{^fDNwW-*TiqHs4pX!=- zoxYRJmFlSfE^l!zCs+a%5#TPL$tJ#^EUY4iMJ|g=E%T(X6KV@|%s1R-jgn<1h6&*) zCu$?*uB9Rf4UwzMZ3c9tQWX9(4=`BgwLg}T=qp;FaF@&JFX(_EOt?_z;XF^g8fI{% z;QVperLO_6rw2Y2&kKna(oD1cjEzaZMz@6>Q^dG-C^y8$i7~7dFw%?1W~OL>DB2Us z4?GZ0l`mEJ7mPbEG~YRu+LiCA@8E9s*gLS2FV8oUP%H(W;sJ(S?TeJ3O*PB!AtsNd zc9&r0v0t{0X*Kh;a$X_}$@gy!FC!7Dib6$W|Bt=53W#d^14c(ZCLHl7As`?}6r>dd z2?0St8dSQKPU(j6D4-%C9n#(1DF_HdcQ}LyNH<8|wP%=Nj>r4m$NTX8*8}X?vDU9^ zt+jVZ>(E06t>&qdQqDd*#nBnf>Q_^qbyrxs~K*vGPw9r z`1q%p3X6hpS6g+=RCjgx%6BOE3O1y~n;V=k)KjJRc@I{h0;BbV+dNJ!^u53R)-EwD zNJ;%cP6P?@ZhZb#7Q2De>uwB8GSSDXCr>)R?DZu)l)v!wS) ziStfogcziaT??{bzJIg7Ra9Tfho_B`Udz(qN+~eZUej%P+{DfScbNF9tiM}k*;ki0*Dqe8ghKcN+DD5Ps#Y%hCz46FsxgKbPX6B9gD2fMw^@0wP=m70~?>R&zg zBSHSoE{SyEWNP)e>-Lc2Dbr)$Pu^A$U5j~~t-JnBEUxX`3}tye<@>x%af-3Orp(ms z)WL$Lw#gUQnKhc0*;($iMYK$ftx;MO@t>m|`0RYmZ6&Zk*-k4?{fi00(*<~T&PU=- zR}PG?oo&nPtMzYr7C6%?wr~G^-iH6{JU*}qFc_P4QK^HgD*etVF~nuiit$GxcK7uT z%2szz1VSJ0U}ak*>9^)EQc`A`;aH&YdUe0V;aNU(D_rNXjLbgA>j^K_@8=dkW#r?D1yUOFjc^5Ma zQpNK|>`7;UsF!o?_1poAcx4Fp=qTspm3gp<1oNko;J&)spkAgapZoYGg6fL~MTBuW zh}L6GH1^$&)uBT5>f2SpVU9{!Tk6B7--Q`gZJe{z1H|&4Cs{5-Z~#zY75-z`nigtJ|8r&%)u?HQTOx(Jf=Tt;O&P zS)c`VQ5BezX}x-nDRn4(p~0~$ctsD;E%N(_PZf!r1Mq^t<)K@#K;Y^=S~O(Nys}vT z4kFL2_u%`119wB$H}VlZt;J6ZpMm)dU^Mbq+@9K?V^okSfblyruTLz6g9Q!WD~fzh zkC87@kiF*WCY6@Lo7*3?>;s`Gkp(%!NhGMo5%;Cp+pmZa(v76oX+$Umf1$#GAS4J%=Pe5I_$b+-WTN`vc9L{P zYrGR9%VSV?Q53g|oH%K7(5A98R<&2xB50~{{V~}3A#m&KLQ+!IzO%vCMv;A6`;wpX z7w@g?%z5W#gB$?ZTt%`iwxEh)2R~N@9Fr>p?HUn?0U4tW2)8zyL>Fh0ZLf!Ecj%ba zs+Twfn0a)dD1RmfU{fHfoS`%R0J1`=uSfdzUmIo2NDS``E#^xj+Ct3ix9UmGpB_so zFdQp10k#&Dd?v-!d6S%gfQ^o+l3MrKGGtI3Ir+aYLI^)(e@9>87}(qRJ&)f z{zG|CEf`dRU{ljkyg6jwc2lAoC-`$$Gk83xSCZRn`Y95$rtB_caxl0JW_GUWM50($ z{cVVBy>~&u&jq9nSeCaAl(@>?^1BIod)Vh=)L=`Wws|_i&g#Qr7qfyisK@w%CENh) zwkH0x`2dD{5Mf@Z7y4P)ndb5NZ&nuc;g!YZ+*f2ZyYlk~I{y#x(!TATHtr&R5qc7| zYF-ort5v^<$vRY(I+)RBQmM5^MOl9nRzU;84?dkf(8ezv2o zPg>1t(?Mr}uIXkbR`lrm)%l@*fd@7NB>pEXeZS!C?F$TWPP`H zu4z`CixSYlhW#=giifa}lnhxjHO!opzz0;-4*~^@J*cjuBMn{ReFy4f7eo?5%QvO; zE_07JUuDd0O;((+woSA|n^8sPM(rzoUBh8m{9+;XJZ!xA`A;cL8oW^0+bOo?8?rf? zJ$#0~s_Ndd91W6YMGSWZ{=x-9ls}WgHqP$qS#URHeG5Y#L)Oru4?b)XC^u*?#z1b6 zk%Y9yD%it#sJe=7cG^3lmi!D4Lm{w!vYYmPgRrP@b)6%&>5$XCTh$CL*90uQ-?E$? zsU4Sk1imZ|__^tX37h`)mFQj~l|ttSKW15roYMMaa>q~5#D@!wDZ<348|jOdS-=W* zRPKiAAKq{qsJm22C#rZKr5#6x_Y$w*@l6t4mBGDkIO?8iKk*ym#gQAmkk+Fb;agN< zi#i_7DHspjL)GB`xZ~;a2*J@BAb0I_GWN*f#xK$6N3<+?^@aTzgZ@DO1TGpEh@e2R zfjw;<1&Gp49|Pa5a5J}BG6V{mv{fv$AND{E;xo4S3~Y&&?i|W|qx!2ZxeUrsRjNFw z{`sY!*H2itJu6|4u4%FMQg;UP^v$BO2S?cma$4Gy+e2RF%6`nHs7{CKv(I)XvvAF z8KX1euSAZ}%iAN3M4V5cJ@D@P40G2zVG`*FC<_2?ZVvE3O_4+Wz%BbcXFXm$=JkW9 z{?MW#q1^PZz46&JYHu;Ofk+$vKY>AeiAKRin7uJp7g$>igIL9J7=)LjpfunQk?CP4 zC`Gp@Grl>w@)#sn%4x)g;pziiw^*S8f$=QhqfDn6NJbG5I-@Bc00oZdM)EgPpa_ro z-Xn<5gpDMe@~^Y6hE34zZnMq04JNXOzgF-*eF`nJKNZR2hKX)s9?gqAQl4Vgiei_$ zbamGt)$#>}KeiF~a0SDp1ij{}gZ(^m2))5Xg+ggTy^o}5Z5(|rM{Dqyf_#D7TWnX$|M8`3hUjpoupb2{k8EO}&D;S>2hWFG9{gofdj z+iPLR%Z`_UYTm(;XSkO0wvnv!PJ_t_h-<(T1RZh&56h8r1X$?-Ni4s?f?fh0Wag?Z zN^N-=zjEBnW=PCZGjVra-j&yX+T@0;?<Uu1@RZe>|J*F2J%#qU zcS*>{T|l;ZH1Fn_h$Gxqd&M@qhr-Pmr9xX%RUnqR|Tl|vk+qfrv-#=D6DTQQ5s zRjv16cH{n!_iQK7n12lSlGPK!IL_*ao)00|QLVWKIL^iT(Irtxa~Ok>9e4A0473o9 zKp;J4GsJ#w_zaB|WDc(*RwmXRey-@r3tb7EeCBvi8!`UEksEAHf?Dg7YvO659O*u> zV$#@5`Qh6KsEg2_WwNB&4sb6yE_$^UZJs2eFNM-(6C)7Y(=#fTF?GEJcPmWIw8xpoU9%Z|CSw` z4QgO$c(pWP{P<^XZkvY6SWH}V{DlPCu%w4CSL2b=wVWe7>~K_1 z)o!A|vvDsJt>`ggCkj;mz>#o?c{%wFQ~dK$0g&LV{CJ=DVkepk(q9*qRf~cwz6u-V z{EZ48k+F&Km&cqQsEBgy&N$rLT`35xAt7-I049y!erMDQ^#(K$rpE&*T}N81(=a?t zf#8N3d=-cNAt@jtng6^V=M+O^04_56fZ(wCp*=FR{PP0UJx8Ehch9qofJ!0w4Ds?4 z2QX96reW|psW;WKjKJO;d0=nEGUr`?3hiZz3CZJH>rHj6RWLD3wLOlTX;x*)q&i<8 z=V0x3qZ16Kc;5bOe@4ZyDpCK$%EdB(9dYGuXwTB5DQCGuKVH#J%CWth_F71`4CP|` z1mbVW?0q{H@~V0tQGx+SbbskI^!sx*F1hpQZ7Y#DI^&id)lHB|;FEnx@ z)~3N%6OPn}?lth78%KdEd?FiI5a0`HviJr*&h9A!Qzy=;JSHAPR9b5em1rHoo|8PD za}nl++2fmA!WT``pVqdl4;q~EywP$a36y0e8_;s6N$l5nH#4cC0L0({7=Qah{oCU+ zsH6sBCGd~FESa}k-PdWz8_*OzFx|OZo-Iq@C1y{(p{G+y#iFiqmc>1A$tS7GY_l`l z_BJn5-q3oVNF7L|Wza=k}F zMzw2ZAA?-hB-}`{SeRo2x>+0<4yi~rm!^NlZyWy)`*@upjiC5mE*MW}BE zOBZ=;dY(L3o8J>8Jc~BZAC*W6W!b^t!3u%ly87ImG+AQ19jEJh}NsSR7C`Wdc1$3`6_c)q08TkXJY-R zfI)tz2YPdKQwJxtT0mpB?;$+L$l z@?$axJ4Q-AOs}wWMn#>2Yc||O7Hk{Bx-)5wtAXJAGLr1oP_j_>@B*F>X#_>8@2y%t2^J~NzLL&>u&XGb+W#T4qov1A zj81j4Wt#jM4ZWl?v5}aaV$M+(Z0`#x>DRl(w|Fb*QS!MK>_|I?^uPa8L|WtQthI*c zSe#eA|I&;Nt&>sGwZn`(Cd2161JZn5`>E7+Cj=PO_%a>=u+Xi#{Bj^eh5t0FDuI}V zq@gFAXUuGY67Lm3qxkHK{c@H@RaWs~f=s5+xe$hBgU4T3y#U1@~5zBF~PD@SlyCZbLtbh>uL@G2~Vx{oHfO0Ml8N z`%%iMnW>#XhkQHhA?*!l0|Gw~(Y^=Yu5!tz;_G`<1GdLOYXo8#|4KkxeAr@Hm`&E# zn+pG`J^n<`eWM0|m$1DtYIwD*nGlwMa+^yIwuI`g&OE!pvtYHLKht%v!5%4I%fJ({ zv}Yp?wn#$l3BapI1XV%l~C6WstV|5N>nLB zE(w=8D$AppS?yuswUePGe~@Im`0NS|0Tn3fi zBJ&FFI%z$>4z|Nl`dNswp6sLWt_2nT^5F${;JgJ6yGd{el24n~)VZJ_9glGtyS!L` z3WJvfq9xPLqI&@4>G-A9;Tszfwe97ugzCmUHF)IfFA9{1Bwo^`qvQ6wR0>@Sfjkpp zEV$NK1eXK__f_vrd+oG11Q|k$N=Bbs1JT~ISzNQebJIgZIm2y=lT52(fq^5h9nfQ8 zSwIWA4d@ydy>xDJ*oJaNyg40IdV<<$+)rI5^dXp)*aUv4B5CI|CzRb)Cl#=fc|=tB zF9mlgsB3THF$69(8{XlqP$y|UN$N#AHf+vcZpnVeECOG;0o?_B)s|^KWAAQe1Q5(X zjB8)&!U3z<7ld=(k zJxCr>H(TjbWAl{-vS=bRBYKzYEXzu5G%g-OUM;;kuY|!ulN$fq_A(uLCe1*a&xO==k z^@dhOC9g&opj8Z#+#P93#vNzgAF=NQ-Y!~DbG4+uTyHHa{SoyRk#jXA9%TQ6sUGl(( z8@gno6SewNYi*u+Q32rcXu_Uzhx7LKNZ)+b-g=cpnzTlP&IgK~p5Um1d^U%r zoekQ!boy1=y}XFFvh?{KmJto+ZRuB5Me^of_?i`>7RZy(s?pEbfOJ}%lHt6?!i^nQ zrGEAh1n_|(3&-N79oCZKd&UnT`R;9eC0jPIvcLcKaB(ef6ldB%$IkLFe<0=|QzDEE zfzPAplHSNGq~p1cxd?-IOFrYw+%A+yM@nEKPv)tBtQ1euC+o^(b^OPA7tQZ}dr}xY6t5Jvyu@JV%Q0?^>8)BgT%pU8kL76h zK1^VyaJwgdW=I)?Dya4-7zg&aI$j@IEr&#`XM_m^Rm_J8Vc@%}hRcN_{Bd3N*9n-B z!8FVaBrrw&vKT}=wU4Oys75J7JsATUnuJ^GxA0qI(OieY|0vPKUVbE~BJa6s@s;j~ z=JAw8;84?I;)}ih=u>)F5$Q%v? z>+SVlZ03SvNC0~z-0ZoK|1Yv?4-92;$zVF~e1?OE*b~XNq4GIM83 zWZXDBYqZypY<-Hk6$bl~J8oL3fd9&J`taP_;6Nd>j5ppVe^hdpG4`@|=&3wlB7{daNs3ZPf6*c)wo(i!Xcr+eN$)=s-G^T^< zNwy==q%o40WZCBR!3AaLo!Y$x;vvkbYF*s>fpFR?_p)K&1VH7^so6Tq;J;#FazF#D{;fO zyA}RTOYMRCLszgu7~Y859fpFf+AEK>0?Tk9IEcb$3O;3Zg_zN@?Qxj;RUct^i$SCh z11IPLNQ`L?;Oi_ebvsn!@Hk>DJWEwhWy(1c`yM4|fVmb!n|RFK#^;aB0!-trJ*70_-)e4B zmr1#fz?W>;E&*7!LgZOgyIM)!rIX}jPbLx?|H%>jdutj_(us1 zB~-d@ew?@Z2E; zOQobo?(rwVV6HOzLq!~m;;X~6XQ;exl7WG*T>VJ3V3lKx5-d21TfCZS;*I$Y??d3o z4rjhjK}cYn5w7S1{$}^6FEU_kNR~eizciL}2DzVLE&=gqm96T(>3$h2$9)Yr-DkbA z?{H>pP{5ToB`*9rt)VMeY_fcCx*yR5s*3>?5TiJ+D=SfMq!-gc^(>A-8|4JuR}fq} zVROW|D!V=o5&Fa5zuX<>(WnzO1$NM28k{lBov$00r}uDqDh#}*fl?a=HSkoi<=2+Y zcUmtp(eWw_R(^5#JEjT^`$;jWWic>ikKNG&DPxlsoz38+0A^4-3fvLS|7L`KmZG%E zjKD(};p=)w7JSs!Fm>8KJU9ZQ+TbSJVVfhl$==85-O0mWMgwayKuufk%8o3u#rCLc zU7W6Y7=@gBCUuf95(VP02(-OtTR4P8)64!jYKj>8J<1dDdRq_^NPsYzXM&Y*$RsZd z(?L25j<}B)kj|w2TL~AgtRo`mZLVQNPxBtG%%6|~+J~_L0G5hZg-2ek7gr+rHUHbS zF|Y}?o+j9?_g;q&UBx(2SoNl(h9uv<{T&``)C37~)Zpakl*QN2ygr792v^%Wu0)gw zJ~{jegY)akd1r;kDr1EgP?c8u--h1-*Bt&KRlBB&LnKGDojOyZvJV&rX7k}NjQ3?> zI<>ckNqsx}-wzhsCo>>%tB#7H?12S?YL z%uP?~QD!z6Al0{yRe)Q(Rq<(cc^A!iD|7vda}5 zRNF?MC$q>ML2mb>xPp(-{S%kn;kl((c3r5&jnMB=()6a~_1ph)4+~x%d=jNwnHVN5 zJ->WpjqPsGYFT9BNT!fk>6YoO&(RpU2OAr#v7@(X1L4$Bw-LjhfqlgrkhzkXc^<2V z!MGYu8u7ZZFZw2JoMqJSd5aOiwh>`iH z%_g=svzWwGovNNQ>k^jKyO$RSCzq%u_7AXLxeXD+i|x}mK7>S#(NpRypHZG+%yA7P z8d&A03(P*GH50dlig^nsxX{|LOAYwnd@$Fp zbdgFQyRdM->T6_OqmIh!z$)s)UhEv0DRIz6pN0R~K~^*IK`vA+ty&L_8FYc}h;4^Y zBpcq%dk_ zS&$F^Rr-HOa&*EdNpa{jHljZ|k2(5RHi0>L^#2k3DCs;pi#dY-aTKb+5A+t*Uyaif zupe`svJ#({S1J4}mz5(|@=En+w`%fhRSLQ`?R&Z%X1#$(^ednyKmGb->nORRprQB-pI({H z$Ge|3kv+jvDSXzYDxDqEoB7In*5V^Ll?e=tk^)DwpO|w;{{=3|92I4bPGgSR|G=5= zz??k#&wlJ^UChy0?9u;*#*zYi@IQiMNpW=W|Erkg{(T6DA#(6r$6RVm9MgJ!TSlCa z`RsC^GDXD=KO^zsX~lco{^7eCo(ewr1^L%&Fp1L<4q%NtX2l|$J7>B7ArrNr{>PAF502 zNhgD;o@VytMrV9==*Yrb@!M$aT&l@@yk7qJD7(Rq08ha#1ItTRmg?i?CM=?K%~+SX zg&at*IyVj1z4OwdqUN;o(l*nr?? zuDDKWYnYC`t?acLRV-ANv7K8=8*p~q)DG-A*6f|+SeZB4T)Q;TXV!0p_~9qs`~Cq# zCT~LfZ#o|3#4Ngpiz=${hE>dERH{PE@=)jTRd{?_M#W~6uSZ!)E_h>RVqqb$v8PX6 z!&uF}C*>L zT|XgH)fzCM!@t`xwwP6{tDl^}^x-!Qlc{y7a%u>B89Eq(nW48+C`dQ0?bzE2s%2ri zyX+bD-4=jJPXwm*Mfb)DDekn76dch^zeloAEUxu>#(x$lo43>o70kHhwyiWp2SaRqk(?M7@da z2&ZECx4}xo+kAs-xnsw|aFX)%@<;yMH;OvOrrnJ zno&@NJj5(<7&Ydkbcyk`Ul(zs7%D6jKLIbX8bWUVS?RPMbV+Ou2ZzH$xDs|%$hqgW z%TyIB5<5n1rW(0si;?LMzz2^wU6;j$;;L--8vkFZaTP-i_N;=sxPbze4Xe5S!U8oi zSa+DDiYd!^*A4G+N8$`huxI{1jr9b^H@7=+Q1bW^w3$^!7fmgfv%`|Di;&JEqX-2v zu4M}s15s#w$uF&%9Yeurd%BDh(UB%wd0CNP*UMC-AOqL=%k9w5L~JDCB@On;d&QPH z>a4tFaoPIpub}FRU2uo#;)tZ>7p6Cbies+P5%q0 z@e$YO1Fcz3T1u`5)QeA!RXZAwI2@cLKUgqAq*bx~R;5q*N1#m(>ntRORVzcTgB7c9 zMb34?;G2Czt9CApuQ=0{fx*D80LFoU6}zH_HI3sSKPhe#!O1jIWGgKXzFFzAx99Oq zZ*i|y+;rYC5vav~TD1gb>sEC-9WVqaNQ=xW4vvF2&wRhPRjsC0wD*H2!tXy%!eF{! zPZ9dG?$_;?m0tr#_PZ8_BO6u$;3>0P(ge(v6D1yHsR`M?)ds|8UG&q<$tpXM2Cfq^ zJi&`YWwZ?7ogI~s4RJMYP*9))A3gt1OGLzDo(*Z?cXU|xC-~aaGvfMXM+V0F3UXel z)xYt3A)Zo&TTgI(1{7k(NCB%hjL7e%D^6G zo14D{s`kMlP!dW7caxN(h4$_0o$GUInjY(wh0<+yzO%B*_nwF`^vOlu^^xmM=%SKt5DcI(Shp1Pd&Oh9^Pgt__Z-pYS#n4`j zEcWSVu&n2vLlGfM>qCQ$IoZ~dcZ;bHZQ~5sIW7vOT#n5#{G?WrD<$}pK1qvlPc9tH z2njfEHD`JRtuG+`!OGum&XYLv${6-kljfYPR=Eqf~673%>Q z{s@J7^)0#Jjz-2`yLrwawJOw`rLU0#`z4OD^P6$SNxm(NY9AOiaw)P7r571jsXaA`s_fE$(xO zkvswucp*lB&Od*8o2i2RPWlq#CvEtrr+v{r@n4;@)1q|r4h@N*xLyErIlC0IDtR!A zQus}0eS6i);tSWsbE#WI!NS=P6Y|Kt$%m*|5D=knqpGrMJZOqiUjBE5jW3_$z&Hi> z^gVfE^JUahgT<+7%#u2mR1A38gM@`dCvw3ADLm9-oP6gTPn2CeguW9`p@~UVMy|_D z*Je3*yV8G}J|!w5oH4pUVkEzv3aS?%WHo<>Y|S6>ptnC`?}?E-^_=U~6$@qt>`;!&m!t=?-Vcm<3;8veGCzP1 z1kwIZ9NT$OwwHZafMw==ryIo9U>&ivbF#TK9QyzgzUpO)5gGXtFiEMGm^BMHv|&Fz z0Yxc)GLi@)63jd8?Gy7$*_c^cUi$`u+~-AM3t)YJk*!b8aai>4%ybwWvU~6wz8UWi zf*wwPV_-|@Q8V9)H6~Ps7Vr>)$Y-j^)$%P3`1ot;Nt-_B&B}$D)jxg{dkKu+>Hv$5 z1pKGpb#4@x8_4OYE;PO0gue9EGJ~P!&O=zWSwFIjZ8L}Bz|`$`x}?v0gB0Mc{}>T# z)j<^6nObLVp=Im@gium%Pe8*Iiorn8&RgD>8*%KpyIMVp5_1u-*x^E_dk z_;`FC4|CQRz&3y=dyrSd#*`!4;)LM;R%|Xy&;dtZ&Bf&1x$AK|VWF4K1d8I=eWx6` zU&CM$b)m=0Kp@Wan+OTMjoRD}-wec~wzOAOAEvzC!~_sM2FWT0(Wi2FbEgjWsBE*S zeju>#5W%7Nj1MYEYc-PlXvGL5KK8=jKq>_G4EM|zFW!W~xJ)OK-!H-244 z1HnXMS;Wd{N6e4%~C`ZVSt zs#@J#^}FUe?NpLRm;4z^9NHA5XYY8B+P6GAm!LT1ch-RSgol-IQ=xL~1?hvzzO|7q`xvxVf9-5_@$dU zVrk>0Z@u(rpEeOmYN}isEILc9|1hcH^As|x@qIY0iq)Ng$7yzcZmRyy5zpxpo+dR6 z__HL2P4}I7zkV#F$?iq^ZDUHwI1B6jp~pIQDiU#zOO)LeN8?ll3)brpRia&t_XoPf3tjhyr9@@2I7~_^6xE{C?ryfOFnH?mWlEekYyhRx zAUPqCTs)tuAo0^ay3)JfXt$6RJeGb2PPmkvk+$~Ryn8P6LZ^hT)9{*%Qc|d)mWsFz zlG}yra}Q!s%0|6}Pr`5ogjCV?fr&~k3Xv~YDnjWtKBoQC8d^TTPRE8gsqlp9V0*n! zI#b)}c9BR439P!ip8Og$8M&y?ba&b8V;!|jW`oP(Q$M+QVbxbqJ5B^lfQDB*Zmm?O zbZr4KT(TV19*b+P14xmTL}d^h#-;Z0do`Zo8ER=F!Yry>x5F4{AVs@=Vm%AgF3s+) zxUPm)9#kx?@9nI((B5IjHJ1g~Qa|37)o*;AfBn2c;hl2>syY##f{6vWre~>*ESym0 zEc!1Zq03B(9sQbQUhfmN@~_mziOs{{r_e8e9=vt2rvH=0#yb1!ToCI=Z=j6i&P2Gv zqkoih4G{BnHMu?445m^$o>QcW1YEgqsRUwdmFqhOv$C`X{;_ovnH@2S{_04>+4bo8h+EbEQ zEY8^8T`%6kr>wSc*Jc&OTyY0UwxVWj zy2}I+!rJj;e|Eg$kIL|3IW!nhZmRDj(y71n$j=_+$1oWlC|nywR;^Ntvi3o|{$9ht z&t;XEF7~5Tm7#==yBz#W8P{-SHu1(KK@M`ilk?_bWDR2;MXdxr8bb4iLCn{n%m1wAX`*$!A!J#OBC+aDo>2+qVo!LB9C~4F*Fe zWe0=ss2PY*#DQ=5zxJ(+5U!=|w9}{Ya__v*^!ONTQg$z(Z$dD4DOV!5`4$x9Q1Xl4 zHhZ5SD+_4BdXTxZ;EXJDw4J2+WSm0W>&C#(vs6LUhc9{}L==qdi950-LOA9Qm7g1h z>|ift0v-*z_AFBdFkV(9tFWZ^8j;mL4QqbIO`ql2S)*gV^{fFz8`1XfU(0YSwr)5c z1Lk^CpA&H0CIj_8D#&?@o|zspV0YqudrCxzH$a|Q{3I;o1d!g~Kw3Z=wwns1 zM(S6B%g)n=YJgWyf={QH3b7ELfAf;G6IpS4>t~BC{uM>2G`p1meD7ovBCz3Ou-Q)p zCx`Ph@qH+%$v0c1be)n(igX&y%xocWV!#c_!emvs3P5_`8LKVp7{KfcqAAb>_TCA- z;f~F3{~(HYjrt~)==jT+rpIEhwnAa>Qmx0F;1*rg^}5w@*+D)(;a4DLf^V7cHt_2Q zAMYxFbiB|@iACguE$ssjGO_KBg6GEwH&61D-V7w8dh*~z&5>dgW>e*|cQ1e2uBhjMo-{hsJMG@~HVV2}E6 zq3JYYK*&Ic31mYdDo{{#{_AR^oS$Z@Y1vNYr*A}26qi{%k0;-P3b&!d2mJ*gu#h5K zH&{I}!X1laaP+kY=+s`AgE;NHK{zmCPzyseveQ?F)|+`Hc4V`|;G|X<|MJWp$Pz2L z1+{ii{e%?IjOwo{wm;ndAq;tEXn>R>IH)y}cHWNUBVAvMhbFFQ6xp%+qU`r#y zSJ>HMu%A7tPByHHmzhO_D44|{;+_PJ;E&N!#VYXj+5GI|$ zA{uwzXXJ#fwaLDyvfBJVAsEU0DH1 z&h_K4Za+Ggwb3>`qwx|tCRO5K7GhAG6Ii8pXWbU#8j5oFg~U{M1oERNHk~X2X+qur zIzT1-nC$b(dLY-ftIZoJ*PpuNLl`d`RppsFk>ZCM4E1LQlE{X}lMJ!iq7zP->7&-` zXQ}s+*!i|>E=E17XE_d&7?hmg=`Ck}LXK#<1b`n1Ac(QPAHYbTxGZV_craJC(z3U8 z;@K!KSrQ>_Dmw&2%(p zc7CEFim%=&fhL1U4ptq#UCiq4?CYP^zbmb7zBkmj-y&D1Kv`<}5USb#y^abB(IdfR zq+^?=Yl^>?Fp7~JzMB}{_{Gh)f{|IniN@=c&-Ku_$=Q>zNzcYX@JNVt$%Wfnbjxkv z6-lh8)txq`%L(rWqr}W^T6%w#y3ShQ+EAYU`lB6%%AqPKFz-xe={a7e66yH!Zy>gq zR=`N^)=Quxh6Ke$R15LWq%+a*znRf2JPoSRuvKamrB0zzDh2<61-apz$K4f^$lCKNC1^z7V$EZ2G=>uwmxCP&&q|GUjOzh zCb#(QpSIAf*rT{gFi~aQ!PK_ry0LKmbLLL=_|F5^R_Epj9%=ivUOGSH3k9Fr2_L+9 z@w^*O+GRzi6stz(e&eq%ZrWOn0XAdtYJ@^aNxFE?&*3&54+E9$sJ|xG-!~A$L-r8= z`B|1mF84aZN49?DQR!57Uq*O;$Ma#!{Y@9XW@EkO9>J+$%hrR(p;3S2ZeQ`V zE;Fjrtvy^+&6vdKZfB-0Vcf_a{``#WUog#{Od&{ZH4BVe-rdsp=LD>}sl;MiV~D=} zj`gT`pYXx=#a7A@Fk4^<+nd{}kS^D%X1;d{#J`6PPCwvl&9Ttz=?LmdP}5A1(4J`b zF3)3f_XQhL(@&w+FQ$hH<8KKt3WJ;A6P!-ZIUJ|IzfHV&#c3t9NPTzS?4xTz!I(Q4 z?9|+29USYaXtew)ib+XtH8Fk7<aRJnEdRU8+UY8vsW(!^RAla?&n-dWkfRgaQ@0u*& z9(m*gMqxRKK6iGuNeM#MQeL_4W*}Ic_WRw^)@@==RY#C!i+8=P+MC@lb6T7>!R0~^ z>j&#zY3&K$i)cL30}rUOJ!4`{!Ll!2nE_?0>QogHgbhBm0stzgt+DDLJm}n>j)jHe zt@XLLs|~jN+umfbRXuJWna9vzpzX&y3o`Ac}#<;+>Ooy5c`n|teDw@7FyixW>(*I1vPJI}Y(tRfa)2R|wy zW&6$K7$d_;W&_c{N7Iwt>bCjLS){$80|-9(4ZsY)lXH{79Yvm7R%2_?=l0@wR5z)1 z4(4`KK2TU1!Wf5_PZOxx&xMcJ3%$+1jKgMmK}x~-;q*MEv*_+q6Dfo&jfMx}|A1wG zyz(6)PS_8ZX*EEuKfsHGkn7@lVf1SrdmcWm<-3lq_8W#3YRSj4tq!us$4F1uOy9yG z4r7stlHQYRHk^kV5$#a_e1Nj$9i$CGoy7 zYxW=6&G`KZjkuIh9n85*)zTDnNb9EqNx9F|t_8gUN{#q*3`ObCw~F}?9TKL`7w+!( zNc9B#Fma!S$p`%+-9f3uLeKT&zs3QipmwuA(3+#}g2i?4sD&N$@;f6y2sVOGUx0UE z{G>N>uj^?{5e1}?_ z=gtLBY9e3(mfe{@Qa+8bwH68R=C>PtcM+CW3s(!n$C;1w?07%1q%U6x$ON^k*T-{= z2|imqI1AIfd1VmA5@ixZ;W_X=T)RG&2!qu2@C_*Y&HOIfNQ?YR4-9{LhX#Cj(>8EXEFem%=e3UTUis#8GrUY+_x!^ z6$&{0>br`K-+z1JW?UW3ZXQr-F-*FG| z$c0qmE7Em;hyXvGMt8gY!vIO)!d3}@5CN=U=?NSDpW9$!XSo?cSq@Dgp&Fd>iH}Yi zaYO<7jKG0@U3+q!g}_SRoc&8`(dM~``klx^PQ927B23}jO zp=ztg3nwCoE_(ktHsde?+0#W)L7=TMc-4ms^}$>*(l-fE;8g6nlckoL<{Q*@h1+JL zr`Mfa47PR}P!ZSmSLpBtp@7qCK_NiF;=CBVq|Y(J zc^1B}1IUC!p{pjdxt%+ZAB6hJSXL|qM$;6%0lQ~AnoOu!C>h%Ow)Ridobzt(IoRcF z@n9UU^Qi9yoeD;@vOw5qbc-G6xoI6*^8Fh+gF!C!;`GG2(x%E|*-mz}n%%zt<0F zwuJbVGzpaNf-s~hv(CBl^cbu-P#Hf)HHAMiQ0I+K%5Bgi-fhCB!5xO5_Czq4-;`m= z3ZLZ?!N|V4QSCb2Nm$fU?FWiQeyh2%shT{EP+r>woJEgVFNW{gekl_PF0nran^x&PXruTCL>B@R-OrK%mtaMlo5SxNd5Jcq zt2ovH55KmibVOKgQtm92G&at=kr{C9Cutzp%J`k_K`4M}$%P$?g@;xPeqlD|#UeiJ zC((HhK$K{Uuo!lf>@9URUXmnAH98oJV^f$ldHw+Q^}{c8Hbe+1r8#PVnG>k-u@i~| zOH!SM+J7Z5kuRvE0NDMg$H#Rqhk+i(N(F2&ZZeXZM%o}Q|~EEGv*f#Kb7V=wFt$5pj96<3Vm6TDfKu7-hzde|C{cbkV=}ySdUkzx)}~~ z-nqBwbBUlF>`eCrnH#SBM=J{p-iki75W9lc0v2M9!Ke{!tPnlok)n!{lCIa~8L>mqSl;XEfb!#L@SYEB4rylm zbzQ4rd2w<7?*66c!gK91bEAoB;is(M7o-GmFpATj3qNIeG4fVHn1Hf<_USp%G()c+ zlymoc9);%<-~2Er$(uqZC|Kr}K$IUJ`$|$j@NwtgiM}DnuivWeue{7$IpSpcWWQU~ zDVS$u(Xpyeyz&P1Cn>(ot5vg$KP&4%1OWRIPjmJg@EZc`!XgcZryGhYOwYoY`>gDv zH`ctfB+m5LO;rzPsZrxZyb*GYujS;?_`q$+@C(!#U@$XUNZJH$1PakZ2jV}X_|$R* zH=K4i+N6|@!R7zT_6)|cRaWvhB^}ezeZUsGgI`Aqh8cFlU{yW6c(2$+A727QZhtRF z{RX&^>Wk;P^qSKq`g&I zU0kT;GdRm07x3B-C^h_YcbuSzN4=XHOrPsmncdl=$Xh^f?d@R|u-dPQT1^M=sQe#@ zk6&Uf9(h9OJ_A9hbcN|j*x(&?~euQ&)P7h)tP^W_5|YIdF|a~Ilu=^yCe zg4=i;RRmb^Fi)dN!h&Nh6}cK~L^K{Bw4pw>20*k`Q9A<|Qf-C;$5(X1_Z zL>3)CE0DM^w$YO z@Bjaeq>_o!?)hi!Lx_%;GD z)go=iRwGdT!`ChWeWNbJb198sp2A?*?;GDplstrxpF?$o$vUpz$IDt2v0tn?yNyZG z6Yf!L(V(3#b9&xh$Zik`Yx`XE;Y(lw5JJknQGLOk8hRRpQhUG6ku(he3)R{w!*c+u zVIw!R9{{CY9@zWFG`~;$f~qO_PzN%f3LYbaBCG2J=ZQN8* zG1cvyqfqJE9126vlg}H!!!GA1?N9VT9tv#(G3(kka&eADN8tRt1{M5WlpiV;_E3N^ zr6dk#2Z+o3CN0YF?5^*e9r-0+K`CPFY>wVi7g?r-z#1qW+zA@$zGBjNrUe)<5I}g_ zfT(O%kDuS(VQ;HJ-97=BF(Z#b(e|V9>T0B1BKSl43;#D^mGJ;+h~g2QrqZB}&UMH# z<#Nd4s+4dYuV{ivHJb0&EwW}~GOgKRdX4jZY7AeLu+xW!7CGaA79831N zdJpiB-gbE;*m2nkf6q0AfH~Qj4!v5)&hCwK_{?_5-yWPcCeUD@i>a~~Bgb9|{-1H% z)Q<-HFW!$V`^8xyWNyj|i2xrQg)!|rh8gu&H!p@(N%67- zx5ZYpz&)*4 z2>GHcc2$Q1(8Zk!u*|ycYwL3idmr!VYnK4) zqcu8Bu?i!9>FFsqJ^?}WOgo{UsdW5fC*!6xUKSxFkSZKvku)bGF@{5^{3Tx6S$DMJ zrk;+Fn3YzsGl7o!={G{i;EXMBgr3=Hlu#9B15Abo-yn0^09+ln?P`O+uBKzYc3OFB z;G?~hXRre)x-%69o|OkB*T0;n`Q-D>r$HgZ0aQBoz~qe%eoq2E>>oqVT>GUCkQCq=f$JMiIJY|m`4OTAn=DBA>>VG3HssiH zaD5P@c3kTPr<9xRXg>;8;yG5C%as@kAQ$-SYFA$ioCln_zt9RGgFzYQ{u(%h#Br|n zvid!Jz6}G|&XH-?Dd`}j^LfQha)D5(4nvn+)?I{cCLCHQ%ntoYyAkCFj?b<0Z%PH} zqXjx}zbBj^^)?9vDD(O62sUS)z=$??V#i$#v0mQkTspT}&g1a=TIUfpgviSt25yh4 zh;qM~gi)F$z|1 zjMC9$J1@s{3;*w_lnR+wl-oz$d*B}&uGkc^@9FL`-@Z;Ucm+awr_5bKT$6i=lLhjV z*{SQT-px!EVU=N80LXN zOwQOAdq>e$aB$Nrjw&q9B`Q}n;-hSnXD7xUi{kY0^xL;7V>#GYeo&Z25{*6-ne0#e z_S>lTD6XGBKZ8!=u2YhISJE)?k|VaVt;&G3tMemSB#{ zZ~;<|{=-icw~1s){SUuS4#6$KAV^K(9|{=5m7Vh!!^>6np&7 zXmNk#&$x@ar?-tJ{EyMnMKEyCQL4lQGi263It#VKUMHWqi1D483;*a)|AtDhmBBt- zDoUOeoZB$&fQO|0mriEoqj4q~K6j@mcIg#go8{uLr|bAosyG%@i3{s64h-~1Z>tDInOcFmd~1 zkbFWQSR_NjN-v|6cF@VKeztz;y!K~Qj!OWb9t`O&b7NxbnY&H74YTIP+?;r%zo4NlK`J zL6$}u02S}zQ9?-b8eCFMHC*Vl+;Fnd(Dt(ZNnkBZlPfy=!$Cb6T#ju>#{-@gaoFEO z&qOA<;329HoWlJTRlZQO7$QB^nxn9X{T#^OV6zP&aDU$Vi6;KT#Wg2(PW!1GA2Z+P zA{%5W+JEL1>b4WE z|C0MU4ge^>W<|SCt6>^zF?sXly#(<&lkHIwjCSb@lLs6-3dt_iY@{-hHf`v^HB76C zHeQ8XYwiAuOfm&;Qm<+|chrr))(yBR)Oc;_Ss$aC!s-hbW`A$2C+9Il3;Vt7YLb&Z z#_qAq^yJ&Jj|3>dGp@|W4Hq~FRIPWnR`S&MKeDT4NbuchAYA8=CEb>Fj+)O5Yp*%w z*{+stEc>jvioF-S`?P04Byn=(eRGcZ#Dor-u!k^^`5 zeNX{XCqgQuXP!GE&nW^SOb(a?lW3WLFx+q)sjiH_Mhh3GH_V;a@*Ro?eebTNd~)U( z8x9FkOL86`+o*Un3ubI;AP{n)v1_JYA}*?=)7xq|B$0vnfL3+Q0J}=Gw!oPE91&fr zjEq0gfanS)>Z~ld?ZRy2!a!w0<7E#{#st`FO|29K{6OExqYewSUk|WZZJlsl3EWG7 za#X7Cj-N1@CpOOOPtCYXpupxnAs^qBd^kml$fN7Mn&|DI!-^`Roq4Ihhk$vp0MrO@x(s{{7F1TZRTUKy;{UoSmscv0Nd7bbf?Sh&*-qv9A-Jw_#&!JZZL` zBZpFhMxauf*}PFTa%`w(@jW3P6q?o0+bECV{9T(V*R|2~at#1&(8?7QCfq!o9NaH8 z^CZJXp(~>(>wkckJSnwgq^^i;N(l8Zt*0U>OpxbD-S7|7c?FijKs~*pVF(pB^Yd5O z+H<0X5T7=Zkd2J7w03@*{*(!qaN8ou6o!mi63IeQLFdf%=kV z7RKdPK0EJ5_I}h;`WjuZqqDwdS^}JxfH9*tnQu!ixL;6jUrR$srs4?oebKrsm*2kM zCs!>-c}hd*NU-f{?c_%T2=(4!_N9jdZSL?|B^hnFbzquNY@9<^L`HDRNY@vlG4B_u z8j0{qLn+DX_Z5?_-VO7)9wNq}v|_ggCh_p_6(XDVsU?NHys2t+>R2M>YamE=wagUt zsAYL{#fZ5y;zarL^WICUyt#Isu~mEls%S>GlVO?

9%O0WgAbuZ2$i&Z(27Nd$Ab-%a4nHQF(ze~F!X8IMg zTAwsK-#59%=M5o z$4xjpwa`pAT4+R0ABhuZcQL{QU6sQh#98Qxo9I$x+PRjkgqj>y^X)2YpoFqM^`YF{ z_CLw;C4(BF;Ff(sr2c_E#UnTpdjY1Nuaz9$be*)v(pc{`VD=h2UzG-(0R?&&cUHn@ ztZTvP0F-iEJ%&1Bf-nw;4}qg!>r>%OuJT{9*LyY)CpkTHi%jK!H#T4IucQm96%`={ zkxFA4*s=$SUKJnkS%)tGEpYv;;$~xN#jl1SkLCDB)rY5%9^6~&b-XqX`Kv}gLtzhl z_KX61*uBVKE(H;%liU~D@;+ry>W74|WKUsBsyzrq3t7j+FjHa!7jUHOzuyzcg-Po$ zg_N&yw@?Jg1Px<%9*9^)_-!gWuLRl!rcM2)BT&$7@t#xH5Ho;yHNJh&GElji^cX5E zSX4EuJ4gPsQ2_M9QjwTQ6ey8kX_+*zvf%Y5sK<`te|Rn)pv(aZcfQ-VbwSthm_E%2 zE_9Ta3`O;W{lZX4>hoj-WSz1oPY(n@{;_fozB6_oG?8TZdps!cTpc5^7bC+-OA#pj z@+Ak>kLv3oFY1lf-Y+B{aWaypd>BtMnHBZy)Mvr8>f7f{sfUFx*ZUcD@Bg}4xcSpQ z9dtwJ5U&Co3BUd7$t!iV$bzqa6Km_5muisqAyU=)csb1gF@s*Q^P9#=KvB1j|7W*Z zVGNJ1_zVGF+-N>7Y@0srmkWS2WWDjXjxx%pq&n%T3)pS!Z9udQ;)^bVCW%v1lJy3x z$W=Pp*VR6v=7$45?{d$;($XPf1Y3E*G5FNX;cnpY&mVvp9<2KJ@6mC0Ana{nYD7Kdge2F`^2cCs$kAXf%)nGI za=j^k_K(_EBHp)PsR(b9(1Cn*SY;fC6Dmtn%r~?!jmL-YRWcC3@!qS zK+PHP)dD<~yrA~YNT$rP6ASpY2v>xCrS7?$l_PE4CToYo7m&UJa4lfEJ5Dsla`z=9 zHVTSqc~?Fw64z;=csWyGw^Bct8__XA9_na z+;ksxw>PYwttxwXJY2SaKy@*W%1T|Ax>QscuGsW0 zwLeMhRN>Y{U_d=paTe4(Bp<9{aO$h`;l~rJ5uMC*LCHjpBS?p>Z+C0iY4Hdfk-}D$GVegYK%o(q$OD z9<$da^>+Vot)Yao@WUmdr+qSFp6>x9g_y?6b|C05q2M zmO(iwlPJ7OA;>%6dYI3tO0Jnj-+?GOpB1H<4`Q^hF&KY!5HNWm3TIH?!B{?-YBpMw z-LkGKAh)<>9M=j6pY4UhS2e_Q$O?^r_|z#?j&fDU$gFD~`T=4N7pO;U>TyZ?#4FV9 zisaG6$d|KlO0!e{23pHvw26A_SJ~+_=6aCPl#sSWr>h>>p=?NZy7F0{d(Z^G?ZZW) zrJ!(SOcg-ii<)!M5f&Sw+5i~I@jpSORL(D7s&kq+YNx?7wARV`AbdpqTd{PeJ@Uuh7R-GbvhATh9m5^td<`@Jk#u%Yja<>ymxfOID?9I=kJSFpnHNH1``5Hd>hBi&cT94g%%@>VL?b(=d- z0oO%^>`DKD!DTa%c5zUX1OjT`=~yy&bMNk8E%v4h+Pa1~8t>kVw2XJ#vD)j6hjbCe z0UHKp(73ALIF(D-lT=I#6>nx}!`me>!36slP}0i55HuYD>-##F`>snD`mXeJ{56_) zVuwAhCp6BhnaKaaa{vwvti_v{9zW*=w_@<^b`##PCrrwr)O~QK3qacTy_b?qf?c@{ z+0O|g>>v0XE%cW*8w5;umTgDVg#cv_hU9bYCV;65H*GCG^wn%#eM?IKKGOqR_(wg* zE+|OjMp=wQ#}2{s06SzhKnJ)??2C;5R^NXJGgT0pgn-tNrXZ>qj>Xa%b!U{wTo3hK z15xaeoLF~SB~h^~IqlY$S2X^aP11kogv8_c_}+9P(I^LYY5wq`z^dl@y1M3^vA8Mm zSQ6UL`vze~$^U9XfL%Q`ih&vGHkcej)@t0zA8M-9)GHCcO%Mynrl#Y(8-@pjBJsL>ZVmHMU-zYcF?QjU6tuSN&_U-5NR zpFpk*&BP(%=Qt4?hx|Jd&^m~BngQ@LpQx20mDruQvg?14vo~*9d&|S!5?p9E(6@R5 z$meQ)T(Ft#lhXwE>~8j(YOHVsdajLEPK^?v@NXN5pgD7=n(8MotH~!~lE=cSuYt1y zb{NR`@^`q=!gaPGmSS!RTtqW8^OQ#K<0;dgiUPJIi%fZcw(sD95&PKTj3v|^U}S$| zJ(}m$mD7O4xeJJAuq#RRP1;rPC6QYOXa6L9Ky7Mmbi zPS|AcUg1oqYU9f!p{s?E(EZJ~!0OV$1~==prfUUBT?o#(ptEEedq4NCZ6Dm4c@<%j z3uTkQi$M3__z0v~c!wv*>d*S5oA=6rAzi-%SYE7&A)l1KAq?y>Tbzhb6l3O10DjN= zEWJm*mL9V)7@&oSaNl(dxZoFc;`PqoyAq56JlV~nE_?|~z)4^^e8S}yB_*Kl%iY+< zqQhzI2xy6Td74bmeQN`Ll>FycBbwaJnqu{0?lm4f`?QBLFxocVh?ecp9~k zVf~TV9JN~g5tZ+`*hj;h9{&-LiLs;dy~^EutQB#cQ*x-BiH6`OKs3@}Lp9r2!j$|` zMSN(^oBUHDIanNvXiOz^mpjastIaY&T&V=K+pS&u!&!sruRg26BehPo07Qd{0knL< zld_n95e@Jd%t2b`zN_$tfp9C)WNViY#i=Fg5qOr(dDV2UBn6><8HX*Gb)v7QBG2!! zmDS>!#Mt|2dd^ubtOd^ULri3*($c(!nA5>ZG05tI*<4f#2nZl;YNoHQoC}1T~Syz4bp4U-S!!#b*z&q906we-c=F-|(H|Beq=-aZO zArRnc+Was(@~KS!uipPow*bWe{T$pgErqNK0grln*q;e?8FW7po|noUvT_s67G8K<2~v4%YOGS%y!H3jp&8V1 zp_84`)PLuPfgMmbaK%`VT^H-%%;)8IeY6rlRluIgkgnE>zJ?o9?jgc*=U9PQOkZux zhj{nqHF?cAZ~`UpElW(VyvmS1w6 zu{SiaYVg@>emp?P_+Gt1;l{hNvMqa~yQw$C;!Ar~9Vx)Frd|5$(P6EOald+c4C>ux zw2yv*JSO)W>Wnj5>iSQtuxC@I;Vab6`9I2HzI18#U*Zd<_t9OligVn3$l{m&a0BRL z{Hv!j80kbgUU~XVIU(x1;G@=z>C{^CxIC($5=-15J?e`?UyqJklLBr7?gB3Qn?nKL zV|gXhkOx8vumin(<{VjC@UC}JFQnNpn3nWIUydfc%IP|%04#Gl;Rx2^vo2++@d1e= zR3L6j8*KBDKa$EWDE;B{Q0%tE){IgQ2HL~fILKB9e@)*Uy-^9sWpJ`4vcUtQzjur6 zUFoRmHaU&l(;<0tYxrXuV4u_)vxEAaz;#fOq~eunE-w2SEaX;!StvyYSl#;g$&8Eo zTSzay|A1mr5HUc(pz3bHZ+U^o2@FqILM2kBI2i=IJw2pNXg(~*&610^S`E(33o$;- zW}gPJ7cGW-JyZAImKzWkpZOHe44+b7vAxJt33MDZd0G5_FfiO(hcX4{v*tU>2%3|% zpSn~9xggY58}fN=R>+g2nSO~8EIHikk>o>$45nCYn5oqUfZ%_a@ATSQ6H?&#;gqeH)ieH&KqNC;6GMHi$Y*i=m6__U zX7}-yCPZ|Q1j)|TR_~W$`v^{6{H$wxQgh;G@P$+A4#Wp82Cs{LSFtHusYyD~^<6eu zu`P(%&3+1S06rjrC66+cgDQNNf`6yTia&}-TzmD>+w4m%`%AnXC|Cr74I}t$>3Z*| zb#Yq;ylL-!FCa{*ewqHJN&xU`mZg@x*3(mN!vElK|139mXAE$2V%T{iNvtYSBayN& zPNOQdtp&7GlZA3%_2eh=+AUxLv&=zHcO!(Wq{jCtQiEr8Q`sP_z5P+ZI4T+^=jiD! zNZ}!U_d654QYr1r3W}G{%@w6R!;id*%+-~T3WoLb0!~rlXtrMg{0!6;n4HR`c^Q&j zG}V^@D1$PX;50~4)9v@KVf$T=F>`nlcrn3Q1o&5$O8eb_n_R}3XQ^``IvB8a@rOHx zssYxDOAFq7FJB!@OI5fxhrhxI0_x!0hn0N)E|U=OD786|_{*)Wm4cFNSf(tC9hh9A zS{wBP6Na&izqhvNTbvkj4jO*#6T0hw1_bgx>=L zR41)xhYll(%~I4IT_kn6DaCxp3Jb?AcP9rrJ*Sd9njSblV8rF9>&9JXA_{Lv>AYvQ zHze_@cDs>(tkV2wl4xp&dzAaC+fV*dKYC!Ep^M|-xF9EBaN1L0n+7Go8{~kZcY$Dr z7Ba0YRS@K+d81lizr)5(b!M9HQbHHHpO#0y{uhu+Gbxxvb4VT9W9RYC?qmNxU9BPP z*(_QO&v*Sny@i%E0Hk!`!_||k$diVMSId`ZM(Mhq93PHOOl&vYbanI)-$Hheh|yn9 zxOKd><2i8;BidQ*ln=QILZI&@SawWJ6(qV}TBj)hxJc-x90C}*$r;9=(==q-I$2Y* z83^Iz4lC1u4|Pa495@9 z?9=uq6C=~lwBx!Y?g2~lNE}G6B^KIxM>^V)(GNTEwDWt#*nNj0)H>aXm%M zdsoJ~+A>BO`~(Dtq1fOsZGbEqOoP^jc{@0$t1eFD0?gQ$E4`(W_z|g1Lmnh=KlXxq zqn-bkH%lv61{^SQzg!qHpFBj-jTW`|Lo8t^#I@tW>?4?(3GoH^bl->=@rdvQ<(zSu z4mS0ncMhl~`a68A5;LXQZ2=aEJXfGfk_0|{%psVhiNls|TE?X*pZF3@rM2!$9NzOqjkisuTC1N@?xills|0STqd!|8u!d3yi#O_}O$$W68)#Di4 zCCpbW|0&4Qvj5@eJ+T5f`v~P^l+nZBY)ZxEL-DYx;L=Qz{$04OF>CJ^`BTY>Z4U>M z^L6E_cZRD&-NWYkk-K10DD@Z6DVwNJS%-xdXxXVV3!kl52vj>5zC5TDl6xzMmrrpgrk&g>bO9J8 z7%U-?axtjz=?X}y(?qOznywfEt6yj4>h#H{yE+_DJZaRp_$?Tdw-0Od$v2X*3@{mR z3i-|pr@KO6pW*?$i3QX<0G-N-orLi)OS7^|aLU?Uc0wOY>Pi$PC!<3u? zm6q}LOpy5*RhpenJM0qG3VK6dA1r{^pyu~g-G}4kPg1avsG4)?(Oy#-sGS02iP5PX z+y!#bb~@9H0Kl^lfxJ>*MZK_pFBE{|^hbt#8PXSl2B*f_xLznCGAJSZ?Z-BtvZt|B zHpo|w*NltY0X_*nEfmdE6ew`5i+MpqFb8|et{R!a%8`~KNW4P!5X`Ol-?^m;;ylj+ z9bIGwHgBfuJz-Z@)!6k{8$*`R>uW(@hP7JSW-&MI5;pwcPc8)9ltAbmQ{#f^!;7f?`9@B8{FG$12m2YZ zEGnw_>L$Ye*m9VtNA7p9i`afoRN`9ihqJswKcJ}g!)Yi9BZtTbj{P8Es94JBT}DV@ zEhj}Lt2!V9!O(N&muZ5QlN`e!0tWKWFbm7b1|t_b3uFY5(dT_4p&x=|Nq9u#ukX^KTOP6|r~;^v5;$l$-@#X>T5S5? zE1rYNoVi8K?Gg<1McegoVhme-17aRtkh+(;6@K&=8U&nF; z%RlOtr-Su!va=RHPUgfW@UXH-&ie0z1AwjypQJ_%v>$>!Kv^XWaY@RSS=`yZ-=HVL z-UMcYWCYcGc%=2A8AwLVc0!L(lK^FFP24r+$=C-jNb^dO^WMB0gRNH2SyVh(%hq$m z7Vw{P1HT6;1-#!~0pZf7zP_@{+l}Mbp(nt!^uQ7VY&L~ge+;5YABXE;p5RL{FB=Ww zPT4BwL4*4{xoRNY11%mFKrZh3vO_rFR4*F->V@<&*iO54$0n*hN6jSoCoguqa2Iy4 zNMC`eS-~a}3oTt=L7ai$qsM7tvDourM7ThG>7W;%Rx-3`X^SO~D+IZW{)|EF&wNQ2 z|Jn@as#^z?RD(J5$Geid2G~;DrP?|RfVP9e%tBL6@E#y6nIyscUHkIn1Ofe z6}DKPVKEg=H*vN0xF9zjl%1JD&A@P%_^hzVLqVaJ1sr1NDf<$=sHy0>3BcvIsPY?z ziwhXX749@!T_~jwsySoi2$*&V8vq~wL}LH`k|(zK2S%8;B{(VH`54S5bzHW>NfEiG1E5=E%*(=v%-*C#8T+2}7N7~BD$;C@D+me%5 zm&fe(SG&QDBkd%RN&iQ17Uej{*9=1qbjJ z0Ifor_b*(9g&3luBO0#N?)b=nFHyhB7T7&Yc51udB!B|CL6^DAsdPa)QmokTss4Sa zi=CZ)TQ2M#K=Bv^ZerS${zi)i+2Z=fKU(!$?d>1&hmzu1Lpg0aQ}ckJ!0M*dPC

f$3uc4a3n(dTw)Bu>Ux^>D0P*p0mE(d8tc(*jKhg#s` zsQ@|DD^pDYtbFh9g3j^&(apDa5*cL4CYwP)*0{FH*{rIJ+1U8x1oCv1FG9k}d1til zMP-0eieK;FfM#K7k_ap^w02N4^)yv|@_3j90*scB{^%UF%3>Gx!`Z;m_X1%<429V` zoHC$q325N4I6eH?xb!z~pGp+P-wtqSCCc4Czjp&zht0RYtm?hKS9HIf+sn%cuwmILl-5LC=MN$r{okEuwv~SBj75Jw1_HNLJ9ir>+HPoWt3TPmh zeh36>Md8Yj=#o8^yB(zX>>@+3jQa4~9YaB9*-N&HIycWoE$0Sr-a8*_I5FP8=djzk zGgjc};ch*fkdVpWHgwf>=Xh-e*zszI<|6(|ALH88IZ#v{n!36PPJD|)8JUDA+Oa!h zT9~J@W16QLZW3L9AaUeE9#U>Q76l~*Cn=X>QGpv3>bwuY$m9RXR5c0ZK5C9=?h2SB z3WOvQW*B*`Kt z_Q5=FA0A~7>KO$U_eM0Y`$Sv-dIm3~r2R0S4mrxnM7INHn*xSc>gv#$@k*f+hx4gT zmHs=rQ)~I97qI$VMt|OY8i6&GRO)xr6`v*u*)+Pzpk&0an4=ncb`rw&~}A>4+T>sT=`V|kL{eNB451#vs`yq%zw48?ATiJ zIuyy<^{p@`XOsB@^o-cjRZ6vgtQjw7*Q zs^UYy+-l7!`XhI*p$QXg6f zt1BfvyjHnC2>wD@Ro;(5g}uQJdg}ik^uNpOre@sSp3pZ{F-FKIzm){j%%lTXBNm8A z?p%xj&A_NH%4U*@&8ard7FnAwZ%sQNjhoAW*`Jgy`%*&us-qEr%rYi)^{*&!pC@#Y z4Ue&d+Z^Sa&rgL`O89-KC>|%nDx5K6C2p zddHeO5Ku!+F8JH-O#g$u+lQ$q;AB&^Ir;RCN4Q@OSQghud{sy>O-6PKfQZt=^GT96I_eLDL`u3@I4!Duc`*mNX1*$~%lD{sia#Lx6q1$+;V(6vUev?WmXTHFaGjN-usWJlRvw?{ znLVd`t491K*(=p*#(3?+=)M)Gk9A9IqWOcj0@%1xB(8N8`16NP_$WaTa*f`=j=j?L zCm3#7g~P`Vg)JaY@CyduCk+RS&w<$O25|Xrjny)oE^#8upCtw&TreeiUhPm?{X(d; z1UtO`3ebZnDOjDLx~Z@+ z{t~uDKKn+uJNRj^LET0NFB+aR%T<-UWtH;8)8H6Wb7*ItQ<@tJHPth$@Gf8@$aC-O zp?lXgXg&(YT95&p#wWWch1a3Cw@Y7VkjmY`igve3YRy%mqsGi>iPgjSQ}wmW_#<7g zB2&r`uyeDPERx0PS+~7&_C+R3bv+Pn!|J~F0DTqG(KY+6LLmDEgX=B;Gui}&;1@^VSxYPJy=YUHCxxPhdgIC@52{Vi^U;`75N zP9_e;?zpL>{Q~L4vQo>lG+)2{zKbzM!IwqekfPSB z7%s>%^3WqRZh2Q1TxT-80-h>Y#!mk%=)vWk3sCp6|3Bu{ly2#r6xsHwU(t2Ycme$? zvodSwOJHaw>)P0c49%S?GaL&nbbY;@AFc;?d4zl)@$zR4W|{HIjNbB@aTw=fmIYhw zmp>l+Pn>~EY?xs7N~d)Lc4==zeTAW9pN@I5egbacy1Zd+>hpWfG!wj?WPwjF$rV?} zv>wm9*}IYyfI}5O!ftA?C_(OH@&GKQ+2J=^ai3X>cSi@PKkg4EXR1ey#5$ox(MUEV z)fMPsYNVAlTTq^1OZbvxmT~!B!B7h~>9PMX`pbv7(j3`R&DHISZ_m+N>qJ-@-DdKL$EwVqp6M+%QNQcsB+MMt68jM$ zgU^$`%o%hSKl(Ed2XMJCQ|C<^jwlR56e zkPPs?gGqJ$5vh@Fw}2U zBqA#Dh-ch**laX}yB`}%3&){snI6W|AThagYg7A5WUgv+7Wd7wvY z_(Csd+~hB^M-$sDanHDYYK{^JbJ1DYrMI!_FE^Hoa*x&iEHJk0i|+rtG4<)qysT8z zC5Pg+(x4w%ZyjrfciXi;Bhbe_rD9{&xHo-l*60jvOAW;8qbmKmxwk95ID`C)N1ToD z<6kE~x6RkI;Sij&E#B9Ny4c1ahd85@*mc}OG0p71^YlL;=;dDzS@c0C-%`U=pJs5X z;%T0S@^F4e;6e6XV9b-J&F6a^|>-LXX$7CY8snt%}%x%aO+69%fgQt$7|$0 zoc9;S`q^iaQcjL$T32zO2Us(A35WPgEw~LIr^lgiOTEV(5X3M1Xi&keM;ori<>e1Y zto+urWZCLI9=10JuuE>n{RUN3nSb0~`%8LxZw*sQnqNTk?B8`4zulD^w;{lh`>2!O z=@|5IYP%jo7wYgFo#b)rM${N6ih{w>y^aOVv*j^mYke&u`(gK{f5$7ZOJzTg7Jbb- zMr|Q?I8WB%o=6IGIblPzY*Bu=IHYgNX)uY~U7~PfnX}wBR-ykY$-Z`DwnM zvg?N}e}L5yYW@KbRx&rvWOO{`E})ucj~%V#zysc9B%8;5=;W+1Ls!haO0bSyW@*_c z?7c0MWQ5#GwdEzmbE&@cwEk-~W3Jgi1mQ#cz5$b;y!ye2ky!=|9UQCufRfth%MG{oc&ETCK${HVYf>=|61FSRlUemdR>;rbt0kbPw5haJg;jl%vK|R!a<; z1j~Yf@p&-)qsiC2CWVQY`-*8I*4sN)PSZ7@9S(0i1W$s&gq8kyP?1S|Mt-HZ2P_3e z_AB`UK}z^Ml=2L%^qJC(ZHpT4NE)XERZz1B<9Q!kMV7qX|KA`E!e4`e93@gm8DbFR zUBlm?PjodK^k8D->3w-##l~_)Lr8ccUpIFX%>UP3f~W-Addq<=o!nzXDwrlE&aXx-b;E2ymdK)_dNhJJrN|fiix@oo(2HXU*9iM z7JRqmVz0SXFdDb@Y`JU=b5uHyBaR#cd(7K(<)=@iA=hgE$zTp{ClebeV-9{D?{z%u zy<}(@1{B8GYNpV05;F}&DzJiiC?Zxi1AltTj?oXre#2;jpoi5mMm(3>LC4k=p}B7_@3l9F@I-?o~F+b;53%YOnof> z@Prj<&h+-P0(UOAq_8d$^;saFC`FVbW{AgdeCWtmVs`H4>UL88fC}@3zeD!O!pEMU zX^L$#D@Pk0BXNpoQnxdB!*pYA9#zZXslopO#s73ZB^^YDzmkeUWN7cY`@H%MKzQ&~ z{{)=)TeC|5b=BdZ{13Dq=M^+Gx>`^D#9JMaSiJ^1I4NhJVlb490#2(g#*Ka`@*BpL zUK~#++c5mgz+k+IUJgs1ISV@?EU)`f!{mptW#i!?U#<>=j{Wpi@2k{R>&OZxPrn*t zlS>GAk$Agz$*$dqs3PNF4^Qr_B6x5lj+DjHuDmuP_#?!VyDzAut zsOm+7=ZGj6*vPBd8kO-|nV^?hE~ORJ$^$&;Wr{r{gF|j^wDQRRdn*n zyebg_Em5b<>t zR_yh%ffX%9tW=1NyEm&g{xonT!RCwBa{dMjcz51cy|^Ga(&%;t#LcrA{jhkMV|vl& zl{pMdeiWBYOBmGSiy(Wh$?*RHC!u{HT#ul`l$%5_Bz~f7Pt-R-FYV2|cmH(t zv7;9A17|+S#%8!ae?=DL^nucK8&N*I>sC_2wfv=2=7=h$LpT)%XCItr7SkwWYRTPyIOC?2?@~OF&q+I!qx<iKua6U* z5?q5Me*^PRaipk1R7G<5Wz!cu8UyH8<(bi(>c$t_sRNs!zT9qJ@Uq+ewu-jaof;~3 zY=Rgy$QZ}p2k1HmI<}%J)Eb21FE&IoRH8C?OP@S})P+`DYp|i_yMoR1+Rvo)A!Ead z2T}o96KH0Qhf!J-M2;Ms9G9Bwf(2kTBaTO{j?E`!$Kjr1_P@=Rsp?;BqN(h4f#i-e zP2CoIOslN!MOb0)vi*x&B_wy=L-cH@YHc}f(wxrJH%;d0U&6Fue;5)|w!CD2afkBb zCc;+sO!RiwaDLQ!_60lBnZ|~yc_B2s?0~{9xJbJe`A1wkKA? zAwAGF1(L|a_*p}g`FxWyI4dKjh-1Tj1pf>`f5eu`Bn~1JiugQ<9pGSpFvQ!szw+nv zkWEdC3Se@5cb~05t>VcaE@-M(?{A+@v_C_>2I*|}(oN9kDvB6ERzmYUa>}q7+v1Y# zQGV;W5Py^Fp;|g7gNDYEpRZqlqc?r%j(a_O4g49#H>Ov~uxkIwnshJ>1+;ad`m~EQ zpEZWxoSFVuwlYH&`2^R4$pJ?bp_4CE(g3^Ma>^Wi?ExsRv$0=Ks*>1Rht}t36{L^w z=eB<%5+~Ve#~2i+g4qcR(mY*zHZDc%%NM{rFj*yY#LZGTcrUw-pywzml2zEQ$h|N0 z-L(2(tP2heelB_Nb>g)YI2Ye}Z(!s!_+Gm9C-{bykq4uVAE@7@ZAHUbHScaAV4oDB zz!%1|y%APCXlM`=wrM@}KZG;GP#g^53S{WXwnH9?x%vkH7i!iY=QtjZL=nk9lhOVQEYM zt|%WRe`d#oSY8z$cIDU@RRa}*QeT!&l)II?btwBdj=k9bqYZcPJh^<2VsJWXSKJ`8 z`l83C1~Sh2IkTNtrJ!5fyxpm-a_4Tv0IHyIsK`1Wv;wPBqN=&Kk&)_~dL6tgkoFqG zPOb-=RXUlAmRF%1ONN(|tBU*Qi#=w8F^@2D zYX7m43q>cZfv7`m%-`OTr5iUEgs1$)I-%(ZG;hw{kYm2Dp{#QaQ{L#1{sC6Ho* z1KIQ{htykj7G~lmhPv8@&7{{-F6x-n%#?RncXEX-GH_nP=y{fx72F_%SMMgB9K}s_ z)$F1Eqb&cf=2Zl_e(A@o$n=LbF zo3O1!{Rgb};2a;hzBzX~$Kqj%jpUAUU!UBX%;s-Yc7?ygoD_X84i)i@H-V7b<08P^UccCzMP45-*L3?h}Za{+i;{u$y{)irib5S;QrGV$lrsJ0o9{7-4=YVxE!A9VVjM1V;9DfhkTNtdBnmc22PLVbj)YG*Br(<|zfIK~FjaA9 zpnONXeK5MfB$5Gyi1$Aq;)E&ylxbYb{*UQ^hcq-y6(p)%!4e|@};P{sCsO;s_e(AJMyqPaHsdbjJ(1-37-KO2tW*;1+?(d z>fYB~!-*~sszt`+ggM3x`=Rr*swO5JiigFKh1OnPmL- zW5X26pWG)_%KdsECgm}ov7H=d9gFx%7!ml&@c~ksZQusnZwFC(kmOmvdg4-b(%JRf zi@5#)4|Nvc=DUAFUrbd{^+w#??4`ZrMGwE?;Dm4yt}t@F`7~hwJu4GmMI(dv6&iAm zhRGwL*w|hUB!(ljhX74!?n0WiE}~*Vh;{VS2>tUX1ua6{fH4Orz=ezFV(z zWMpJ4*~*C05LtfbUTRWmlBOXZ4}I!EL*X8#^hoV!zVZ+BPx%|4Gu^w@_M)x^BqyhB z`xlR5wI8WM1)A|(mj+F}i2Z2Q_n zLq>x{v4g}x5T)iTQcxy`*u`|XvOE9Gj&|Olif9VDNBbELsjS?i!vtpY1?^Z=b)Q4R z7&f^2U~<|Uy!U-e$9ibafHce4eNiwmCnm6+mGj>}SJn_6t&Vz3_#6uI z6Gy#4k+-w36n4M)7ThMp-TdY<(w_XzHT$36MA*(yJsUDw60DT1QzsU}b>!5_A$|mw`V(BV0&V^%)+b+}!@j=m~4^yTY>l>u|_;msdgPj`+W%j3&f*T)oQD-3?9SQ`6bTSf)^Q*S5c?=nHb&xU*xHP&*n6Ug( zEMMyMs1@5iqwI$6YPaT(Nk*-lupBq~aC-zV+lDpiDhRH>A}EWmO21Ey4`f2d;2 zR55wU){j(UnRo7a(Niw(%r*_%7S$ArCX|eYecSsU(`v9E)DosqsOMX9*TGh8d_*{8 zIXGraqq4=ZCO^#Eyu8HgR?oq#QjxJoDlv>lXz@xby28(a`F^FF(QeRsW~ZY==ew&?r5inh}6CZ#(8N=ds{;?Iw3wKC1|Hl$E!IVr23oJMYwi@M z$j7tjD)5sS{F5=r2XI`wEDvqS}GPj((6eP%^ixUi8|7)!jE{Mg&pKRVsPWR8PzYBbu~| zbIQUaW4o-_0vFp6!;7*bqFuQH#g3NgZvYVIxh}b0=rdgx;t-tbHFxh6DLx52Q;ESA ziTt3GOU)G$On*ng~1sO=_KIke_hq@PuCF& zH%HX0|Hg<$@9PR`v1J)`PMU_z*X@cEudzz6e!RkjzPK_dP(pED9yXmdW{ZF_NmmJn zeBW!2c^rH5#-V+jjdDw9<5UBR@>aT1-i36HZ`z!N!a1Jw6#t{{y{B{m=(?)Zh3ss< z<(BM&;YF7Z?p_G97gupB5pMknGcAi+jL{8Gogb_&yK#z_b`|6o44}Aa)*k!9Oi4L1 zTVhEoK(r&Fo!6PS{KZM}nRB@wx0V&xzyQ}uH15Rb&6)mRHE1fy=Qy~%KI0h7-t$)` zw8C^1cd&evv@Xjh^l2qVb-zl~OVassjcyk!z#Z9ww;gvYVlTq3mZ@ek5VL~*UaU3D zt`aO-Jy2o_su5?-E%cVuNfEuGxY<12PBQVD+aKeKi-ihGkd122#q5lo-A-{QD9o@X zpd#s?=}?@@)DQC>xX+vAg4j6NszKuqF(lBSE~ao6iha^FEA{t6)Rb2k7F&Y*I+k2) zQ(RD8A7rJGOXNbz9i)t3MH1e<%K<|VeCbtVX=XcND;cdmb%CdD99&&8mFhpci(MWV z%;>|PrP@;AN@~0Rv|7Wknddu0WE?QMh&Pq~pvL@SJcDw_2vDl4F8dq5T9=kE3&xm) zKbqH@8Q!d!snXEREoFKgj2zZ9*tsj)cy>a{X*JjIdsi&7mUUo2hl{=5?1zPGc~-k| ztv(y6`0n8YF-G_3=-xmLOBeIysdB@j674tmFrHAMUXU?daUl_x(9G&I9Inwzh&(s# z{mgeb-hSnlYu^_p&Qgu|4?jLPcsDH`8(+ zA0CpS+#VFDy|$`$Fdr%ETfbyF_b6V@+~+3_^AAg^?b-e1MmMOc1m2mwQi*Z#N*~>x zst9XDHkSuZuWwC9G+D3if0=}g>K*}?s35(I0M%7z zP>bKzrNRTY*gXgve9C8H;~IQcFv~2pdnMfjqAg2HnGXy`#|3O>>u`M0q-y7WgwQBE zub8G7B$a{ygeQ;fu)t(N?q9`oz%-;bQAnNKdI<3_YtK|tMQMd=HXI4Jd^jjJ_z`Hw z0+R~Qg0azI9{D7UeF#6EPHs$2PX#-$vF)V6js4p*uKiZkD;R#5X&FOzxWK#mCqYS* z3qdlLvocIUXQNE1Eu$Gyxpjppsp7~)!Z)2iiI*F<&oD9K@QBxJ1tRTFFd2LIPTHRT zb`)}d90mOA7fr+6$Xbs%>8iNosft}pQ*H3n(^a~byj}rHP=s++X5Wm}zORH>9%kOU z?#P4JSO$i0@%>^An%g6%tib(ei{4=ovzZOX(|5WX*#uzfv*?f@ z{J9_X**WSu!C}@|%Z*qjEk zvqQ)x+3Oewnb|9Q?{VzC{a)v&`*VN4pYQMe&wW20d2qd7uWLN7=QZBiM=ZMFLJhYHC=^IroUIu%zqi;MTluSgO^a7so8dUv`F#?E^T z_FtAQ(2@?oUye0;2{cQ3cJU-L+{S51?d%MdRz<}ujc;Xf$?P#5CZ!Dx(fP6W!4>u}w5@13 z%TSDLI_+hw>X^W_!-x1f5^hs^d#kJ@m<3mmQO>OD>>P|2vy(KrNvmv>hFGm#d#%y0 z7-iNIfkTi)7n)_x7S@0Diy2p%$z|tngC< z7UE%+#+-MdEwionK2p7X9K*syFmo?g?+(ZZKL5Ja5>s%rTQ!00M9w_#Kz-BQ+L&fe z?%3FMV=JBrGfvHKZMf=4vH!E5pw}fk%(tKvr3LoUxaTES2U<85BP?E6YtDm7o(#@x zZB=anZkDSMozLdlx(JU-zp(zU*Sy?|GX=L-LUXe?-$3mt zB=MmrtDm`8W|&r(p>}^Y^5Su+tCMp|k&SyiU4wo_=A)KjKUGPHf5cwJ$;n2?>J?10 zC`3q^=`UP~?YfqtQo&wte-bG+AjfOpDm|P*{LKOH;8;|Xp!$o{u=zb>Y(^sEXXx(G z4;h-{zHJ4zdG5M-yE}p|Wygaq0w8Lk-*spViJn_4X8jqdlyE+;9#*Ecr|6bKtQ zXDP4_N0j|gi~VZ$8)X{M_83S}U2UA!^;vk2F(=71KV_+T_l?@k^?AH{1(-B}9*yKf z`HWZ0ArR;bOyeO0uJuxG~l&XOV|HE?2vl-8VBIj~dHVJG9^nuUfea+;G!0f1W8F~eH zReD&5Y>ts_mq`>g?~-rtVv*U+%7F_|-T#)EK88+}Y2B5$|7xHHm(d%i#$>14LTfX& zs`pAiIMT@^-2>nMpnI{EIz|{LrkQaE&_5ogq2YYLyO4zdd=$+r zJ_;dUjy6@2K{HmCxdO74Nhf_@qRgy-$48ByV$x-t2k@$)|7EFGE8P;UO0&F-+2jw* zkBl4Xj7{QhZNH?6d6f+DUvUzjdWX)T{Y$b6w({~hNsZ>HgJ}0gnbCzGh*&!SMs^j4 z+2!8u{D!;Q@#S`>GUdJLM*jDelQ@gk6a-?Tf<-M2LVrc>A>TTkM5U-2gWrV{dUvtC z{&_}O84_fOu4%`jMS}w>M0JcFh+8e{2WF`cuD~~P6?OK0YM(h*tRSnH(5VgNnv3 z$##E|&6c?c^4cIBUhg1jR@PS+=k8B7^}{bJJHP%=BI)0eOnLRyTq%v)BvP4Aj}ijK zH8#1X&&`yR#OzB%!prJPN>u;GUW9-)>t$4F1#-Pk3eK_FMF<*HS##>yPKGScYnBUS ze?9udQi@dGJ{Rc4P*T4b%d=2~FAN`Rp2asVkXNR7DiIEW5Juma$3M&-7;fnqwS@ml*R^?oNl`O&%Ur$%h>Bt)_I|YjwHy4b2By>Eicl~Grp!>>2i{9E(X0zY2MteiByN^N&NxF_-s7KhmJ>@9d-OwTavol z?=VC+0(6gGR;P){kVtqG9pHQyEjD15(emniDnzO0Il)+21#RiuTLr1aSIdw+$20eI=2-`c6p=A9kLlApo-=$L5uG1d z{n7LH>qmCbNy~mJ(D)xLZS_kBkF1?n>umS5(fR}#AFio!{oOA3^x>Z1d_j~=9#27j z5zKmMVY6ab!pX+Xg*QXujg^ediguN&t~@9Mb}DB{m?$j7RYvru1apQF1;%aGeZ=S8 zr`kLaZvQ>d71~Cs#;g5a>H@sucvbn0`Ob@t1i8~n%sKztI30C;QILho*aIJe5cFYx zYw0s>+Zy&m(Q)KHybC02P}Or{Qi`0L>K^Q|Udj`nn)D9Dl87aPc*V z|5p$m4O|iuaN(NThc*4h9v+Gn^B<^#VhBfR{v7vTHv%V(5Dk&i`(WNJHPa+cR#@w4SK!y`*!g-oL3K1*a60Z4)X9)GfUfA8=h`B&P)mh*4IBzKp(Ua zj^>ks>)ZhYJmH4f<%OrM-9Nf!hYj#kvRt_y(fIsSj2esV<7NY+L^`5TxT4|)cqsuZ zo}e=?1lua%w@F_~eh8RzAtH(syHc%h1jt zlz7dhv78xV+GbPORqzffa2kao@1Z-jx6$AgD!+25WEL0e=a)7=Rnx6#JyYp|2`v!K z-2m|_GPbk9F10kNj3?!<8GF@tvfkgAQ}+!mKn>%E?%;IFX6R(AWIr|~e-50rTd>zt z7j#H$w|H5f4}=zua<%4PQdbOt22X2Oex571-6#mDtgWf3cU+6L^wCBhtzp=pcj%*m z{D%$Vt8!&k46bpM*Jwnvh(?D4ih)d05fA&x10m&mylE5!n+M-E-UU)D0r4-c?98gD zNBiN+#rxX&$?-Yl(4l`>C$D(bvC#4IQM{6cx>AKU=vte?9TFpug%;4N-AA6s7p$-X@XN zBg!FIAdkKSmP;_vY`)pSvD(~@Is7c8q`2_Qkm^sdL4I)A@5Hu8$q;2nNIPjk>RwRb zl;~?*h^yS$O8J@l@#ct!zxH9#_#X&M@|PcgOiNi)x+>l@mdESl9i-zcybP_{3gCRq z?Fu*lZDQK&52itM^Xy>)N)dBYt;f@79l3;Y9N0@!-NNWZ!GFa0#kqUva)XPOD%cb5 zUT0J?QsR#2V7h$~0_C7*>?{pnS|g**7R&gYneC@bM<+?&TwlTV0)n`U4lEpd0cTL^ z!9tY|mXC4@Tk-mT1}{E9a~}SUo3p{;B0HsU0P^ zmfDp@6)x?!vjtK4beG5LL`(DY9)J~~^3#_cdFb0_K5z7_8t&_Yxpv7>jgDu}<8JUkFi zG8o5hkQlOHYN1>YqQ6l+X4XrN!T@y0@(bYfxZ+g((Mqit#D9}e&<-;%1YuA9SArm( zGoJb6sf*KeREnFJldFMruk^6rNeJ|Po>b!J_;d>{E;cz3b9C$gthOb+>gm%4dbE@s zuCs;>wH-z@Nz@7irZl&ULgl_*ocPY?xUJ9U21q~UwbP@GB+ClvJLne?YWycT@aL(w zUypt0bJU#BKNM_c#+G^y%im8dDYe4lb4tcRBKTo#v)I_6@RU*n!j9+PFcm^Ov)RM& z=5T^p+yePMWvWt*E3#Ovt&TA$&BsSd3$K<|J8lHsK(?)B3*uv9MPMM)E$K^4)xDCT zt+ID0zRcjK;pfk|4(3NpNfdQC6-@dAzsO2 zn^9z=+s7CbZ^lJh?+TN;S(^m%t8tl!!KvoD5C}i`&cUp`<_u7k5{}t?`unx7o6%Zj zE^=Muf#k!=i3>U%0*8}w^&a~}%F`n8$0v-h_s|oZK*bsVQE~Ys#I;J^(Dj795Se0{ zOFCcm@3t}LkZZK12HgXIcI!{-k~!Z|hrz0t4W$tOpfoBEPWOq|mXuBQnXkTwXNBWm zb|NtFC5kK|eJx2ah#-+7&l(Z~?KKc=JvqW61ugMLkerj^Srw5E4!Yj=q@k{L)iuqb zZh+)YOKb0|@$D{5?gxyY#v*n|EdOY;{6C%|Nf>wv%Ph_%0E|Q6W54EXe26cLld16~ z3=gsN+GD%14wxKj0888bkyk;S2|^%1cpJY*!1z}JW~dPY=hy>zB4th`YBgA+B=*Q+ zi>NoCVa}ifLH(%oP3f&>l$Wgg8}yJ(HDhd~A3V@Z;-E$rEAk47Rnd_wYh-whRm-gw z6kze-*Hl#yP|K4h?#5B-Goj;FUctNPVLRz>*oJrk`mZZIIXLyr!j~*(+bo6FmB@?R zV)QZG;y0npSxSny*epAx;4Utu8hK9=;Md`SN1ZqVR1Bw8 z9@J}R-e(V`dfm{YX~0GOLs;slFlCdQuh1DwB-lR0lm6DPb{C>!)qaVV4RHSxo`1n- zT$~@iv|N4g(JBc>GOOpHk}FnRkqxvl#{i_BkFRcjkqD6i_v`5?!Wbh;6Umm`CN{dY zg9RV^%DZ}+s4nA`Op8~a@6&8`6+oEQ?@+I!edS-u$q*rK*Exr(n}lcOwHxGBC%o1u z=CM2Hr>Xa!(+rs6LGTm}_4R>Z#ByaJK#IfRqznpyUXKEku;8UUp1HU^?E_JwrYCLc zw_XsKo24W=m-PjPA3j+hCmY;piTKW(wIjXylaeUPHK7>EDD_67G3TY0kC>a-O^6WN zOz3YXJyMWNi6~!D1;fDuk|8qsq3lrv;IsFCuN*jlwYuT4qnQ6bOvdaFnUPmQC&9NO z(X5yyTXtyOgj5e_@P*}r==(i4vB3xK$y%iI$~Z~q>6her1mXPEJv~O8;AKA@zdwVYauqa``d}z^PAYuoG9(&>AQcRbGE~@{~c)| zm`JyNRRs*8Z9 zR|29*Npg*cfUke=CJ?&voyMP`&iwaW*Qc$w5_rM4R=~3y^%vq+f0Nh1ap^Jn{YU|% z%7$AzhGt+kSxgJrH2{7CL}-l@kS5bn^@#QDj3+w-v>WRp=i@z)?cS);Y3m6b?ML~j zNak?V&JGDS|7Bnhg~VR!(M{%}nW_;N0adE)?E}6NkLRgi*2{H~<70klg*P6gll1>{ zX#D?)LBzf&oi)I=TwKVL;TjLC(Mcz^?U%+XbBybbr);;%K&T0jH)U`J*pTldH#J?51PD@|ZH``*eEa?E}d3;li$1x&czq-5AwROxyr?SX5h3K2H@wRvcpm>Av% zOJpCPHq%@-`s*SD1CM+ES4xY*I9Gz0fGxR(ZN|v{@cXD{l$d%*n zAqccc|6y!&=m7Ib)q|t`G#{n>Ai_r7%PH9)|GMh4=$VhG^fA3V_T|L4*XsK~P;#K~*RKLO&!Kd#&PxiuwkH{C;pg&)bI z_a(5L(-c}YOIR=K5a`qT4)J(TXt3X$?+1#B^G7k!G)EBMapOPKj1FB}{C*E&XQ%23 zkhIk(ErgE9cqwl*>3)-;I+%zARH7P-LlG8);L)u8vMTS*tFyUjZj7$-4?p6iyHxZo4J-NjCmB6kKeynz9gegC7T8`~OR<9IhlPGIQY1DT%ii$BviZqq)klgQCa zeK`b7m)?K(E%1fUnfyPQWm9DtJ_B*B*3>9Ocqm7ZPqIg1#9i=0NSW?O)5t*qvLSCT zx#2v^eSs`dh<^f_zJO^voYt6zgL)ET?m0|{`ocss#RyaGu)xCj)-XUuy7TXNc=!5_ zi%Rb2+MZ%ry;iuvcQ*g2<0gE}lxvv$`K&$m;xU}0AGxM?cHb8VRBcu?nr`bi8uTa) z9x!Y>R<#%=jhb9}1Iey>w`%-&X}3VP)1oAR=t&x|MpypAN{YzHx#{D@Q0t}re>pM# zqMaV?pry8wfaOELAhejz+9&;(9fNm$ZkpvD+F_Zs7g-o|>omIw@v29_4wETQ=i`*y zck8uCHZPH0%EbwPvsz})K`@=i#(W9vU9Fbsal9jhDSKKl9Bk5E%_tz-iN5}=F~qF$c2>ke2xMC`t83tg3^964 z)FsymCeRoEl<2==?LOB$X<(3@lV;wNVACJB=jFr2x+7}d4j?@MpO;|x@Rmyz`!D^6 z3Xp~u^f5c^BoMFmwc`S|)ymal&;Ev(@r_ChM*V|@{;Il;%DwU`D4j3L(LKY7Mzhl- zEx?SvN&13wQfx!tZsPqbIv;~>v|aUyFvx4J2j=ZFBH z3iP)Q3=8t^;p*s{_r+um`(cMbFE^uff{s2Pltb93)Ib%(X+uVXkDt_Uiy^L@8`B*I zXFdnkr2trKHJS;;7n5DJy{Q8y!S{Rvx-*0#4H8#Qmsyt_5KHDX|W>~wr) zt}hw0r#ce3te9yAj$_r-#)*cSgF_L_N=akjOG1=0D24#enK7t2eT z7AW|ibQVJSvV46;Vmvf$+^<|Vt5mUUh<@jV715-h4|5K%^X&yN!Jw>-^0hc>aO_jmOe*XT$uX&_Awc_GzdHE&`#FC6JF9t zU|WA{E$13b<#af+fmjUpFxBtRdC6#C>UI0F8i*#UAewX3h+CJeT{1&pvP;xFDa=`GuUNT=ONj;H5a* z?muPL1whMb{T=N_|LSosu&_4*%9@W_!TaszuXe27C;EwXS%|Dj)*-gIZ}N5yY`Jw0 z8_tmncmQw*M<#g}%Wdr1GV9s+DVe7fBgd<40KEAZ_8X zx`teB(e_XB*tYz55h9|mt1Cd3IZrESKPr)}P46R29}@t}G{^<_TvjJ)1;_d<_PxR) zy@7dY*e`?*0_8>r!lOf=8YEz+?rHCSLe*jI#+;o@R>CwL131cX%Q$kN?vfb>I+_#*@HkeR}7Qxcusy6HOXdNHl`jrxCGg5nHxM9 z%`bbj71T&ecxL^8l@$+t_@9ugJC^?H*T!!Yl#Edgl2ZEzkQ1(+Rvav&hF6YlLA^s~ zU&DDxRAcW$&h1f>))|v76OsTG@c_Lj!nQMlLGA;p3yH3cZu$~Nz*Iy1ySmd$O_ zv^-}Yq&&Sjyu^aLL-C)6EzW{5K;#<4Wp~!YMF!1_iTsoCUViOn`sj^`+I4=Q?U`e8 z>WhcFiFbWg-xft@{X((6(*hMQuv4b{;f<7HsFyIh@U^_+IDZ!p;*7?p0R^_!An-qE zkN+fCarOyqpSD{A3jKWNgwYhGS{6|yj8|BPOP$PSdic8fpEZ3)A#N%Xwb;+B~Xr?Y2*RL8rl zFEouR*QFI}ulbjcZS`0WuLx4G@d7RsotRv#etpmoFK`{SnV};d`^SG`(RG6mMu`Lm z;(luuvbH`$#vD|%5;8)xY2*py8}>X&o3j{R^%n_Izrzd{p9&RlxM^iaxZPbc} zIMpOa{b#~I!3$Kg{{^`4XQ4i?^b~`DtB>C6p_3t4Of=NXBnEhF;T~?!T=_YN+z>?JY>x{z(g~E^IpV|i6uY~%Bu?y{i){s z&4!>hIW8yU(-E}}b-(wJoOn2dYY{DOEn<67 zBUzxj;4fQ7NwjsL=IkSJ2mCm@=XPuAdD-2)1;GNL<*-4P2d?*~hJAf1k)5mPR#^|& z`Yc+(K3-xsl#M?Q-47rb^)-S{RA@Iz|WaBY9Ey(^DKoHhW#sW(1YzzA`i z#4EO~Fec=*HK@!+;W(&^jRg@|SgzR!X34QV1Kvc)0VLc|$bl=(c)BIt8;Rr_amg1T zl-sVJFkY>bGLem`80`vmlagrzZx7Dq-rMys2<^hJv%}zhK#8Hh+62GxPhY9OK)t=4 z@Q}qlg@x=k=dCGGni9F2U@Mi>-N)3fzc`~;UJ%NCFbxHbjAT|2$2i+oP%=@C_LH8M zZOoYdhiIz)?9#$JMuOu$@ls~g*@aWf<_THK(rSmPo2#7X2efyCo(zWCZbXVXo;(~h zD^x#~ehA)!`^ygqJLF-M%ze+vE+s%j^KVRag$`H69|tOwTb6?8U0z;s>J>8u+O&sG zP-yLXlgNWS>i1oRTpnHw^|+~hB#sn^xIyk_4Kn3m%wEe?78x2 z+4hgpmb*)GY5OU)Tr~m0rRGZ_s21)%q8*QRC1Oib`5TOCy>aP1MQpc)ZP9$#$~PKoD?UCJ)%^o4Yl>x@_w6 zJ$3+#PZqxXU$M@yY4UB@_j19Ufa7vB8?Hp$OE%yqZH=tr8dDx+P99_mUs0|0)o&Ul`jAbf^bsG{yoOc5GVd zIC0gx*uOK}PY8ihdDtw!t(eR1(kOY8@G_lzDpbKK5Wawp52ow(CoXFYSUVRF z^zHbgy9eMKA;n|{Ov`|XhPta4Wo0Q;f(@8uU`PP?jU1&+ri%+h_OBJ0_CGg?nzT-+ zwJ#2>yuyPJjLs{&F>|%I*Mo9k-V=|zr|YM*Xx0g8^S|+3fUD~0)W2*;_eHU(GS z@W^QDf93n^Gg^Cx+zl+=Yo7+yErXW*2pbv#a2!0wTz4M_R<3z#-9~GiSNkJ5zFXV@ z6UZ?l&*R@^lb-K-&A2{7Aa<|m6YqGga?qf6q@f=;81w@w$xapaK!X=}UiFZV!U0s0 z#9LS9FPFtg%?9DVifo-4usgP8EJ_4t8 zZ1HsXH;5Uih7a;FNZq~p$6b6z4CH9krLFNPM(e3FDqNEIb@d(TVRIT_A9G`7lNYKd zBxqlN{2BAOq+v9W&+Kn|MfTSz9_M^Z3v;JArJzExfaF-Q(b`AfVvbZ<*e>Z1gT@xp zVp1GB4vl=tFi`VmGk^TG2dh&V^fUa9=%_=RO_T>;;D|#G+GND4(QXAXSzIfBTKS>t zuf>dCZ*wRLC4#WKR&FdPPw&QuV}D@t;iLt@E&CN1kM4U>a|xdL+vKt5A1NslF;Z@) z7`q(p{kW6;8OWGA`YOFkM17~hx%7*&7LI0!4`We1#Qz(e0;wX{YB=)H!iwccwm?1@ z@Y=uCFeoq2#+~ETV|VqkSo>Bk;qjw#-Xo5q7Yf7%(iRUCEsldjzup%Ze_pEMkf!2$ zqj5f+V`;lxG8$Ui@OGJ4R*m@igy}UVvcjFm4$pN8UwGcS;4g8lHE!{j*E7VYJL<6Z z{KQ{ZO6d%uL|7dndB-2E^|y`?unhass?OL5&Q0%qAf;7E%V8!?|GsnFgbFbs>7qolG7js()v8mTU z@br(0^0Cmub3v~M&|nZu$M75w_$X#jO{eg=JacSJvEYnao%%TL*@pIM=sQO?P@>gl z2*6Vq5R@EQA~y8*%vByzeMsYpg($WYc^HiE%cILZf897lLKinjdiPFE``k^{sRL5T zaz>#Y(<|24tFr<4x+_tFSG8TItP{Z1_#=)>(}WKjTrTEe=O9s8=tz$n9`C_5vOPyl zUAo2`8Dr-CS(XR*W_GR31XIe~#*qqqNPovgaMS1q7KL#yH~M7fKdv_)*4v-W(F&5b z#|t`4tUb3LbzCTZ^upxmDRDzU{q=~8ST2uK?RkWukSw~))()9bx+?>18=#GR__M;o zm41)*?K!*l+Yp#TtnX=r@#s zxBk#+T;iDk*M^WK0eH&+mLNIS1UfGQ0Yq(b;L!Dt*1Q; zNEL3Z+^r1To1SyC1-eHygSqyL2Ub&E-ssYj(EeP!+r5h2QJaC_{?U7&-Box#{={TI zX7A+qmz#FzfopV1FgD-?^b8+kOb%;CSD_=PCEr0E`T%Qct>o~)7MkY=iiS;B5M+uc|=Evpo- z^R6%Pj$MBbA_$ZxtIhJGr}{XMRFQWf8yn2aa^5H-QW#K&@m?T!|8>Lhi@qx6yM#c< z0X>c~=0sdv2JH~x;wZ|2AboLrKL;bNhZt$o@>qHhQx(s^l z4&3Xq!p{HznbZOu9-YTl3xig zAs>#Xg7fQ>OnS~lQKtfBvVV_!T1p&C@QKdkg=dPvGsyM~PsUSj4HQ`sc?c|8R{DaD zf8=g}!dr7~f??8juc=a_+P@dBS#Y|OR+H!OOP3)vh&cxvuDgA#EkLPtr03z1T$yI^ ztB6t+M0CN>gqYBpF$Jy0tHx;=*LAqtQv$gFfq{PDk>~E4ld<`b6%6IQf8ax(V#OY9 zt#-e4M)@9Ac_UTHPmUWyp!H{F zMwVNJv*rfCigQF%yXS4DXg+o zFFf5`pSuz8XmUf5K_pKF)75bF-O6~yO^5oQlBdCK$3$9W|a~U;rH?!U#EuVi4f@SY@OqN!mt!QOAW)SO098t@#-5el=1yt!H&_88|ldb0m&woV5aL zQF*zM>=EPTQ#_ZKH2h;MJ_-n}a7HbI5TrXzvF!W6?38yzsU*bFJX;arlYcgoKbWrS~yLgMVRnOcj?Q)2meE7-xchT%6W!UyS%*4`w}tD zg7)>>ZI3!WDvzFo(r%sDm5l}_0e?Adbl1*4bAs4n|yC8x97#M@sijAc0{3xt**Q5 zb*m4+B$tpsq~7G(g}fE`c<)(t_SctD@7r|+Kd!(ehGPxgZ4&QXbu_jvun53opZJ$6 zi+A6^Pf&S)COhE?1;sG>*04U23TGK8@A|}%;B_jeh3WU;61uBAkREJD=_9;jR}-ew z1Ftm_flcy{Z@)j1+53`DXE7kk%1v_#!BN_2PjxlQB5mc%pU8`a8OvsO1q+ovb;HcL z1WTV>8(;fI(m%S#Tt!50w0+ONoKbS=Sy#``AaCQUfh&kfQ}axkkIyKk^Hq2mmP6b( zZqu^k1WhYdvKw(+W=o>vzLf%D7qac7!)t3Xs@?T0&_#7`P1Yq5q8D_-yR3IJuCG>V zU*ol!!C3|0AOT~FhqjZcH<)tNzeMp2*-3y3%d*T&8CZg%QdN=d0zW$&?Ofr(6UpHX z#(&CDeRZL*K!=YaUs7rTe2!}%l6-1!1^xNj>R)8=c;;Dsobvs=Wgc(H1P{g8#@_wh zf>W%C=QiVH53YV;iwZEkQvFRrEx?Smif?n=sA6YCh@}6du6K$@Q+2!J=V6#r*H2XO za6*@F$*noVAPH<(Hc_vVzcIF>M*f536u+lG;Tgtbt-obx((kt5PGw*a&u;}4jSoM<4Z~p(EYfe-^|KB` zZW1Bhab#(|UgE6oPJc>?S3FjIH7mAzfd1%4*NUAmlEj>)wJrMir*xJdWT4zhg3J?P z#}vkz?YXm+R-5+6$NCp3#vjS-Pj)+hQVzN@&684qKN-8`WVyf1AV>p{Rq8>l2gVBV{JcAn}D2&sWUf%?`pc#eG9hDvS!Sj!Wk(GO$JKSoBJSNrT3wa`yhM!c@ zuL2}z4Nx~{A_ydvlHnqqGqeo3tWgDfr5;`b39^>7eU4}KVP2k$MN0SM+?1p(eQO)u z1+C=U;=@S$F5tPAr_@U2uVt6SZk5qI#DQ}H?pqvOLmKRsKP=Qq%_X>pWLE`shT z6-k3l4(4u_QQx?TZQ%T-Mhqmq*-iSgB|}<7>|l*65qsbv;UB;Xx$JkY6Q7Hhwsh;7 zQN;Zm1R;j@l6crKnZ&~%;C$WN=$J|hWS$N|P?YhXi+S6QXGEWo zb38yTyeIWrA`wJD5M58jocKA5eRVStw`2uRX4hvT@hij`|52p_fg#$jXU}jfa(;zkz7fJ`y-#7zglc-1xmfyr(1!cEou%^?F3lo4kjR6 z*6uc$86LIZiE5b@pF9F>^Dnja?K^rpR}wM#diRqtrIkcS&H5mXvxcByEo zywbwqed-aCJmMnX{Ztruv-Fb0EYDKaP(erCfaqefzH~@G)6f%YDbjvnVtF9l?Zww1$bdJH<9?E3Q$?=kUGyr<7a5`!D~X!Bf&tTnz6O61;WJ$sEbU9nA3ASY#ypU zX3rXbpfE~1YDHZx9I02|7508@Xs<07@9df~}jx(S}fa)iOz-X{~TrJWSd zdXW&Fue~t=HYGhAY1j=~YFdQhex|z92Sw{6QARbP+Rhlm%$18asw8`lPI${!&XwKi z^jz6rM&s&&e5_^e672a<`_%DFVL)px_R0ek5WTSy@szSA{|@H7Av$nOK^LmATOZoh*2%UNFEs>x1aI?kH0Vwjd zqZi|A$_%LwI4JC8wBw~r0BhdpBk>Qubs5P4W?DH}GUOxB zmFjCUAG1S^R2c4$7LOL3zXlq-sLpvRU&*D^vj{6hd0`#9K-;UYvQ3$$=tEls066W}Q zxif)^leLrLJ8=H4aiT&M#t~vX&+AH-cx_LHvdy*l=x&3}!!JHsu=cMkDGj3zzTys$ z#1?O|3?#sKW5a5!nnOgCRs;&LWK{G5xjn7iNO`)K@^ulH56j)-)6e*e4F} z(eE&p<+JlRXENG8q#>VJOudgWN6YOck$(cBZ1$&q zwS)-}~$(Jf0_~_@lw#Dnq-tS@;3^M`>M9|^1^f(L)I5G6& zbq*1J_I%e+RsBMK?2T49m3uqgzQkT4uZFc$zPN?onMi5Khm{BaZrQaUSSxz_lriUn zX$S}m4bOA-+SqZK;2%M5F1{f@cyel zFp4&S(U=9Faxh%o&-|W})wyDKk>kg-dc<-N)xw##JYy_wT-2il z8mZ*eqXB_RjdJ2yFDfuh<-Fzi4|CD0fQrW39x0|SXy4`-I@^pZiAjcRG~-^F#@P>G=Hh5c3usq54ZH3U*W{vk+4GClg` z*HqstTHofaf`aDM+xP*_k5^$lR5F(dJYh)`YQv% z-th_kveuTmBAdxw$)w~N*~Kd!y+X%@1Ep=-Z0J7D>&JZ`OlqL|_`Aji!37O zP{pPpMHZhv8@<3r-G z{+~O)JhP_?X!-&69a`nw3MINMgt;NW8=T`N5nf4pR2C@0YfM&C59I*c=m)lOt3-*8 z<7+p7a;j?PGIFv!8@EjZ81Fakd#m=_%U zI;&p_xwH744*sG0MN+4VAgPJ6FDA15^}y?ty_RuT-G!c%G~Gx$Ti=ZXfVM!+Hq z2$VqHz|E5z9{IWw#~Wspp`vIZAmtV3YaZ300jXn_DAMoFM;J~KCb+! z9ba`%G9%WYIkw?tNzav{&AFL`T5kLg@?U$35|>Ey$a8as0&LPXdB}@>O?3tj#G~;jI$b#CG_YQ5soAy<@^;@Cv`p zG8?%p*i&Ki^c6R&<_StE>!!d-lN>IYS8K|=tao`GWI4ftj71uBEU+k+w)+$B(iq*y zRnJGHw2@^iX7|K}*Q`s2zU4u4qUZ;nfZ2sIF;P_Tpg&zXX|{eAn<)o$KQN|qlc&IL zGUGsPB$LWMvr?MOGBC^~|3m=Hm25LRB~#Vv9ZWGk7ht)5(==GDKJ}0zqL}PafKui| zLGJmVFZ{#CzFG`@y*99gdh5jh3M54V^ZhlpMsZi<+!xPZynh*x%S7&oLaM1=y&8n< z;gp~6&$QoIZpGl9d!_E z?H?8sp7sdt_pNEG;V1OsN^Z#fir#tY?#>d{=huJ>6+-jYqe<76qfYs&SLmX^7(%Z4 zX6b~$5yt0`V0_L@2;Ia`VNXOu!42S-kk)IT?_drGwANuX;)$dDY;$+(h^sx!#6){d z8aPhI1y>KA_wWQ3OtQE6~&P7fzI;T}hQpGK`=6Vj9NE zCMQ>w8WsO_T~&uJ?EY{OI2`$#)fRqS?cUuWxphCa+i(6)Jp)c|`wvMmOgKvU{>}Y? zM|)#?LQjsr4`<){-9{mBi=J@wX16kO)x>FL&xC5-D6@>nA$26F_;>1L630p@SmD^6`$r+g9e)X!D zJJcd=I&SVpSD?CW7F|aB3pqB)57yQOE}0>ZOfY&y&1d6d9nfGsD}B^q?%hM)f)d`CH`zUOwj)^XzQOEI*soOO3|#x1#b)roG|V{zKNI zTH3ASuIdlNTbSC-FfyOo4;IVg9bA8pYJwZT48I^7Mm1xJz2t4N0XRWROG8PkQ6iI@yte^-;VO=!yD8sCDoX(sV7W{C zaCKU{ba;_5XS&>UvN=2@<53`pA0R)sv*J$k?BJLDr^s62fBJNDsCOc@bRN$DoijqF=Ak^w0)8pppR@I4e%{%^epR?_?+TpV?OTy8k?8Zg0wb^vqCuC~I zN^vc6rGkcah102?B#_)pdRt8pScE`eDQEwcf6iWfgqb>~Y^B6r(fw$bc&LEueev9E zAhetuO!ADgYLk-X*Z`-T&qN(IVi-6_v$rZN{-67qQ(#@ff zE&=H-1(B9+knRTQknR)?jndsA{pEA{p}yb;k-Ee-kqJf=9<}=;mr&=92(I~ z`E5InE&Kb|(vw+hPKa;hs8NGHNB{F#KrEYY%DFl)y|qI)(Jc=IMOGaQRHPiqZq87^ z(;Fem4AV!C*bLkNT_EhsYo#m+Qq$z}!%Hj6U-%9xO;;-`Pp2|Uvkmmy)hU@quww29 z6rUa~R*k0?V%?cPIk8~r+N6FNJYTqqEe{1EBN21OASf1xEzn+X{6h#B-Rsy_YiY8> z*7(j?CpwJ3fV-!(A7^?Ef<~aT6nEMt>W;bJmACA6Xz=0=O>Unm?W($~KkhB~WfwAC zJOkx*x#E4W8|IFGdA@%oWK6p8zIVSLS;J9-)~5VPK&Uw@nb%-wi)ijKNS=WkQ$(*S z*sFGZH^2&KPw;*aoz>JD$+|l32j>08GJWgKPsT#MN^Wl7;C_2|M8Y?c(Wx59pRSZm zOGit$+14NpTZYF%=~+(tifE~YT1zTaTA~n0FgcyJ-rK0JCdR2I7QNA?WV;F$1(5aL zLl-O@&N@es;-Ts0(o>@DxUXZrm;p*r>HdfikCP?yH6*z;PeXIfrOM1ufBcuXha7lV z$cq_NCxF7qaI!Yf|0WOS$vR9*pDR?J&>Va1RM+s=I&G|NQ{_%NLrUG+`+Zms>)n1) zx#QRGlDXqw2LU_@s$G7%IBb5dTlQ6#awI@5VhRK#^Ts8|vpdJK+aD+%7fnuBno2!* z_t1ZpEjGOAQ=q%7E=3O=!VRqnC;a)EE&PD4SU@c)B^817V4qcC2*is+IOt09CdNRU z1yX{3(ZDymkE=kat?%u=O^#gq&o>l zrPS47DOuCxWuFDgi1XG*^S%%~f-VFRX)IO{D~7Y1)GJtjIs(HW(^@U|9LX`n=}iY^ zk^?)8DR~;3bz?H@I-yELv$KL`M8CPo0Mg%wrP$Tc)@p5(ASxDwtHR4_rpu}=wTm0v zKNRC3MePk28uv&@KHw(LYK{WcjdLsBrP#g z7hz7&)M>>QVwgoeSxatv!KJ1=HGC$odEr6*<>A8!{X zvG2h*AAALUU_P6#R0rF94>HEBX&`_bvkiM*DQydLHKbeePxZ7XW}Y~(%YF|4{8q?! zlX4S(@1}puuF*9~`0m|lIw`t{MSj18B#nB15)81eV&4g8^_QQPYKO;ZQ_!DpIv*OG z%qf)*J0hl6hwd7r4pCarQq3%+AMj!?<{!c^8`#&}$cmvELmoQBf{5Fk_bfFg&LlK1 z-ipBs%h$-Fl#3fSD_PRK#Y#d7PT+bDbJyN1F!#GKgA2f%Rtxt5k45xz`|?5ym9=3p zalmn(`+0%}g39(WV==O~+qXAAT^pXb&6^$jSd(2|yNuqqp>Ni!cu@`-P%0GBIN(@Wd6tq^YT6}k z5ACDDM$TIcJ(XP00IEL8ZYq{G;_F&&uE<7>jvjMZT0E1<)09@*^(e2y(c9yGw>eRi z!^?9IH^q?%*5z<0jQ<~KUf1wqUD{iB`*X9D1R+GTedlzhsaly>ARmxOKgWD{u-xV~ z8Xnc3pIwQt9ai-t+^rApojciCtMOUBu$wTuZ|2n^iiT-maF^jl3AMNr9ZMGgVO?*HaBL)lNHSkv9PaM)uWAy0@tWuBY^hznrKZZ zOji~~b2^#o8knq|nVSPbko?5lQsXV%qYGEgs>|h9j))%$fQoH9IyKoo-L&pv7R4R$ zKJ8IAOQyHbdO?(}GP5&oux#Bpqxz**WrLc~P4Oi!yLK?B+!{eV0y|Nc{RSRCvHow$ z6Ha$KyItD*jF;Fa0g!|02*{Y;wz~AR({6?i!wn8hwX4NfIG4X>FV+Dx7bf39g9S9+ zL8Vdq&w9NJoU=qkStTB5+qB41g#ngrGE%@$_`zATjz9Ns9)z=$3IK~)BH)H@QkOCq zc`?TZt__|4bxdy1Dg7y`XyIG+=p;3EC;eg>hfZe}kVPN{pp0?&DE6c%R6N1KHp(wxi3K~7L`Ot zttF7mxshQ~r(_nv8by4oIWrFQ!*Qd1i{1Y(vi%3ifq&qGs8NjK%>m%n@i{Cc2P3`r zJnTEJWu4kRvi~?0JXKg^9$!1Z+$`O2c)1hkb6LgkKof)#+*xYRpe#)XLxaf<4d~Ao z2+9W;9#?O~b zS=N>5Ow9?Gb>aDB?iZT(EbNoY26zDyGG*+or_u78BaEn%RJ#cs_IkKq`g*#lj%RJ8wHbJMX=^bVuIjy?psx zlN*aMBq05=nD;0-*c__Daw(0TquO{u zdjqbqK&^+OaFPyy_?lM!OmtjXh1jG7jfi_L5Ki-nFAQt#Y@(#8)VaMo(%d&)rMc$Rdwdl&ua=Ql$6Eh)7$2{e%3lZb56cFG_5nXdnM+v)?XdOZ6mtxx?j!1f>Hd>cHVD_FE_)&+2k{(oZ@5z#e;*!nT`|z9n4=R zB_~vtW=P=PKzpTuhXY$2dCOErUS3Wr1c#8ak#`|@@cF8aI(CPjp4}|T8wprhQ#dv@ zKz|fPw5`4+GXa+UyrGw}Ko{c%faSpXneKsd`gx5(A7o5fSX0*`1QMvZi67bxkKC>a zL_!h=7V3JLy|fj_XN;WLP@OBECepR`_6>zVD9-et2ZWTPS&=1KN=mheA6P`BQXfUp zdjBB={utml*qHq;+?6VZhOrd@tD<}dSoP7&0q=!EwBz~(Oj2TB{3JQx#VfqXbbsWw z2rzxa)nG8f9j89tvk}mT>7q%d7V7)RfCFW`V}(!}biQWlU8}=BegqF!W6pvduCWQ~ z?QCqOB#%T({YeEuNCx3ytfBejhE*yx_P6uAuvMWiNeSEsq1A26b-WqenccAM2Qa$` z@)kW@vCLeEuFe|vQTJMPb{l8?=Qzw)O5^oM095A(?D)Yu4GvK*d7x;>L2D<4xZeC< zYU#GDq95vp=!$a9)s=e)>dF~jGV5El?gU00s?wM;_pFaiI=+dN42LFZMQiY=YXC=* zrR|}yplr6{jIwMs;)mpEa-WIx(qwS&8icLa-CzdVgWC?I*dp?(t2U^bw;VddaN9LS z_TKdnmat-e<$GUXKk!)n!j>AX;M?~acjoi9^=;&&^L(v`0PEdpQsx8&AK18#>+B~_ zF@$~R*%?ELO<;@~lJzyN*RkqL%pK`kO~%yF7{F#-XE6;35zbfD(o|)EyN0qvt4UX< zvzXUE(?1&8bNUqw)&*Qr_^45?NmbDmM-}=e6Rd{D47FV(%Ir{dVm#BM;`I`9R$~wZ z1T3hT;rL_UBEr+Vb`gO{`~D)Dig9s?O1Ikvj7UVwSu5m;+v#h%Qyxi=Kvj-OMinS)A>om884;<K36JRZxVHSEsqRG`f)^DmD2x`rf& zLugrNLrzTt%JBUeZ-N1M#Sm0c%D2!;G$kv3k7%w8$m6c41{GxvCsQ*!6R}S88fK{x z)pDzX2D*&NRs2wdvwW>L5Ma~Ccx=;_##<=agHgonA z!T$35EMgU56>nN8(sL|C)-2!%?3@OlYeuW7qXcsuSbEZbh2?Q#fKobd)-pnzrGV5i zM66R5P8Q~!?N`Ic$t>}AEaH0&YO&k!m&#gD)6q`+XjIOvNZFh@dDl_NsyVM!H=ae^ z*B>nLVVd6EEx{Q~CLqUCd4EX{BveEq9?fM z1rFI|8~3r#udOoyQWQJqjaUtYcAkUc9e)uE#H*k7yp)gHhFGPpR4Omre~o*(1z(&! zv99_deDQc#Vz~EY^;|L($9$8ivuaz9&9(+o@nSL}&(^TrCDD=_mW^b38Xk;y zR#IsZ4rxx=Gi_6w%ECyacT1T#+MBCQGW(yLZ2*D=xkfDiD*^OtVdS0HAL<6q-g>u1 z_~(uf{p{)*+A9&P#JXroH^@~HS3C4(GC81oOKXlC54`T|Fp~V%2%<1~batrhJ+TJl zoLZIm4GkaeARo_YRN;tT0nxheF&aE_s?-=L;@-LGwqVJQtJsFl0?1js>eRKEZ$hiJ zMOZBU{oa2_%*IEs%%8_R=OME-ss=5GtA=(kx*x_y(vM+Y3{_9g9wNaaug|gWJLm1x z&muRBIRiJ1?X<=H)c)s;)~O-<#nVzd&IenD_}tT5X^%dty_70E(3}dp1GnMZsU8j5 z*MdH{^(%VDS*&r3-u&7^xB;n`OViXQJz`D2fO!2Lje#Jug+7-VcT(2OxjZag?DiP8 z{z-n)6&oG-=`r^chMNsSToTA!;u%c*WcVr?-3Wd6N`b7l~s z$@l3>2U%T#|4wXx6QFe8%Klux`}EaDqv^I&F35QqqjOuRXbN$5CuOo=e;PaYhVT$+ z!!5n&k=s=&;p2O{nQkB>>D@Zs{i6%p8ngSxcl1R=KR&5oK`mtp55%cAN{o1CgTH{u)#TZ1T+DD36se91PxaD#G#{BZHO@=K1! zr;xGUebafDF~Cb4f^d#B_g)bnY*NCn|8>FPP5WuOZ7ympFL1oWM=jrE%v|LDB%C>| z-l20p;cj}97f#2`Iskgfhw23lt*qKjZ0X`yZ4%3o!-H~9z5~qAF*24{MHU`rZF?CVN;b=`uaWbuq7>)lWCq=rznXK-AJ8H}nSI(3j1$kSr{Kd9}2~vN4 z-n23Fb8T;^Bs7x&&wq~C+(6Vc1HA&PlxZti#D}Drd}Vt)TcfHhoH~yQD^h76c9ztR zG-`$=yW?6rrD7$-J|stDe=YR|+9^3J67{4iT~6E0(#grBY0l28R_2Rl@LGEM%vc%u z<1ueX!+%te4A=47e*$O$MfuBpUb;GCF|ex@1(W{b>pGV7a4=@3VNb0A@3)xDH^uNG zRa|yRqimeTfrKy-;{!coCRjSmM`hMPY?vL3=v0@{tdItY0EMS`1*P8UEu{2qqWR-f zYkI4XMFT1-H8sT^_&@#*5D{xv+{G)FjxsQ!_qg7@Bi(laa!I!RmC3JG1MYL5*^4ZC z93-t@8@@YVk1v)Q>l>I%*5q(rp-G-TkIGG?EPuy#Vwp>!lKHC|}E@T^UI5ye`umOO9n#$QU zwE2A!k_#K!deY@{X-YL##>EX5$R9N(@_LUNV&zX}oa~bol$GP-d!=ba4R#KZ*5?dd zIs9?O>vmtCJll{dv*h^>G6?7KOkoN9_ve;B!={O!*Hl&Ly|iinKS-=_45fA+MbyMc=(e`tLdQ7(#PR#As|9N z`YCMlIwu^?S^ov#ilDUaMDEIt1ZNG;-i~6$B7rpegR14iT$H-f`W`Vwm*{ zTbt@BlT`cPszLccW+$~+Dadm%t4M7VBNLw{>KX9Og($J$Mf5c#>)IYyp?=L9mQ=M= zcTCPI80ZXrpTgk~bD~>Ut86lIrW?o2wGkthujES^cl40a%4t1z24Y-3MD9JYpkQca zXIWEJ#FpP--nir~t00={^xQvo|H1l?Q`=#3rqO=yH6?~TUV9FgwUFyeOmK}_!~eR@ zQkw>h-u9_?ZtG`BOL}4eSGT#&uz!MUL|*hbjw9V4)HI{g*Q7)gLv3+~<c647DrFc1wA!E*oTiv98cUk&I0oe5gnxk&1+BW+$dVQrQn%Zu*Vtczk?@WNp|*N zdF}+fCj~pBNf(EeA$IH5@(EQSU-a8!T;7XN4})CAzPYw@B$8YHa@u3I6XSxm`%QAL zPPD4*F4pb8Sa4!3t0RbI$^6wyr>QkJ^o-q6n}+|IfuCk5 z3(5%TGDO7XC6L$Ork(%Ohzb%|AnbnE{_NwW>4)L+>1o|z_3ul4{k zqpt7~DR?p~r>}`g3Bd-221pNNh2t;I( z^JvoinW=X#(()IXd{0qllp~PU+Z`2DQ6t1nlWS#>VX58@d*as@*Wf(XkNzJwg&3Aj zlRlieuQopiXPm*rY}TW$l#EgjBRA zHkF&R;z;_$;okJ;Ephl+9fNDhC=v>FB}^|_wc>zY5&Izfo!X4taDk-taL>imJeh^{ zrP=v!G6gL9ucsfB)uXzvM(SuU?jIl5V+|RYC6Axkn(LHk8DL9F^^feoEJc5La{k^b z{O54MFqJW`{e&pfq~yFecGnt;_(#hjJm^wIT)CUChO6btju%=@-4j!%d2v=>Tp+zF zD;mi2 zbz1}Tg1GGq9bjCimT=W+7|abt(L_|pjC<`%(%zUOKf{yX4UXdDrpz(XKop= z5LKfQxw>kNYD?Q;&AQ08;ttc2+b&T9X5{RCE=0WH4aPy?{q2*LEA-3O{tIyMRWf<5 z#&>>Lurw|7ytyD-Ck{drF|^SaHKn~%q5m*0ZQ8i@T`&?H$ob?NRMe~p2D1FcL=Ag6 z)4ZOhm?BA5zCb}N!Onn)h>rIXKnFJ04d&GaL0YwgrN{Z#t+=}|`zxh^S z2uJ&j$u7JL4*ZY+A9Vi{(nj;ncWXqS`OJ;z2fNx|T-fw^TfFd#sd@Qsv4j&QxUR@P z3a7agJSxS_Cmz#=)J!BaOb=h3W!&#X=pi(=v%jp@Qp}G@m`;efusJR?R2{w$B^Dg9 zp-DF->RF^!?$e|~c*ox_>RphqudepkZ_Q)&Qx|)1r1z8!g3c z>ZxPr9Fz_gwS;y$on_grHqyg3BnboekC2;K1( z*?w$ac}sLcsQ2nc3H@0pSJ~#R>)0sRaX-sFXF>8p)6R)w^A}#X$`Ac=^)K|Htp4@t zb9_k*{p?x=SEt-oP#P%Oy;G&dMXk=27DtW4_}l%-WhueliOtKTPM_B~B6ni2;oypZ zkVDHc7j0KI@Z4wR#r>_fe*K~dhbFtvu$_6X;*g+dwoLk=IM5KpgeaOyf$Z6TkJah9 z>IyUmbEb6e?$?te5Q|)Uz zx2LX-nGH_P8Fbd^`N zXu7-cnj)cZbvIh9iY85gmX1T%m>Suo&F0PBwi!Nk4SaD67xo1ut*eXq8Fc7K^p;8N zQ!l?c3P0Qy^xZTsu}9OAS+BElRh_EZ%o=t_OSYVZ(s$d`5QWTYXBF_Eirpn9Xnq-D zIOsw)lR4t^PWqe)V?LyCzGtMO-PaUW+lcJp^6deFVX_t@ZpjLW^AB?l|{& z++_rUm~waNG|-Elub}GCPSmWPe}j0M9|ze`eP1zVtV&?-#MR5Q-ulfp-C`Z#nG1xQ z3|dUyxn>=-99!%V-*0mGXqM$8xQhmtmljS5&d+0TejX?}x)DE>R*>^$vtSz-?iyK3 z+5X=C`Zifte#FOIrmb~-o2P5e+W9pbNWiTY;)94RK}JkoK9Zm;SLMQm#?H< zN{vP9>^fvos_wU3YLf@XwThF5jkg`jJSGX)sy})3!ZU~5iQ}p1`Z7eao$8+U3d?2X z%C>xL7#d5VTBKs&gIgFvI$}6&?*|~1mw>XG!Gx1Af z{YZ%@u|+ci9ViXS(0$)FM4EDFzH#te<~Xcgu2JIHi9Z-j;RqtUb*iUcN`*ueC_1;Q z&Yk$=E2A%4`w8-w9BpdVK>g=C+->$>KIrZZ9=F7N*-aed+;TqZ;;~W4s92ITCv=;C z_-zoeaj$3zr9|(@>@zg+%{u-P;r$#u`_2%`l~lbRwJ3SH{q&+W8`{h? zZOh$^#NTdDU;rZY%CeS-KwlDdtq(BgAiWgmS{tSkE2}l zxxJr3hPe|g1y^l@9NZ<;V?r7m&;~7b7#c>4@k^ATs8c>)xF47wx<1MU-F4|76lm}I zm6*$VDaEsniu_4;F+Kwe39YKQ)rRBc_rlhAwk=zRbZ|qeY?(VsHuQ9ks)W8y>w&!U zB3Ur^O@jnbQs3?D_)~mE48AJ;<<>*5flN|TmX0MV3yi82YaO)v_re|fPOMJKwZhM~ zt3J>V*qaPHlhka*7dX%+nhpnZz`0Cz49bpizHJW*l6yji2+TpK4T(eu|Cvo$EiFQ; zHr9{m6_1fFm*<%U?9HFr6;Rd$rF|!6Op#v37_r||l})76`$)cX=jL?%`3g@=SulCn ze+7ZWXH`Q%&zmoJjzO5F61sMZX`{bXhv#4Es^_=Ni9(?0s_Mb|oEo<=39f!tYBD3c zTH=!-aFdNY%suJ19--f{bv#RvgoA&v!(FZ!i&q#WsM8q`(SaN{t`MqI>Na7({Pq4v z*<5yEW2PPTB^o$5sz!=Fzbcu}C#$s*JXZl5ZcfKund*_Gb24_&476Nd3`zsuv;2bU@H z*fbE?2Py(NE^gDk!TRB#{evpP8zM)PD{ar=N>BNYvCH2&ahrp>RJrRHHl_oLcP=zS zzM4hi#h=CbJ)I;_%^U8b-=08G-LT~)l@39jq%5;<>%lV_-SX(fo!dgip`CiF{H>^% zh>Vu5wp782rPJ(+f)7c)yYyRg_aiAF&KH>Giv7q8r+@8GKyYDXv(ZkugyMm|s3Oc5 z+hcStmSO5^)7M2DHcvbpN8Mi-9g#8=omoY{Ly-@t}925 z0V^{B8{FHCiPL-a(qRHrQ-^T~$-xp5Z$G=Ac{gBe6REY5qWl=Kq>YK7shFmj{ngWs z0Pnguuz*x@d3;qyl_>rOTG|ux?Tzy2W1c7|-tEbSsa3$^w;GE@zwkavPQcM15XNeM%!p4KrgUQlU65Pg%Ka=T{j{NQt*CPZu%xBGYc{mrC+q>E!fZ#BYM zz~9zVZ-?MPd|YxzYkTu+k1kZ#?dv|;+{*j)OJAvUP%kTXrPD@3TrX!;!Gt)2(h_Y= z6M%@rYU8o;xzF1i0>q#a0b?zT6%B(yW|~#nvpA51<-ej5{QnLV|}&0aMR@P5|l0L z9|g$0@u7vh4D?f@l4bm;kAAOSE+Ofu(r8{Tu`cd?f&bCwuqE-R2fZo4cc)8cvmgGt zO7cU|YeFH)T&u>u66`U3E27+OyL=j7RFn-zr~*&I52=ZqzV-X&0bO`|mR!`AKKl59{if8A((yu8wEca z&GhmMF{Gg;wZGYJ!(?6u(^`-IS0n>9qwph*KD#`pd5|TR*sb+f$#0Ec?TYR*^X%MTLt?3{BZw)>A{@-08K7s}oIfdkNU8e~r^ytw0~b zt%xM*w&D&`)>J>kR79sq%vO6*F zI#*cKkoqgqBzIvu-a3ES-5oIKizvhTMFaM#BLfoaLLNDNCsCsfJJvWMY~`|jPw!#> zCb%G?7cxU`KW#;${lx;Gy%I8NTUpyzERn#@z;?S|ks6vydZ--4R2`+OGzL-Cpzaq> zL;QKjNM+&3B(6T>TYd8m?f`;MhJ4_?>Ppv9jp|mL+W)N-S*+)t#B`QdX9&al6`gwB z-4iZQH61G!&1%O2Pgc{X0Gl9BF(K~hk%%eSpN=}%*0QmHI#CuF5t$W?004E$k%aBFP`UQm{MrqJYgZtvtN4^& zB)wE9ceN62<&I8QyptePA&*0^mT#3Ckv1F|#e}fS59vakT7g-%@L4Lttp$$7`vyO% z!u1|bD4QtxcN6Kp6^CVYMjS&D2ky+HIC7m5*Ta{ete7 z-s&e$CHvyz*PN&&ANB4$)ZqNVzXKMqUFM@pzTRMmx<+f@|H$4_qogeJSHP8*koHQ( zda2_yGVl%9A9XsT3xRZNA)tyDS8BgjuRs$E!v&P^i|) z&s3?D1bS4eYYJdg+bdxsJUWDgy}9^pm3!R;9Hq#r!Z{AV7N4=Ysg^TbF8+7(Z8)zt z-vb>=ZDhTfXYr)LmZkC9Wz1LR`bqA$M4q$MKDS%>!jBNDD^REK4x1o%xl&UooZeuB zMqIHe%`}FA8JST;e2r0r3`pbcOg5_jfql_rnP-1)Zu$1OHedk9ibTLLUI;;B>m%pY ztJ>hVm{H^&Bx+Y8N!VaJT~iK*G*$L5`+&I@HuhqtkB(Qh6da;>zrr6MM+i1vod2P% z(BnYj37RrvMv|xj=sQ%kJjvVFW$7O6hQKyI+CFOdfL0SlGVlt;v@~>rB=Cq zM9s~q|5aesnAZxdac@_hv-&lM)P3C+*TtTwuh{I*_HPZuXRJrcBkY?AYu z8o{;K8ecJjzJOA@sXSlT9-SbQ^|I{@CAt?5F22l&FkT}*q?KRO09C3>VDjldOLe#B z(j+*q?i0T1b{XpUY$&Iz9mG@>2F@wwoa={NnerI394i0RrkOJ!uz9&3( zD7Z716PVkJ&Q^5|zYC_C8&)kHE(Za4rB1L22R+05s3o?eu5H`Z@3ceY_gP*mr+D?E zk7z#m4FZgOZNaKL7NKskO72Hk3}GrwaFOGuyr;FG@y!bSOW>SLN!8lXKNJsgJ3{=B zt*VL8)~19mh;7+JxlRlRXB0PL!gr+*2UK9<61&n{%cVEe>}5HjohT%_IcQ{<)c2vN zJ$p?*qqo0P6bL|r+!vea9;yiBc8zby`0auY^M4N;`0E1!Uh-J{iDB5PPTui<9BmX) zX>Ky$v)&nekLtc5*SWm?>=Ui!1$6r{!1{A&cZ*)6n6-{l6_{fs-LBjCNqE6WdwQ&e zP7`9hK3{DRv+s$@2F){=`l*;vkd2XHdy5W%0LlnsfWDZ0#00r&fnbO3=9bVeL`Tra z;HmZKGwKq*PbY_TMHt1rKs>lzQ$oMN($;XW<3JH6R%{In>)*o$G@iZrop1fd42fHQ zea30eMe5D(`P%O&=Z^ z#}f!6ho$D^(|)VEoNW&FP?7Z7l>%HmvQM-!6>GpRfP?^pViZ+IiH|X50JtiPJBhh~ z4ALzKIS3<~FNfJ&O13A8!|FwpNV>OI_oA;x=7s=E={Un8M0BPn8QpBxPI$DZK6oMT`Xz)jFs#9nm*pJo;z z!;gY&{t|em_Ui3JQ&p=!ow!!hecF2!UPwKDGNUwYM|rpxBB48;Tt~p&YfW9p!pp51 zoEd-6LHUv(IQa8#)cR*Dl#OrB3HaTjpH)mQVVrL91d>KyUO{#ACtSm3d9~LG%}mMe;tE~6>e;KO`jQiqrJN-S7+`Mk?ni$2P}Ijh4g;~s_HY~;DLQWDN!%P zt&|D^M}d#CHR74jgH0hvg44)l<>D>?;gj1x2%5iTh?3f;MK6?RUf(y*XItXHy6dw- zRWBb5SqmP3-h{T)U%P z_GTRu(*5;pi{uka&C=*3$x-Ke3(12on;ZKq-FLAysW}r};^_xUpPpaNcHf0u+NwRx zRm%O2hixg>&QPGzS=Foy&VupKN`O;&7Pu@AXT+-U80FFRZXCNnWqVu4Ept=+6Q5G* zGgh%#u-uOVz)Sl(ayxn8oy3}0!2#&}>>wJafdAdjWW_}V$^_r+2b|jf<_;Q5zFb>< zFn5OtW_vy?B*z$THj4hO(-@2gcYiawaHj!U9YFMDzBDA`Ne?#2;V$ zOb7D4Jd$xNW;e}Fb&4~{-khLn99_0695Gj$hs*2zjAM6(3_+tkZ)g#G$b?kX@6EU; z{G&<-f+dU_w$d4p(18MF>|CG>eS-XP6T>VO-@ex*W0z!611E2{|5yP~d}W%Wg5m~U zF;kynzw5GtO!t3{{FFaW@qu!J)!+ttQAliV`nl@;exs76Ie%Gl zwyN>xm?M9Iced+3$ke+RXA;l(n($9e_Ay#qA5T8vcgZo~O|(~}lN$Om~xPSH2aN9eB!h=r6P%#16vv9l$qrW*J_f!=Y7Gg)TOh7TkT`uN2011cYH=vT2koGCJCv zeef!7%6NL2m{<2R?#?Y6-(6G-^K($!)Ct<3=%CDVz8VMFxHOGOLBGed{JvdnPeX+2 znw&QGVwz~qid3Py1)63W`Mqm=2Tb98{6muv4H9T{8dg63ZW^BWVhUp>j=t1%w^f~= zu3CYvQfa-sG?O_l8Rm}#LCzoN1|bQrnKS%xr6WRD^Q1!zu>&j-|5>MWfnegUCW{@4~?Qmu|;gkGs~Drhs;c zFrBG;rIS<}MDIcSreKyFTiwC36b^Gm=st>sFSEN$Xzpy?#_{IqtLcJ>lC%JO9SF9_ zlug@rW@brTs%}(%C`(sf6fl#zIxrT4#Zc-_W86MquqAY5W8{TK1Or<)m0xHKhfy$x zeF_ehF`Oxj{i?A?pmu1cOCBo{7)OD1CsOuD)gY4`r_w?;89zxPEs0!qRu8S}EP1Kg zD_bZXYa7dKX>Yh`Og8<_llgx=IGl#(AG34-4?K6*T}+ke89MLmI*sB6z(>Ib-!^^5 zvG@j;l~L=!I38lMWWDR8y+je9S{YP(HKLV(coDt`@PTR1CRPr-5ib4M7)pz{yb9v#0dvdW< z9Si&Y9e-H@kI1_7rc$dVvd(18%WQP70bzIN5v-Fv-F|=3ExvZ+ZQi6uK-(b6mu!9L zc1~I}u^qHu(@pb7ccWSTjvk?ErcEBFA%siS3?PQ7lGXJw6~z<{;dcftthDbF^6FuI zfe_HxbX6NLEMWcusq z1L~JgPR%KI>Q*K(*luZL75Aa>uj?kDJ4wm8u&z(o=I`eBz@X|s<4u)Uli|zR@RZND z;L2((Z+t}XSMC;YnEgRzDMO_H5Oj?tu!CzgFFA|G8Us$V9$+buXls@2xK7x#%Q}zf z&VAKSFA}H=xv9Csu(R>z0O&Ftjjf2#?DE(D?zV0i7LylHyFOCVbnqmwyNyG{QTsT+ zU9GTE_3N}fo%R%0XmKtlru~9 znX=+yg!{5?B-UXX3jI3#Q}q08w~pRJ>iJl_Uvunk>iATbZQI$Z5==BpcXJHd=0xcb zFsUNMGMZ&}6(vVP8O+iM8FxMm6mvIFYiCi4WvN6eLYnBG{wlz7Fy}WzJ}59F;CwiM zApX!Jk#L)Mpy}D8c1v}krb^wBk!Z9fE~soXr27&FMkV|;xc>oiHl;>a5e%Fp5kMyb zql;?h?C~3l0v^}ZB)D=pUiuLYoAog07h;;~;+7;abBS%m;_W}pTcFH5s5MTvRIkO- zz3Nx$ZJ@GbRS9AdR&CpfWCDg381@&Wk=`gL3Hz)t%=)x^K2y4baF(8IH<`KH%Dvn> zrf1Ol=r$RNs(F`)=3u+DiU>}3o?I?Xb&yatKus%I&zZke7Qlnc?Gwa1bw+-pRnKP` zV=Jmgp!HfjTZV^%jBDvO@Ur-_%#dKRaG4fVpJ8{5*!kjs}r%AdzjllLFfeXEwfJ(bD2n)t0g1oM}K8(O^oi^ zV`3iX^K7j{BUp;X5%|a|3)BiZ%`fh>)f%}B2L(DtDjwtMCd@>m1!{dd)3l~`&)wZB zZzr<)YmtH03I0bVPq*Db&HZ7=7&=f&)D`mko%e!ItTX|Wa>K7pP*d`8F6JG-J{@L7 z7sfV@9Fg1%=~}Sf+e7N7Rg;}oqk*@Yy3lgl#9l0$ounq6S5~{bO=fYxqPvx@PftUIDtEt#L>tg3#yD4{W5JCg5>JRR4(V64828=-dDxJHFKl@^aKKgVGh&7$KWY3*EISmt&5vL1Ox zAk8xqPfB_z#iHd%wD{5NU02oMDQKqPH0)W|5Ps~ou}^d5HbRfpGxt-G*mqF}&|@Q` zc~oS&6ZFPq1q!NpcM1fqMg9Rhi9{&>**`_`{(2Dd-xW{zCI!z@fa~>-jg$W4;7BPr zt+4|Zg7_1b%P-w1F&=40d9t?+ha51F8AtM7ncdgWo!ZC!Bz($U+JbsnHd|A{+~J!v zVF;?`J|w`5YBf(%&m-}0C)n*7_QhGDZ)8XO!M19UJkYq^G{`OtSO%r1Ys2`GigUzP zdnOrGMo=+bm{q725_>40HsA&;3H@h)#15%Y*EV*-7YJ~C{bv(_QRpxS(W3&Csl0iQ zQt1B^Tz)Z(Idh}n|0XZqHY?yLpD9S9-+w;cTe3=Z>>JmE*1;&Y?J5?uF;2mIH3;7u z?>q>2SqmxXlv7O$k0ZfL+q+|_ri(DIGj)=X82KRW^!#~e0q1g>TYFJnO0k1O_(2gG z7jzT^qPE6(YeAOA~Z3Xkyig)ZaDE>gpfbj9CP%{U?|LWoA8`6ODk5 zNLUXl$EV{XQFWCE=vi9M;1H-KJP$2l^N=&TK`+hg9qHVZ&7>*+FT9 zYPmXHue`d?*LOW88CfQagCWJ*Lk`X#^)UlM)(Xr^_b|the@{$d^UVImKl6w4u)nT1 z0DIx|;U7xH$ooc^y7miSYnxa=Hne`z5gvA3%g3Tlq|({){$DjMZA^>L*Z( zvzKm`QO~% z>0DpR126D3{NweKby4(*Ig-+)SH1sFNEQyqLCP%{!CQ((0a=e#b&Jd;W4n`J!+!qn5o1YX_a8Tj3$Usirz$TNB=;#0FOfp~CeNfmqp!~xezN_R58yuRnI?_n}?Z7xD@y5 z892Ujyv%y?oghRUzlf3>abyH0Q{Jg^ahoWly4{8wl z{r&-e0A(v(zOYfjBCST>U{N`6=w3h4covJAYAPKSl3UMF^h8G0UZ=a0!mv(cD5*Y% zK9ZagP7hhI@N^ssJ+d|_P2ef}U9FN5k z_uvl4xX$FehUZ(3FThd<0*xV1pyHYX6!$dW#dP>+Lj3lOTbzsI@U}0=%<%e#^XZoD zkH&CntRuWcv~Dj?>1Qh@Ah?N*+JKKz$div1+*)#RUNK6L`8G0$7|(ql$NDL3*A@A@ z);T=>R(#6uHK~i_%cG5oN3UwetTldqXo2&v>ki5@dF%du$+o?Kl}=;w1*}@dk2^BI zi8gw+zXFDUPPFx#04u(#c>Bnx*%KMel>4yQTyIG*Q`Qo7BtLg`Ps}9H z-cVydz;)gFmqA6d75AJjmaC3_imf;j3uTtHaHC69j=2g87V}bv8f)5XoQ)JFwCUr> zkl%q*R*Ko!O^P9Ooj#6lVflmlSV8z|C0eO&BX;CDpsWJplo;%R zZ1KvFC}1F>6Az-9Q8a*}wLm>a)oc>lquur>(7C(T&C49hJGR`4^;&oJGAiK2$8>(? zYU;SVck0#&02aqn`*pn^NtzM*LmLge3O09_F|S=!nN7E2x9U6}V86iU%4+0^=l zUIi4~nMqZU*t%cvESdeZ8{SLDCou54x5#@Q9=*?r5e2p%_t2Gdz1Mn=JC zdF;?2L`H#9Fyzs_Z^c8Mtn*d0=|PPTe7`0QhIgV|jk0u@OXN9&by)$0jc+W(0gvgH zhe9xh-jWVEBoFCr0!*{tKB%);sE-4x5+GkKd~@hK;kD=amOi4SLx+-HeDUV2xF%n zB;uQpzHOvgOo9Gdy&1~gdhCde^cZV!W|9JBHIF%r6(=G=83ouBJi;F=@o$^uGzu#^>zKgtPE7JJJ#y1L5n>SIeOZ=}}w zzCHPUwQu?h;@DcGM~-ob9~d6NcYvhljVH^G?l{GQw3gqzuU}#hn-fGs=U!>E_1FJdiqp9Is9CrFM%=42N>liTby|(5R)KT{T~E=;fVcnw(yW zeX(LOgRK$OoU$+EMMQ|;i;-Wd+&^b+--^4;nng}97s|hW&tjb3xb;h)dp!D{s6?X$Sdr#t<8$ghlcSaGa_G) zzVAzc$e%o_yEKfSd1>h_v8i`uw+&jwDXMXXs|vQThMT_0?ffb=}(|s33}j2uLa=DIzH? zASsQ2QVNnocY{hdNFyyshe)Tw&>=ZAN-7=FG2cFeKJW9s*YBG@^rGhMb@qz;zSlZ? z7Sqj++y)!e83>@e*!5VEjy{=ES0xace@RqECd;m|nvJ>CZq>Cc-baP7;KL2J61nU$ z%x9YW>KOyYIiie-8N20{YK-e*NPczAxF<#mdD^=Y68mw2{5;n}LxK%&>8o{_*LvTa zzHCTVERxv)FMu1_k-y@?l`IHEONbobniHC#^bf+Z;BPi4Z4Y)W*htRJeaR!}wu^0rXuibf>hjJ|A#8hag}Q6K5NCC$ zbvwBiSB^hfYwv5m=XTO=IS0c~XkL6d=oI~|GC7quwCyp?s(5Ne6naCM0M4bn9H1UI zvAW6l=)F%ol@+m+r0P_G3e^>`rWDYvfK~%Owe!-SLSzS^HlwWL%j%^lt0Y0&B|TM)kqiDQN2LYeGaEpR-sQLa;dRvAa}n~C7tiRT zLC+}}93%%_@Wr#AvV1iUwHiO^%6qwuBRlCJSn>T;p}px;(!+*pKQ$wD)FKwfi8(KJ zEgoP92t~S=|IRDz{?YPyPE3t2q2qe6GK;Fdf7s91-TecVw&yO9gaUQVa7y`svGhgK zpb<(vs%QDE+s`2n)cLFRdG`kG^^umTLNl_&MtV{H6+-_sKkkeEodcQM7z48n_n3W- zk&P%t+dZ^|x|X*To6^xW^wy~ZbPEh69i*dA+LB3*U3*=rp{(qt9-p)T$K#NzgYV~LSKADkbXXI5bHKHqVy)Zyg zX>#Z))zn$q2istZe`j$$)TVn zZ1+N&uEFChhYmHr`|8-}{_x+i4={$~|Bop5Kk@_YJ1@wK#o9CUS-SPDf(~MT$2(kK zJZxN?BBujgVg4gQAkB4f&YT57ac(3VcW@X^710AG_jxWC%}4|84vm3+wqvJ*DjZCX zSoJGl=8SGM&{r_lN*}V6vxJb+T@ejVl;Uk!Y4rD}8B?BgwT~tmU3gj<9Hf`gu`iSx zLxOk!?-u>MT3mGOL^R5lne&;2881kdfdxTJcv(38MaNL9Z4CLdVLOCg+lYV86Bg#u zt7H>w*HUuqZS04~Q=CJGNs3LuqeqV?(#=d???RhyA@wJin>x>fc}8$-8k*k0M=uY! zoPccKe9~icK9?lV4UEne*Op4FTA7B=>#U`H6O(&wBZZ04l{0K;aF)>}v0~-Ap{k!^ zCw$&Q=k2=lT6br)D76FY?129b^qwWJI6(W1KTZgJfi5dX;yN#Q>ruN1d2Z@EXsE{9 zfavMF^!}|BmWx3WS)$Dba5@1&2FY@|SW~5F-&my=l_wb-^pVmsHZRq+Cus0L*M-U& z`_l<$QsBWT$Od}ln23KRZheK|T9T9vGyfFZS$}CL!o5?ZdAepY2&;67g;42{HXXR3 z+*f58FN?7-mS}kf<#moO4<@b{7Je4J&BwI$s^(eI_{v1i++%v9+$Rb^fQ#neJ3aU) zWBKZd$}ftS_Ra!Cg-*(mI=Q9OhehHL$kyceiw#)i?Y9N((r-f=y8GF!e=|!M>sX}T zMr35TIeh@}2j2H`*g{6fBxe%BHXDj9x<9_sOy!{|iqn)GR=QJlD(dHjG0?fa@&;t; zY%usbd|t#gGvdLcDh|wloVwt)gTeUO5WC>10;dw6Dmz%s{iX-vnLQ7}J#7op=$J3( zojbG1dm@}wb(6Y|>vA-aQHaA^LG)W;YHTB{>Y;a!cI;S`Z_SjdNM)+%C;t>zwwW4T zR;ABwyOJp(y?VyrRM82XEDGJ`cWc4rQ;By(7ypT)9)IOPB_dgm7jJ5WE^*94C z^Rc~Bd-nFd$6zIR0z_k;W56vnYOPWi>CXDQ^#MT-=g#{bG0DhIzD6d065 zh?PchFYh#63B*}#u-zBwNZj{|z8~w7tX+P@^(@}YcbA|zlZuTp6i+i!>$5@# z_ekLLEJjHKF{{j~B3_BP?&Wf0X%OI(t#AqG8ccup*V(Q?IcmAvlc}$f2HmPgq1Od| z=YG@P2Ejus&WE30oJ;|=7|UaSZ({!F>Bj)=-_?fIjlYNNw!14EX`s;^YqxJ+C@a*{ z>HUrs?2L0&1xVi5zu!+OZbbD+%6#s|ehJ+{CcOQv4xh4w2ETb3!k&>sl=V8o){lW&NY0i z%~)&yGo%5@DiPog-by&&MWd`V!$d*`nLp5@3Dq|}C5rTz+4n$A2QOXqrjrh!$x`B$ z@g9DA^U=Lb=F-V{)7_?AemTBg{ysCdx*p(c!}hP7Tzr?o|WMq^8h zK6qq0m|VMA%<>xZ)NM8~eBw^%7_Nt8j=tCSa9>-6)n3bdHN4Y(L2_s7E49Z%DzD#n z#7EwIIm0GUM2aqV{)pR|1y>X`V;d72tlsz(%ZRrH34pQPhVo^NQC$@$Cfnvltzbk& zDT!abfLU_Fxre;JpkmL^W_Fat#&JDF*;x_8G1z!4XgxkTIk5U!Bb%}nSz@9Aq8eU0 ziWJbxtf@h^DF^SGx`%8QYR0jA=#S${wmOPi)^q<+A`LnNg~6_RNn z5-Q?y5FUyyeM%S;8#MwW+QTH((<=shpF%k%#+6UDI(Sb7Iz$Y9M8RIn4CU^S+igYl zM3rQCKXd3@!kQf`_7XliTfp2oIm`MV}|_UR*f36iH+ClW>gk4 zCDobC??m9i(zyb56+Ji$wBVD)0Q5C&C$e?=EPpyHe#64c6eN`#p)Pe@TjBOETHKYN zTj}A&_}H@<*rRM=bVKFKQC+h?e-K=#rD3*ez1~-!Y-~>gmMCDb4H@*XSq_%njkdYr{x5tdwhhklI`k*HXmBQ4 zzVho=D7jTNZB6lN@M4#nfo-$H5^8MT?ZnCIY+o}zJN+!a{)j>RgY~agmQW=`)KB%I zoz#{icK4;z)Vr!5XE(hLWZm~C^fp zCI#U}SfW+1@{|YK<$m$zH;;C$dvr>f#|2`^XKCmjeU6DM*gaDF5`~}Hw?yVD*f)j8 z!^49pZO+sMAGKa}`+Wb^dqTnyf&K1v+bY7ICC8|sA3t7Zf@Oe(e2Y!0BsSpf8nFmj zOlgSMo=`p6;w<(`3SV=YqQn!iZd4}uIe%8)&!`(Gi)0``nC%~A;vuXo>mJxrqfTni z1giVp1&??8g6)Slmzq3MPu06C97&tGBlsbQqg*NC0r~B|RacoW4@6M zTS~@c4}2#nEmRv1zDZ2zJqH*mPmi!jPMA#c;<7>2%elA5?2v_qEH${wZ~Ln0U>@f| zze#)^^lSnn)#wzJcBor$VMP=S0n^iNfl z%|q(eBfWBQW^#|~BX3X(cxR7K*0WdiU3V-t4va%l8_iqA!l&V(YIBKxM+WLGgWM4{ zw%hF`&Va>6$VydwFDZGzY*kkjk+229?4eY-q+a(b4%LIR1To1W;HG);)>C2?UBt9p zg%*@HCqL5}-|y}PT)k1EMbY7qZ-B_-b2!Q2FniKm-BywBCeNWFU4#4>6Q@mlH>{pe z_1(v7DtDs#e$AJr?|ok251zR?dI7e1`F!gWd*ms?2iqiPe|Ej)5d4k2x#b2f2wvqc zj&+GPLa92TKxqCK|swJ1E zu7-CNHI4z(o9fD6wXAgJa^U!iReNrSoL)%Fi{7eu`FfvXogc<5&!cKGGtTeP6V?%1 zzuWMbA@BF45s!;7CCuVo)=gceccD+eI$RwY7$A!)&>?9H4?%SQj&@VJ$9QG*w82}a z!@-_4JYnz#SYCPh;Uu@ipk;2<{X@8Y4Pm|F3+-TOI<1Nah3Rlpu4DWtCpfZGi6DdA%XI+vD+%9LbpG;8Sw5AW)N3>h7-{U%i;a88*_p7!n1UR^If zQ^7{ADf#dl^VY=UlpVquSvTN-fNL!wu-P}=EIsd6>_|!;O551Et-FRmhRpH zY4?o5BdcS0+B5D(J$9U-1|z`yWg2Y=6Uex^Ne!R4z7sEKJeHdI-Nbh1LhXRuY-E>) zE@4|Z)dR_!arsC%kl+`jE!fztF3^UB?YBSc;&-77Q9UuxjIQUOS|(b3@3 z(nWQF50O3;xs+cWc3F5o^D;aZ)WOVUX_JC1@IHixlohHoE}a2ulo+VZ6ApcsjL4ic zfu(s;gvta(T7tNt!#izGB2K&PEgq=Zq^(_c&vDF3pNp%q#pQ)UiCWJMj9fcOpB~lx zmV6P4h+IwTcolr1R_sT?qgZJ<`1)jdZV$c#-IY8?hvGn519rEf3$P)AbK6w98PS|^5(j(2K{n1mJL7JfqzrpOKwnxzce&Dh(BVIM zLg!24;ykkRtI$c)sZC$~%zX)*cW}3ij~{ur4=)&qa*M=ar3B*_+u?pFqM#HYh4%nM zyHyQ%K=4;L0#Omh7+2I>SJ?mN2Etttsj%TboOzcdi4A*n%_J~m1+r~?lY@m$=sy5552JuvQxoGM++YiQrq zrG96Hv-d>3zwLfyMH}Wbn(Fj=t3$!>vs2DpluPTXjYilx`UdQKZHZcI5t1|hmCnTq zPhD;Idk?;k%-n~{9DC>;U5&+4aLF{mPYGg6Qd&kx)S=p78aMdPCx;?Udi<74S4Ly} zy>(3KOVhO5w&MjIzLGw@{jP&}PC-T~G;45lh$3HI4?x_DI(W)%#U{! zAwyenS3RZCkVf;tM?72v_*@Xuhb8Quzkl!RJ3Eg;IsiBGl|_56G~QT?ntMjPzY*qe zsjaq;GYd0Lw}oLJ;v`A%jauy)^=jC}dbv263^qxg@^(2k=Uit0Wcdg{=S`2hjBsWh4CgFlhQ-+>U`O}0Q|fY*61ZpeZl13sH?;G*$9#rbJ;{#W`RHFRmQK0}(W7>;rdLeEWo z_>p77l$?XA9K24g;9Y?MNRR#ShG%=9 z$7$&-?F25!GG15J_K%0@HpjUfmfh7T0b+0N=>PJQ7!qX{)9>7{P-mn@pWe5(vw#Kcf(>RC1 zpc`%1$qfkT`oH^K*6W?)W+De553!Z$A94Yv^wtN;XWlAFNu=Q#QvS1>U))!{&c^=Z zw^kHqGaiO|T>HNf^W!NyDDwvkD0!?|%%<8}kBQ{c_3@rkC@!7W9ri;tr|c=+R}rGr zSNDDwQQA!0ZG06#G)-Z2Ij?!IcHNV$=xm2K*{hKsP7KWKJxKrYvtb-af=vi`fLQR& z&NfqM)H3=h&yBUlAwf69{>LOweF&Pf%Dgu^Wd6Z_FU4EO1$#6`p~%kVNu4VVj&E6O z&i$_rF2LnnVlIrwg%)dwh~K}5K5zh38-U(HB^=;1Hn#TnTXo3-?mBIR{K20? zIe;jH0>E5H96mPcBph!CqB85ds5|T+VW&U&A4ak@zG6se*>CL{@v4ag~XqI!Isb#4Vh`9aB1gDd&h z6?Bbcl%dN3Na|Ie2j0$|^Zkp|-WeB&YXelOHKzng_oJqh_JxM4Oin@im$>asPLOuy zHh(JOf^DNc-!?8BPE`(WVZt^kKmGZphJW0$dD?vwwd&Wf^X2`o$7e2-0eGT9%m2+Y zW(e(XP6g_lvyCwZ7MI?)Yd*vVyeTT4PU+z^TgkeEoecWK^E6gF*I+sNB zY?CA#3x)ntO5PJ6dk% z4^?zCO~O#QHxz&yc9C`4fCRGpz2{4^Uzb~uO+`xrvT;j6W|BP>m3W8P#2q!=Zqd+# z&on<0c=o8;V^%fQh3)tFpwn5o-8icp&6Nr9a@mIUba6;psgh1${H&So4yLBS(#OhQ zU5zX5PU)c(NJ{<;^wem*rJ$$%lLJQB#1iNPLVWMarSb*-SqO`$c`vZA6BOlJclA#3 z67}}F^hSRlpF0b_+Tn07JWxYXBHbEFPETdgdD593xE_a#J>7Nc?ly4tbtt%_hM;`-e8m^HsnJ@*>bNwdwe$0PyiU-cOmV=k)XUKhKI4AeWEqPvPq%6$OK> z(zmrx+-hUl`sM`^hfc;6%z|M zFUAIQAh|-F>sN3vN?PZ6HTO-(jpyScDyF&>7>Rj2TPj7x1vv|@-1TTZAkS!4{Hlr9 zny?dAc%XBs(GhLikynX;Wi9f$=@ZMUUhJ#~qtvB`JOUpgCJp?L)ff{}Ql_i6Vg+Ug zR;+?XN1e{<^EGu0YwYJ@B-5DJ#;a*Pe;MpcW>*hGrOj=*n>evhNf%Am)qM8+%2vRU z7qErl;reXS)YmFEN?7nN)cTsjH$qhJw&5y=t=R#r_mr{PU$gw^6QAu*LxXNrId~Ci zx6i(-XSvh8{Te`I9-}iynsCn_1a|O3SofB&l3)l(wBF<8r$w~}Jx@I%wU9T;$d7_9 zR7sRm9c+MfX!cZC1RpT%Cq-)LB`mBj7)9(b+Yo~ z^Rqm$IQZ?S=4S46u1yy}q2uaYTQN$w=BfCx?ze4S%0y@-| z+qw@--cwM9l*V12&3a9u-^ZzV>k@De$=%<-TOne@QuH%Wdt;ZQ`iHT9o8m}&+fT^0 zu_p~8Vs-ao=p0+VQo5h{m!4^?MYO(Oy4O9iHnAS!fV8~VN`1GuA$M`QaU>>G*FRSm zq+B$R-XBh2`use-4*CL?Lo}vm!oOqZ#WBV83b=~q^B%Us{^`<5d{%z6E6ROLPcJ2% z<>wSI2%(Q!Wz*I;1$HIm4sr-B6m#gD)N3XYIO~l)sUTHPhHx1GGEdN!nN9o>7e_P? zOI}|MrWQH{pX!cQ3q?c6{{@*7-H!CP<-dd^o-#j!ysYl*k5>?s$38#}6atZKfpprHw!4OYIbZ_|!!ixn+a@P(8ECgG zd4kEn;Qr}qZIFc1-k=Gss0CB^6GRIjbUcEjSUctq7i52iUHM#T*s_)K)l_x5u))l(0Kj3NG4c@g=s zXO;~6<~)eqkjAn#Ds<+^eMqaTVX4pvu92qynfJX89QcUlbBLpjJsH7gJx?1+jrw)# z^Hq0P*3B+tcGhZ3vLJsx)POmQ-hP8)bilpw!Fr$U6F0WbKKd z%vW6&nKFTI43$87))e*6P(zRvfr5LkbGnNBoPjLLo8Mg%pEFp(EC*@v$m68n|5~Z& zJFFduqS{*!D*NzetaN#vW$(P~cf~0}mKm<_kiE|126UrGCoB#?|7o2}XK>mJ<_&Ny zB_>V%7jo21zcqTZ|-MeB0GTB>e+sbPjX7!e!I^`tw) zBhyR(J^wX@KUtWI=!TS(KE!4K%lOCXAS}^WhXO-pfir zT*=*vgfxVIv1@O#{Xj(z2B5{VP;ClV?-{3G^*?FkMW^=G{f*G~&N|FpJUYfcgw6-A zkLOa{8ef9gayz1vP42@ZeVbST^5@*rS+Bg63;T)(Ytd`9GLVWgj+c|Jfz{XLXFvH* z7||s(v~uRBCYVz20QX}p3R}>L?0JRzXberyrVwyTiyOsSbQaZNP^k`h-q>5LO(}J~ z-aO!{j^6X(jQqdh({gu^q9;@D`{T0^rbPrgbj05t>(_(OnYwMQ z#S920NA;s?_aO;-Zqj2JdF_$B%(T~Oz2332J>YM>o}1b67HgZj0J58PLP`r(<(VIp z6P$)4nD~5hyU!CJBb>ai01a$4)nphSvj)i0pfN3pTaP*CR~i#@v#{PGOYxx&gJc1x z84mEw4##wMZZ!h?!@$7EJ;>*b&=RTAGox0ix%r{PvAB;Rz4KI2a>e_1$FAklLHvAMyvAX5%{hv@f$#=FQg#Nw`)mk^$!ZfDpp8 z-rE8mCX8X>*AV@sZ@1>xlM&6m;2Ph1jQp@99;w(uXs_U()O9Y*T?|8UQL}VM$nGrE zOQxBjJ3(H}>{9oxj1+pT2_Zi`i}wfh3;d{_pI=Q-5d{8su}=waoOKe;8HVz6a-4h! zCj@_FLlQt0HI3%np^o8ZmSG9Mn8c&oKNUUI4PJgi$ozzAA7Y1d@*r|TM9m53@javVs(7*hy;_QkHt6F=f z_W+18vqNeLbehQH{)x;VZ+Q{+$V8-Yc+VU7ZHJ$mU+T~?U-XIKIxP#z0IV7ollf3p z(-g|b6ySdI*Vf=ZdhAB~qHRDH!?F0}fc@Imy^GnhcLQ@O7Wi?MjG_2Tlryc0q^xRR#iQVL|Oau!31uwW5SMDX@D?jHm!ae%A1GHPB-U?&LUIU0iKA zLnx9PT%o^EJA-P*GT6luF$<|ANMN1{qsiMXgoFw{$5H$xuIi!^Q8tUUrL&JqkXdNy z(;LD0e@jd+zDx(aL8CLAj@JiJ-{cM~=OJ1~-|^ibrSYX}7y^8wu227^(e^39x~l3k zyO;o)n7da-PS^B~Vl?-htk@c`gzVPadgCu4Mfund`6E!~M$8X-3R{6m(|3}X_yYdM zd)0nk9B((9fOGZ_A0|*n?H?qV&-2HTzsWo2vLquzllnd?g2fs|#L9(s7S+9c4*G(N zizmbReyt3t_^i^lLh>1D#zw}Vbe6QAm(I@$)MP<(wBj7LFZ51+{@OtNQFS$m?3!Ja zBcdq)k7et^T?_5NMc$(Eg}P?jhsC$_U;l%1xcX+MS3*S}OY5h2Z6JlIrg*0v&$tZ- zSXuYDt&?Zw(p=?%iWBCbK@Muav%fhJ#b$*y?$yKaF0x`4iS+MVAZ)*{@$kIYp@&qY ztl`o+x%&ZmfQAEoWn<{uHxr*r%i5)Rq|e^Wr_2Mf+M!Y0PA*^Zvh1eI5Ciy=Kc>8R z379zovpozKul38x)l&G3z_YCTGQ4eNDVNoe+8g3G|kJ4LRZUrRl>x?ggvQA)5;zG7V`6|XhMWz zyyEH)?aH<2`6GUinn8Le4n$MD?im26pHNW-He>CSq7ID>{s3z4PY=H}-Yq(;q8vbn zzxgWSOw%r(a=>KWCR_=pHg)tCH5qmAuOjYN=^uL*POWp{!mqGnyFsh3mD>vyW>Wp5 zVs^)IoGyB$-WBc-xWdY2yPS>hEwKKp?XSK*dSV#M4dMnClg(x~V!8+*jo4bUWofP@ z2p`SoGEM6-)F|IOx^X_DGL;kCG5NS(v_6+RjhtS_#SIlE&@5RT;h_aZl@P5rSMfna zHL~%{^Tc_{Y4)togSElEZ|~rUL`273j}3Z)M6{Y-IU;t8L;S;LE2xr6!Bjxjq5Z&B zU2)gd)fHD6=j|zvwCPlNQfO1uLCZ(s8>z=LP6%$)a%6y(myR_dQdHBsjmqU4fLu+N z3^O2NYD-8A47m9*D?JTL0rXK4Z*6BChP-((96K%;vnJEM*gy6ivp-#dfXlMPl;;V^;lfuK16QlvPUp!4&J{{}I`m^NB)|Xnzk}(gnYMN6M!N(`C4i!w7{Lrz z?9bkM**kqkZF?z)3?FJCsxFKDdJn*#MVuuhD_iTTW=Bvc#Fk39JiG(M6YrqG_e`v1 zAcmqPwcLz3%r2CRqJ;$AcO5mcy&86M@Xt=zIok>{<}6pLk`t11yTV0QT*a=?_t682 z?mcjx%2E^lsE+fIkr1_aT$_9ewK(#6Te{x%SB+ga<-@1;e$Ml5BOJe2&JgfYNygXz zz?biK5d)A0X|pgQU~sgXGyhp8N6BtoFGv4RkE7D8YdQNV#z*KB8zq~>PnSL>f`bJE zKReabXIIn_lo*(T46NaKLgG;WNL95=(Z}U^gKas1vj)%)9ga(RdCCtirr8%O_6UP% zDA~sl&hmEU1=&~X?C2P=-yZI@lZt4pJEm?$HXi&s*q=EHLI=&$mG3(uTw=24Wn~O$ z6g}r3&m5+Eyz-eRb;fUrCFScPg~O{a_YK zF=`Ce6*hIF-iqhxC+9eeFH~962&#@%i?Ji18_ji*TMB*WS+dL#k-3E8v>BXzmBc^XN?L-W5D28CuZKV+%t7kZ!ITJf(9P77C~%nh>k^CI}a;lJKTK0chV#|_* zmlDuJ5)l*ujmLq>elTZhnTy6#M^wme=BPeAiLL`pj*-q2D5*lg9k*2UE=a_Z`?(Oe zBBz~N*|lhN(BnGY-UDDa!1UdBGHf|BXJG4kZgqbE0;-U3TSAJ@>i z@i>{>bL#}h!bK=BybF!3a1>V>1kz`wE~XB?{sAa1B4azpPhuDp7F%j1K@rpmsL-T2#BhIW`lt?~>o! z2n4;%Nb+$OT@8!N$F%4euMznM_aWrle)l>;@rfw_FI6U1;UhhXKFo2GUSj3^5BW)_ zAOWdqCDsrJ^b$nQqakvHi)b9L#}|TMAEH}c_^{?+VK^=*7he#V)`OaN@Q7lpAF}~f zkAAJ6u5etu0xMBM1E!&@6wADGz|q0jsn8TLC~lXoCMG?yM8` zI^Bh9fxn87wyJ|xM@~lU6DB##oDE)9^H76_!CH&(-#u4Kg*UGbPrNytH8LEA^61{L zl1T%}wkYclfg<8Iv>#-CjdcM?2b6s%#>=QqJ>pBtzj0Sua>GwgRud9MESyTp9S~iG zh1@7-h18UsPCX|So+G0DwMR+>OsybP1Qm=hxuGo$FPg$0!Udv5PMfz5*gqfyVxfds zSC)A&ND51<>GikOraUHbL*=R5WzWE_HJzX}L8Y}n7zI)6;0d}wxF83@HXfaGlU*|~ z(9o8ce?(JRbQg5KZUVf!GV6B2+tK(=VjUXH!c+&x>Hitxns<3*I`6mFI)9m?iOaHX zA>{Q9sW1zV>B- z@|2Lsb#c>AEP882jKwYC4U#a;#LL%b<*Z}FgZp0f5d$75ez1-F`vNyVw))MEZoUAm zUHn?d_4|;6biX^#E@nD}RWd~me{?u2m-_e(4bx(v@qi}D@aSnv@6RND2VsSF#0@xW za>wf>n#qsZ03HRgs&KX@0dH7xKjZeVhxpVv+*+2?WGly( z0YHY4v{TdrxchKy1%ZLGVxO2V&mQN(-ECVP<^>>Cj#t;zhmh2*RAgk*%%3X?&R6%N zvhe_`-*G|*_;?@p=C01B0l?9Xg{!2$-wnEVpsCxhnZZT0cl>cD^qPOTCT~&_w4QP#89_S3{SD8T4`%3*8+n1h>2d9akg>qY0 z$013blrm&Xy!qb@0LHxFQOhW81{{j{F=0V9=xY3#xN(z<{;Yz*1A0F@ zqE8dDBfrE?eYcSlFDT{uho%8JnrRmeB{Un>oGwaz;f^4)HZy1BN9tGrugP&ruqIW# zgn#~E5-jHqF7DX@)->ytoGYVjLKkX}`bUSfowhh8Yk_+WqXjVUEbF6hN+CdN0hxX) z^J62)U)RT>$B9b8+aBPR@G&d8(<;_O~51!7{EB?h48n~I0<-}Ng3Fc5qu9_ z5+8*3VV%1>p2ZraGNH+h_ZY->B7iaUT#4429B;XfnS&B}lR=6UPA}I=5J81FCAV(zDn(`NFggq389D z;astBq3svu(~jYHfFjXr$mwgu5}gV`9PkpwH8tNhw%)XK^*l7#n%J)=MD4BUorm!n z^1Yv=o@3KjLvjS@YIqNzHR2a{AStp1NRj`OOrO)@L?r@`@|DHVkQpk3=FA%EDzo(+ ztm525)Z!+;O;@@r*lvMsFo0Up)r#_lV+?&$&+Ym&8Ypd6ijkA27pg9Q)q>RZKLl&2 z6n*2Dh#sOB>rFN=I`rzIGamI(x!Y`Ip9lMk%Fh>9%~XNDNWd5v8(R^dobmu{SjlZP zD(lv;#U43mR|=sRB?0#!?GbpFwCe$HJ}im4zi9ZU8@p6QjT^V$0_Heo!&6;Owb%qH5(mm>f?zuT8)BC&lbP9#M=Tsab?S zO@a2lYca3bl~qrDcN074@V7qc?5_mP?7IkP~Can!Oo*p~B?ehDVNB^e|CXV5zfB3mM;6OG{hPtWXz+R81L z)wW!nz;x?D(p}WaiCZ_FShX(5S%8}TodT?6_+&`a3CV~(F+ta@EQs*&lEX& z%?mei-w=66j8?SAzYPtTU6jo(1sZ(Gw-sAexhJWP-Iy>XFEl%GZvGFFP!gO3TnIhd z)pRKk?Nm8>GMbC6TI&HfHGWHg4p3!Fp8L%mU;39Kc~bxC6XSs58|m|&Yzknwav6zI zGWya_aL<)}ZMPNCE$+SI25K@q6RR zxe;a(a&k!o-{r~f(fnjY>v6;Efpm{@UzLruzdu&zb3300Lu> z_)$adTtjzO{SuMuLi?wXzO7HUrytN$ds)ScAuJ3X6_j1CaC*RPhhPnOd6U_2q~H6V z3~@p-Oh+Jf3R)M#&Gxvdqty*m?EqT11@@|n5goz1hL-w*pbLiRpr!qHc!-+)8OsgB z+)7_R>Crp&D%I^~iRr+7lR9kluZfpxh3K!q`-%2F_Ov)y7P+m!j3Fd3oDWT3T0iWp zq_sTVjpu&c10;y2*ZSy74;o#z`&30p5Q~F)m~O7F?EHk-G4nu_Z+r)CxdSVCf?vR! zJDuHEveEXyxHA9_Iu(5m5k-p&wO_}|sJMzBvW_gN85ndcOn|>}_Cgy|4h<+Pgj{b0 zBVPYCpd8)Zj5kTWKY5HR{sGKb<%o3b)El}N9Gn=RRm?azZ8`Wa|11AI`d*=yD0#VW zjma~i6%5n0tmHLqob`pbepWJ(Zx3BG*gkilxK&RnbK!b)2dn-Vbg+hH8t$14#tMK* zDVPKEyFdouMuYR`Mwm$$*aZ{3xB%_SIEG_gc6E6VcJ!Wb_7@}p`1K7%D8kctpxpd_ zDAC@JW5~zJ-(}p+1z2?X+Y2wB_9x8fa&%KBLxY+S{=~2XfCtdF7CieY-m01QhrxU@ zpOU0iE1`Q+zm^mZ5-^p4S}vW*`$-Zi*Y)EqFf12L$W4-@*W|GjBlbz{BQ$fRb+K04Rmy`1-ZSr%$3KAYg`>1Wyt-25SU5-9C*AL6Q?c0v@H~{$5^QzZnP;v5@Q| zYQfm8fXFRHx7Gcnbb}y$5=yyEQ8zBh^u0b%^7>Cp)1@$%Uq3Xr5KY9U-h|eVQo}95 z$Yqbvx+=>sB-^r2?mzue!#v34zzm)-n47P5`vUn-a3nJ8HqQo`^l5@14_Wdo;4MmV z4-!m1i5;RFQs8<+-r1lahz5clv{V+>>SFKvt=siQx-;FTGNJZ*(nOd6wG70&?vC9Y);_~h7iba@8lBQck4~jsH>4p0^vf_5*(2fD zDSqxVCDvk$N@%z5xKLZoSw?jmxP8XC#0(=rOR-8i|2J5GF^8dfum4dQ(53o$9hi+C z8!xhru?Fs;JtT(^D;4#!0QD3UT&H!a*8}aKy&>}>TkRh~K*HCVR(pvm!3*~Y*Q7&5}^ij+>g&aGfo zQ&kNnNNa&SKMK>)x#y*g;ioai_d;;+7vBY;D(&5=9-kbPYe38K-)(VNn%TVM4g#Ni z2LOs35t*S^d!VBo`8A8Ym`m)YjM&@#D{NU0rpg)6?ftq}FOB^Ari=rTS)XQc_V;7N zs*2uhtYj-Z-fNo)7w_{BX*gc%3>Ml$y>OazEN){81#<+qUgv#=FNGa!CW8T}TxbAF zN$U9n-^(m&ev;5g19+)5`bm1NVp_Q><`(U{ z(yGCJ)Zn;V|X3P-&z|t^M0OAWMYVOQd(;#C&1;n;_HF((mQm93#9; zc?mrOX>0iD7HtV1a@~9c+~Ys%GmQWLpa*Vow2UNv`tU#O70UA4FN6U(xmnse@SnbF z;?lJb?aK65S_6P{_4kc)3f8XrJ`7s1W+ri75?Az$1{zXj* zg!hz3qj3Oz?8VjVLMW1(TkwP=fw>DVI;!uG6z-NF2L?-_bD%q+TYGsN#W`?4P28tNgfCca>L67B}uHZj2Zj z5!BsLfd<_r8E=5O)(CA82Gl|R)<@KW!Z??hd?@>aDV~~=bMB9{e(pa2Hgh# zf!l@)D7K{cWA$sJ$;W3io~K={nqr^>w2#{SQuTX0Ja!k!;UrmiomfjelidIuMd*4L z;vXgUf7lhEYbt`UsO9 zP+giAk3cX^q4^)j=UIWZ)TFIT*=;s?Ue}2T^iwR_6q$&(lb*^-nY*Ygtr%R?%^K zbr=q+cVg`b8H6Mkgv=|x!+LOjNU)-p4fA%vhw!67jt9_2%TXLW2P(kZs_@b2V?ge@ zJwFFO>Hn(3;E2(4*eLSP!wYud&N}4;@F$8u7x=H)R&BG1GX!<({PX^%tY`^!sk2lR z>CCAkZkrfl5j?;m(1CoY1L$|js|U)~2bW+<(da%QxS8eZ^@bVF7D71; zNBT{b3GDcX;3tsVR>Tid~PktqsAAw;LUb6nG4!9*$pzg3=Wvo=O!y-BObvs#aIt zxfqG#C1H7ykuh?BE`u%)6C0ln`wn+x3>R@!IE1u(My{z^mY`!6ayGm=C}DKvPNsH^YqDxwlj2E|ijmQoM=>b3_wJC=5Q05t_K z>swz{@G}MF@CokU5srBB@+D42_2Eb@_8m!G5&H;y8fJ?F>^nn&JPLvOYAY3%cYQ7& zbdyjKRPH-}dd6!Y>3 zA@wc-2A#3t%}Dh0=G6VSq8|t^%0A}4rZ^a~39mfL$^TVjq~7?2WGip~sa15-&~QO| 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 z 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∓B@bn?@0o2%CKmfvldq(6?bmhVa(mcUP!2e@v%ur|3|=u66H zR@6PuW`;RJk9z!qZ#ceYG@(`!7JkgaXKz~aDgoxP?d@vm@BYcVP9WWDp)Tu!xWlKs zaQOYzriC*%Ej7YDbSG`w%w_a{^ulxb* z3p@BJ?6?RSaXCHU`di6;Ursh?TW(XR$g=#RD{~V3{nL2T0)UIXW*K3#b7zO#Bc#cM zS9n2IZr@JsF@9<&J(dic1-yq47^c%Qf87$igh4k;9~&}Rmy!4=#If{PpC>Gi4qGmj z{n=6}!&5=%ytC&%Hg!uiYrJiAtHUWgaZmTf%(wXiciobuo5BwY_LA9dNQ7{?vN-f9^prjI4bjqyFu@e{mPo)Ml^z1r(b8uIP?{yl)F z7_)P7Mwle{rbjXqHltnS-1yB44_)vIKc;5bQ5{ASH4J^%LI(%%bGca+U~3bU>vHlx zpeo7g!90U7nga?J2Q%@~t5rutZgh%W)hUDAL4ra!+~F+OMdeRCPq?#fy>&l*G@=9+`zYQx z{?tG$z2O;h5k=2&-{5$q=4HC6c0n1-aPm~C&DbHfM-#Iu8UCGTy}7)LG$!ht+fs)% zn?M!b-=*Nux2gqvE_y0zcWess*$bDDLjBDI5PNi6Wn1_p(E&eO)8^k&Q`n5k7cicT zX$7XJi{IQ+21T0-3YMk@67-telda38h)$42eIzv7EjU^2=QGi(doj)w)f7n8vqK+V z1scz@rKDl%GHm2Lh_AYZPy{|tkmPg(*Gjls|8W+&?K7+KyRQNk%b^|%ie1?)&8N$6 zgafDxx0HxIi|jV2LMOMQBcjoc$x?#t2xnKnfI*txDe*Ka<)7~OwM$JzE9eGSK)?5- zT{$*&zsk2X9SjbT-2Mr6yNbp|?yt-rgr>WHL(_YJ_b@iLPeSysED4x$?I$eBpds8f zbFvPza)%;h=tbmcPB#Fj+q>ugEFr#MR}uTsIk?s0XG3-bj5@UsOmHYNxfIc@+j2M_ zzF%so-cgXHL!CFu{_7e+wI>J^ZGtWZ*Q%Ps+SwIbU6uK6RywjF-+cR?O3}qCx$Ai_ zpH4TZuqGpQ>3FS#SP}uYT#94g=Tk4|FgSv{oc~eE@5}(D3?80^McXyHS0laMjcaQ1 zdGrdsnBPjTf1I~DF|n$6ua?m=;DDz&Q>lT8d>NHdqAafd`Lj34>`Y~uu-R_o4@9T@ z*&**PZaYwgEtRkdC-Z2`!C(#^t3=;d=HeiEQ{;fSWVGLTKNG_c-&9C0@r_(+!+!Ee zG62LYf$sSlb|cJDxEhAr;p1Zee9U`Q7gMzf4)ydatkS!}6xFL={{+rrW%-uVQgCARRpXAbuu=;C?3X7xE5P97Z)&JKiN#S5;Q&mC6{SW=v#vx&I$q zUmX@@^Suv(Akv`HC8-EVBds7I0w&$vAq^4=(k&rfA}WpaQqm=*ba!{GOYHvUS$*I4 z^S!R$^M{upxbw`MIdh-;KIe>tv05*s>k|kIJ*@Y4(1mNCE&0oFNFVN2-^;#GZY>Hc z>Us<9j8F*2oX{XhWxy9VY!w?LQ~&7;3+h+W|DtdSg=l8~pxY+`8%a>$dIZkO;we z0Asp87yI-b-!?rhXUNz)pEefqHhOmEgz)P<^x!=`C_gkt73;9*jQ-I3-55og)g&eL z=%%Y;)9Gg(l@P9=sKew5JXT<1in_T5fRKxRRNPSh2-*&!B{f_^noPp~@%h=HNdY>D zQzb3(s!I42=$@O!4Q(g!2KSg%1N34IWmWP$FtANoA`175^vKMBEDv#I^;yYoL_pK*`K2)=U~5W$K_U)tH;YDI>9~?2@VhXMu+da#`6W= zLN|_iFAiv!*?a`G(k@MV5!!tw#p5FDa#Wd#^)+)imr5t~Z_h|T=)A9Lq>uI63G;Q| zidbWSJXK+VhmahtTPQe+7{h+p)}LFq)BY=cV?enx=(uQFxtcq>&_$*WdGOWUFs~W;l*Dsy~f=}T?7TO$@+G| zg2xr5Wh>*h{o3f4jCNh1+7;THD+&{5nXQ%x$z>e`vC>oz_LkW!iF!JM%6O}Z)3-3h z`^Uh1OD|nBiNb7OGgQ>D0>~r6{R0+OXUvphr4m8uEPjxy6li#9e;oUOuFzk(&P~a!NBBwsLa# zb(m>~_aae}ai&cusmX?oPmG_uRz*^u(z)})nz|(0ZhDB4P(jaBKHvk)(-qZ5C3!OO z0p*ZdVXcOajKBPoA_l$*Vq`QAQTr$>Xfs)Tw5@ zeu>D`-NHjCCyNWN%sM(HUZh@fT_55*k;R0iiI~6Z5Ut!jv;8JhTwH~@C2gtu5(0nf zNUisHL7|M-gO)x7x$D|R-9JMH>DDk3dF`FJ&yD0Co>U~tZUSZ{uJ_RPTg$|v8jn}+ z6_bnC8);daOBwtGr*oZSn@#@N{a%44MKU#zVVnvS_Q`Gt2^K@paxwQMXPXm9r_C<0 zYQuM&i$NJcF;yg?ZM~4j|8X*a8b>=B^XppGpsG%$4y?TOXhHXDrUejFrB#J1ZQly&=!b z9=kT0Cfp~8EoSQlzgViMn>`DBI1Vv@KDe^8Lzsj1Yn{UBxw!NsAOPP*u5!A(oJ5L) zORJE-hc-0Mssi0FD%2N|?+$5!;+grGRiDT8ahotyDmw|XwTNp5geN9miTV`xrYsU; zIIp&tY0pU7mwTvyRn3%^T2;oHj2RiN7$ueNpERDE`+eG|Lnnn8J;dJf9GJy&U6r%P z6chKta1N17Qsth!ihS!a#hmDSD{;P-C*!bCz6XHJ{LBzbamEzv{Hn z#tXVW0)QYRru2O~Z=&7w53?ioL_7wGM2cI+?G;jC)_oE^l#`{drnYg(O!;O{E9n~B z^{fOgJ>@ofE1&0{_LnYo&5C_M|H?JN{ctyHDiM)(RT0aohM4n6 z0782{sXh+tsf=NT>FKJEWzrL`ELKm*kqjGVdQeg*T)>evT9R)e8AuExq`f zK-Uf@?90v#zh2^HecE&K`|x{Mr1YW?HH2$)T-LGBN3*(ee(wb zCAw&~hp6B}+uxn;oj1zjU;N;{kaZSdGR8`?IoVIqKl^2v@1%9C>SDXDSm#PUml zWR$%45c1JjM4~L+fppg{x;tbKqYrxZDGHPlS?t!5p;SP`?sEI7dm|9I=5)0xW%K_R zR?jK_h1FXM$t^D0TEeZ?5u8Rp!URjpPHJrXh0t#*-2tK*;Gt#4zfZ#eFr^W3x7ZR} z#%))@#Dv|k;$&`zP}}N{l2^>mbHJa-oJPO({J~y2dt(0SpXfC}MKL?*%*QB}=@~b9 zvJbzBo6(t*7g^zyjz0OOenEtw@0Y%*O;>jJG}(=lDX)yjSE}sS{nmt?mnMxCQf6K= zryK=B`aTCZ&%UCDt5Rcr_mOAC@tE-3KaC9m-dW96Eas+8b{9t+AZLs-B z*|H~D-f@5pDEdUx0iFr5<;>m$G5I4(gBfG=;J!|Q;&Fdn*+YI`t zc<={Bg#er6n)%f|g{NdtLoa#taZBj(K9U&)>~ z5ELcmfh^g57C~rh5`1Um{2@#D&M3re?>;tiLGz#& zgYfovb00Q95j?jDexZH7m)(oN|ENE0?_&i`3y1Xa@o|GIJ%liojwVdrrK9hWM1OJ# z`Co(?8uX{z0>(9l{qSv02_u~-R5HLo~?s`nm?*%o~H& z12@3QCUi;H*WT`PNCQexDtWi|Ci3;XrQeDD@r`zUoggq`@_yFo~p2?mEfr(Fua82RkG z*OkbJa18}mo?RnUZjJGzNl*J*H~5?M?f=~0)}=py)UO%baDW~}TcKr*#>5FNpj4NZ zMs-Ct3pi{)J7PS`9K&+`G2D}iO}EBhK6QnTM9L(wFOhJwvTcL9IEi$WL6cfN{bUdl zR2)|$ocQm{a0pzv&lfE|%Z0OGfe~bxgW4Su< zAS!u1p|)_ezNa;VFcV^b3~5Zzf*AU#HA%&-wf7m+8Hht(dHRa&Vg`v5X8SY84tjpq zJfDVmo{^5PF9|1+@I#(EQKNcZTqDKW6vN<3k?o0!{ayI^(B4+ra7BNI1AkplCND#O zS8)oq=Z$nPEwx(SeA_=Bg4eFz{mqxoi>kB`Y-)bCF8Ko{9!TrM(fJ8(z+fykNp zN8{7~wjqZ|VvvFW5k1$4Kw%(w{Q4%TKhxYhm>aWh@_YQjZnqw{^|K7|`hmXn*c%ys zdu>}`PvPAi+Zb400+LBhSg0MJN1Vq>KB$$yve>2dL+Zr@u-`I412

9ABfnz((yj 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

Woy_op*I*wFj*v@Asoun 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

QikFSD~z|MH+|RWz%ht**6h#|B(X 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

iFVAgih!tfIrrIrPR;+K=$CQ;Xki$ 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%0AtNuK!FOqS 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�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

VsUQ@ewHk@F7% z@W>^Ecm`O@{Y}8zNua1`Wm%fooE{K6+aw^3xEY@odB{0f2zH4qKr@2FU_lJTv;KdQ zQde-1KMd_Sz6rb2`SX|QPqrpNjnzNgr*~_s?(9@1OrY}vq9dw>q;mGy-r^XTLLb@b z{Q=UVzs8v?Au~5{UBWFBfv$Lu7n8Q02WJ>}FAQ4?nJFoVhv#zwzGjjaqO{z_MJGOQc-OYi zJvC*{&f05)WFCa7x>Ox`(L?4cnwkvgkBd@L0ttQUvj4VHlGQ-^N-edIK(q@?#(SDm zP*UB*LfpDANueH*?Bc@kY~y_nBu%s7tjnhG`^rY|vby^n>|n4xJcwk_X=41v_%&Lc z9eMGL&&r;wGHBto3G)xvL|4_wlj-0lrQwrtqw$Ccryq^_B8mdHA`Lf|^K#?NCzp!>)FZExf44)`A$4c)m3I+SLVcSf%YDqa{^1dOL^Vp%hg zEby-Xvuo2Vx3OMEQGq@UA>@l%>v(yEkH^4Zqg@tZJ9Cd~Yb1-}HS}=q3!4heORMTm z$K^X@+|f)@fg-_HJR}Msuebqf7Q7ts8_fF!7C!m_&Y}z%DK?5v0`K!N7kY-5+|Lep z29+XM1v^6q?!W>z1!PhNH#y*qTWgt5CPfXeOrun&WY;AuiaS32-xSllXEo{!Gj|xFG`3Z!a#>lM^4yjR02(g=V&`(1{F)fP!OyY!0TXAnUlc$UQc2a6xtUj1kpAQ zh=Ji*xkdo)vm{E`*5b0l*Poi|6?&*3knw+=$HZTH7rX(yCtUF+7B#mQi1yEuy|`fo zn#(8ZNa7qt0x^39kM;(-kH`uw+i8f9_w6?%Bd7G;4xNqsXJ04)h9Vk6--HImdI>N} z-c!-V%z)K2P?6KUTh0N49Ea7#ymS1VUNI~ovoUPkYub=1EcUtkFKG+N#N5X4Y6iLt0U?MOR`NXk|e@V#loj1E0<^ zh=;3rdF*nW6U+58kPMyi1oR<%YQo^)9S zEttlNuJhuY90UHf;#U7pUG-eTWd}jFpvQJ^j$D#ieN1U9AdJf_xsJZo$>#N zN9Pg07J`K;;q0dadJk|_Y2cy=re2Iaw_{Kl=-k!E$&hrM+WPihW;&A$$_4WiPv{{e z`AB^+o#*d>U%7`aIeh~22Gr+1Fp&&zOmjf%5%2|V|LgGCAmr8tLpX6Seu}l)3}Gzb zz~Z|KC(AV{%odid;x0TpcAs>UC#?V&iBPX>+jGlY3rC?zWrR&v{XY1h7W;%WaRXP zd?4OiF@-$gTb7d*>~)8&7MokijOU+j>pNr2WF3rUzcm$;-v6Gs)Bl}oCGHwbDkX|1 z>M^2TULjxxriZo0{UomHC8}rf;=Y&hLVT}o)6JhmHa6$0QFo7IbNdj5AsD$kqP7F~ z2#oya!>W~@ztSnX-*g~gId9Ug3Rqba<>XPthYcT&axm@VpG&TH<28P8KzK}4)Z9

&r{we*LlN)Wnm@@WDLsj0kl9r;!be)$CEc~_ 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 Date: Fri, 19 Aug 2016 12:27:35 +0200 Subject: [PATCH 0292/1332] Add target_host file with original host to cache since cache dir is hash. --- cdist/exec/local.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index c6e25be3..50f0ab65 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -254,6 +254,10 @@ class Local(object): "Cannot delete old cache %s: %s" % (destination, e)) shutil.move(self.base_path, destination) + # add target_host since cache dir is hash-ed target_host + host_cache_path = os.path.join(destination, "target_host") + with open(host_cache_path, 'w') as hostf: + print(self.target_host[0], file=hostf) def _create_messages(self): """Create empty messages""" From 7aa4b2d40ab176ceee1800fd6fe115fca6d5c93e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 19 Aug 2016 13:37:57 +0200 Subject: [PATCH 0293/1332] Support comments in hostfile, skip empty lines. --- cdist/config.py | 11 +++++++++-- docs/changelog | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 31b41781..8d83a072 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -99,8 +99,15 @@ class Config(object): import fileinput try: for host in fileinput.input(files=(source)): - # remove leading and trailing whitespace - yield host.strip() + # remove comment if present + comment_index = host.find('#') + if comment_index >= 0: + host = host[:comment_index] + # remove leading and trailing whitespaces + host = host.strip() + # skip empty lines + if host: + yield host except (IOError, OSError) as e: raise cdist.Error("Error reading hosts from \'{}\'".format( source)) diff --git a/docs/changelog b/docs/changelog index db86de45..12510041 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,7 @@ Changelog --------- next: + * Core: Improve hostfile: support comments, skip empty lines (Darko Poljak) * Documentation: Add Parallelization chapter (Darko Poljak) * Core: Add -b, --enable-beta option for enabling beta functionalities (Darko Poljak) * Core: Add -j, --jobs option for parallel execution and add parallel support for global explorers (currently in beta) (Darko Poljak) From 72505e0f5f75878ae5127dc18ac14e292c877a9a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 19 Aug 2016 14:33:41 +0200 Subject: [PATCH 0294/1332] Add hostfile format to cdist man page. --- docs/src/man1/cdist.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 47fe195c..eeba97f0 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -82,7 +82,7 @@ Configure one or more hosts. Read additional hosts to operate on from specified file or from stdin if '-' (each host on separate line). If no host or host file is specified then, by default, - read hosts from stdin. + read hosts from stdin. For the file format see below. .. option:: -i MANIFEST, --initial-manifest MANIFEST @@ -117,6 +117,15 @@ Configure one or more hosts. Command to use for remote execution (should behave like ssh) + +HOSTFILE FORMAT +~~~~~~~~~~~~~~~ +HOSTFILE contains hosts per line. +All characters after and including '#' until the end of line is a comment +and is stripped away. +Empty lines and comment lines (line that starts with '#') are skipped. + + SHELL ----- This command allows you to spawn a shell that enables access From 147460e3d0404f5c760bf823c9084ca8445a6b24 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 19 Aug 2016 21:18:39 +0200 Subject: [PATCH 0295/1332] Update changelog for new release: 4.3.0 --- docs/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index db86de45..b817555b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,7 @@ Changelog --------- -next: + +4.3.0: 2016-08-19 * Documentation: Add Parallelization chapter (Darko Poljak) * Core: Add -b, --enable-beta option for enabling beta functionalities (Darko Poljak) * Core: Add -j, --jobs option for parallel execution and add parallel support for global explorers (currently in beta) (Darko Poljak) From 7f1e41f76904ee1d53646396e9f8e4253ca0b9be Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 19 Aug 2016 21:56:24 +0200 Subject: [PATCH 0296/1332] Move hostfile line processing to new method. --- cdist/config.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 8d83a072..2f28a22f 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -89,6 +89,25 @@ class Config(object): self.local.create_files_dirs() self.remote.create_files_dirs() + @staticmethod + def hostfile_process_line(line): + """Return host from read line or None if no host present.""" + if not line: + return None + # remove comment if present + comment_index = line.find('#') + if comment_index >= 0: + host = line[:comment_index] + else: + host = line + # remove leading and trailing whitespaces + host = host.strip() + # skip empty lines + if host: + return host + else: + return None + @staticmethod def hosts(source): """Yield hosts from source. @@ -99,13 +118,7 @@ class Config(object): import fileinput try: for host in fileinput.input(files=(source)): - # remove comment if present - comment_index = host.find('#') - if comment_index >= 0: - host = host[:comment_index] - # remove leading and trailing whitespaces - host = host.strip() - # skip empty lines + host = Config.hostfile_process_line(host) if host: yield host except (IOError, OSError) as e: From d9d739cd44ec005b3cf02bda54c44faf727f59d4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 20 Aug 2016 07:49:52 +0200 Subject: [PATCH 0297/1332] Update HOSTFILE FORMAT description. --- docs/src/man1/cdist.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index eeba97f0..baeb0025 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -120,10 +120,15 @@ Configure one or more hosts. HOSTFILE FORMAT ~~~~~~~~~~~~~~~ -HOSTFILE contains hosts per line. -All characters after and including '#' until the end of line is a comment -and is stripped away. -Empty lines and comment lines (line that starts with '#') are skipped. +HOSTFILE contains hosts per line. +All characters after and including '#' until the end of line is a comment. +In a line, all leading and trailing whitespace characters are ignored. +Empty lines are ignored/skipped. + +Hostfile line is processed like the following. First, all comments are +removed. Then all leading and trailing whitespace characters are stripped. +If such a line results in empty line it is ignored/skipped. Otherwise, +host string is used. SHELL From b83e6993c1a4067c662fcaeb918de4acf6651e1d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 21 Aug 2016 17:10:24 +0200 Subject: [PATCH 0298/1332] Make comment better. --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 50f0ab65..93301063 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -254,7 +254,7 @@ class Local(object): "Cannot delete old cache %s: %s" % (destination, e)) shutil.move(self.base_path, destination) - # add target_host since cache dir is hash-ed target_host + # add target_host since cache dir can be hash-ed target_host host_cache_path = os.path.join(destination, "target_host") with open(host_cache_path, 'w') as hostf: print(self.target_host[0], file=hostf) From b5262c850ed6f918a1ed9154ff9a4ce915b30999 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 21 Aug 2016 21:48:21 +0200 Subject: [PATCH 0299/1332] Exit cleanly in case of non UTF-8 file. --- cdist/config.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 2f28a22f..e20f1a7c 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -121,9 +121,10 @@ class Config(object): host = Config.hostfile_process_line(host) if host: yield host - except (IOError, OSError) as e: - raise cdist.Error("Error reading hosts from \'{}\'".format( - source)) + except (IOError, OSError, UnicodeError) as e: + raise cdist.Error( + "Error reading hosts from file \'{}\': {}".format( + source, e)) else: if source: for host in source: From 4121d14eabf4e4b3f8da65463e63884378da3386 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Aug 2016 08:00:23 +0200 Subject: [PATCH 0300/1332] Update changelog for target_host in cache dir. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 518be192..61441d98 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Core: Add target_host file to cache since cache dir name can be hash (Darko Poljak) * Core: Improve hostfile: support comments, skip empty lines (Darko Poljak) 4.3.0: 2016-08-19 From b5a79fbc8f0c410608a4915429cb27f1b006270d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Aug 2016 08:11:49 +0200 Subject: [PATCH 0301/1332] Fix spelling (Dmitry Bogatov patch). --- cdist/conf/type/__filesystem/man.rst | 14 +++++++------- docs/changelog | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__filesystem/man.rst b/cdist/conf/type/__filesystem/man.rst index d88e27c1..73f576d5 100644 --- a/cdist/conf/type/__filesystem/man.rst +++ b/cdist/conf/type/__filesystem/man.rst @@ -13,7 +13,7 @@ This cdist type allows you to create filesystems on devices. If the device is mounted on target, it refuses to do anything. If the device has a filesystem other then the specified and/or -the label is not correct, it only makes a new filesystem +the label is not correct, it only makes a new filesystem if you have specified --force option. @@ -30,9 +30,9 @@ device Blockdevice for filesystem, Defaults to object_id. On linux, it can be any lsblk accepted device notation. - | + | | For example: - | /dev/sdx + | /dev/sdx | or /dev/disk/by-xxxx/xxx | or /dev/mapper/xxxx @@ -46,15 +46,15 @@ mkfsoptions BOOLEAN PARAMETERS ------------------ force - Normaly, this type does nothing if a filesystem is found - on the target device. If you specify force, it's formated + Normally, this type does nothing if a filesystem is found + on the target device. If you specify force, it's formatted if the filesystem type or label differs from parameters. Warning: This option can easily lead into data loss! MESSAGES -------- filesystem on \: created - Filesytem was created on + Filesystem was created on EXAMPLES @@ -62,7 +62,7 @@ EXAMPLES .. code-block:: sh - # Ensures that device /dev/sdb is formated with xfs + # Ensures that device /dev/sdb is formatted with xfs __filesystem /dev/sdb --fstype xfs --label Testdisk1 # The same thing with btrfs and disk spezified by pci path to disk 1:0 on vmware __filesystem dev_sdb --fstype btrfs --device /dev/disk/by-path/pci-0000:0b:00.0-scsi-0:0:0:0 --label Testdisk2 diff --git a/docs/changelog b/docs/changelog index 61441d98..ec1c9f98 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Type __filesystem: Spelling fixes (Dmitry Bogatov) * Core: Add target_host file to cache since cache dir name can be hash (Darko Poljak) * Core: Improve hostfile: support comments, skip empty lines (Darko Poljak) From 3df61be7b8b85f981b17855e2fcc58daf1e95623 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Aug 2016 08:12:14 +0200 Subject: [PATCH 0302/1332] Update cdist support web page. --- docs/web/cdist/support.mdwn | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/web/cdist/support.mdwn b/docs/web/cdist/support.mdwn index 39388c5a..4c89ee79 100644 --- a/docs/web/cdist/support.mdwn +++ b/docs/web/cdist/support.mdwn @@ -8,7 +8,7 @@ You can join the development ***IRC channel*** ### Mailing list Bug reports, questions, patches, etc. should be send to the -[cdist mailing list](http://l.schottelius.org/mailman/listinfo/cdist). +[cdist mailing list](https://groups.google.com/forum/#!forum/cdist-configuration-management). ### Linkedin @@ -17,6 +17,9 @@ at [Linked in](http://www.linkedin.com/), you can join the [cdist group](http://www.linkedin.com/groups/cdist-configuration-management-3952797). +### Chat +Chat with us: [ungleich chat] (https://chat.ungleich.ch/channel/cdist). + ### Commercial support You can request commercial support for cdist from From 2d72c08e9b896822d5050912d4f5c733e0fdd540 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Aug 2016 09:24:48 +0200 Subject: [PATCH 0303/1332] Fix spelling. --- cdist/conf/type/__consul_check/man.rst | 2 +- cdist/conf/type/__filesystem/man.rst | 2 +- docs/changelog | 1 + docs/src/cdist-best-practice.rst | 2 +- docs/src/cdist-features.rst | 2 +- docs/src/cdist-hacker.rst | 2 +- docs/src/cdist-manifest.rst | 4 ++-- docs/src/cdist-type.rst | 2 +- docs/src/cdist-update.rst | 6 +++--- docs/src/man1/cdist.rst | 2 +- docs/web/cdist/features.mdwn | 2 +- docs/web/cdist/update.mdwn | 6 +++--- docs/web/cdist/update/2.0-to-2.1.mdwn | 4 ++-- 13 files changed, 19 insertions(+), 18 deletions(-) diff --git a/cdist/conf/type/__consul_check/man.rst b/cdist/conf/type/__consul_check/man.rst index dc7895de..9694c7af 100644 --- a/cdist/conf/type/__consul_check/man.rst +++ b/cdist/conf/type/__consul_check/man.rst @@ -11,7 +11,7 @@ DESCRIPTION Generate and deploy check definitions for a consul agent. See http://www.consul.io/docs/agent/checks.html for parameter documentation. -Use either script toghether with interval, or use ttl. +Use either script together with interval, or use ttl. REQUIRED PARAMETERS diff --git a/cdist/conf/type/__filesystem/man.rst b/cdist/conf/type/__filesystem/man.rst index 73f576d5..1c103ac9 100644 --- a/cdist/conf/type/__filesystem/man.rst +++ b/cdist/conf/type/__filesystem/man.rst @@ -37,7 +37,7 @@ device | or /dev/mapper/xxxx label - Label which sould apply on the filesystem. + Label which should be applied on the filesystem. mkfsoptions Additional options which are inserted to the mkfs.xxx call. diff --git a/docs/changelog b/docs/changelog index ec1c9f98..9d7bc427 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Documentation: Spelling fixes (Darko Poljak) * Type __filesystem: Spelling fixes (Dmitry Bogatov) * Core: Add target_host file to cache since cache dir name can be hash (Darko Poljak) * Core: Improve hostfile: support comments, skip empty lines (Darko Poljak) diff --git a/docs/src/cdist-best-practice.rst b/docs/src/cdist-best-practice.rst index 57ce5cc1..493f1506 100644 --- a/docs/src/cdist-best-practice.rst +++ b/docs/src/cdist-best-practice.rst @@ -58,7 +58,7 @@ you can clone it multiple times:: machine-b % git clone git://your-git-server/cdist -Seperating work by groups +Separating work by groups ------------------------- If you are working with different groups on one cdist-configuration, you can delegate to other manifests and have the groups edit only diff --git a/docs/src/cdist-features.rst b/docs/src/cdist-features.rst index 8a147741..7018d248 100644 --- a/docs/src/cdist-features.rst +++ b/docs/src/cdist-features.rst @@ -7,7 +7,7 @@ Simplicity There is only one type to extend cdist called **type** Design - + Type and core cleanly seperated + + Type and core cleanly separated + Sticks completly to the KISS (keep it simple and stupid) paradigma + Meaningful error messages - do not lose time debugging error messages + Consistency in behaviour, naming and documentation diff --git a/docs/src/cdist-hacker.rst b/docs/src/cdist-hacker.rst index 326d83ba..efc5da4b 100644 --- a/docs/src/cdist-hacker.rst +++ b/docs/src/cdist-hacker.rst @@ -56,7 +56,7 @@ or open a pull request at http://github.com/telmich/cdist. How to submit a new type ------------------------ -For detailled information about types, see `cdist type `_. +For detailed information about types, see `cdist type `_. Submitting a type works as described above, with the additional requirement that a corresponding manpage named man.text in asciidoc format with diff --git a/docs/src/cdist-manifest.rst b/docs/src/cdist-manifest.rst index 5655c6c2..b29cf0d8 100644 --- a/docs/src/cdist-manifest.rst +++ b/docs/src/cdist-manifest.rst @@ -118,7 +118,7 @@ On line 4 you can see that the instantion of a type "\__link" object needs the object "__file/etc/cdist-configured" to be present, before it can proceed. This also means that the "\__link" command must make sure, that either -"\__file/etc/cdist-configured" allready is present, or, if it's not, it needs +"\__file/etc/cdist-configured" already is present, or, if it's not, it needs to be created. The task of cdist is to make sure, that the dependency will be resolved appropriately and thus "\__file/etc/cdist-configured" be created if necessary before "__link" proceeds (or to abort execution with an error). @@ -216,7 +216,7 @@ How to override objects: .. code-block:: sh - # for example in the inital manifest + # for example in the initial manifest # create user account foobar with some hash for password __user foobar --password 'some_fancy_hash' --home /home/foobarexample diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index c75d0a52..62694fd8 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -126,7 +126,7 @@ Example: (e.g. in cdist/conf/type/__nginx_vhost/manifest) # parameter with multiple values if [ -f "$__object/parameter/server_alias" ]; then for alias in $(cat "$__object/parameter/server_alias"); do - echo $alias > /some/where/usefull + echo $alias > /some/where/useful done fi diff --git a/docs/src/cdist-update.rst b/docs/src/cdist-update.rst index 0b445ba4..e810d6e9 100644 --- a/docs/src/cdist-update.rst +++ b/docs/src/cdist-update.rst @@ -85,7 +85,7 @@ Use `messaging `_ instead. Updating from 2.2 to 2.3 ~~~~~~~~~~~~~~~~~~~~~~~~ -No incompatiblities. +No incompatibilities. Updating from 2.1 to 2.2 ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -164,7 +164,7 @@ Updating from 1.5 to 1.6 Updating from 1.3 to 1.5 ~~~~~~~~~~~~~~~~~~~~~~~~ -No incompatiblities. +No incompatibilities. Updating from 1.2 to 1.3 ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -174,7 +174,7 @@ Rename **gencode** of every type to **gencode-remote**. Updating from 1.1 to 1.2 ~~~~~~~~~~~~~~~~~~~~~~~~ -No incompatiblities. +No incompatibilities. Updating from 1.0 to 1.1 ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index baeb0025..52562e14 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -207,7 +207,7 @@ CDIST_LOCAL_SHELL Selects shell for local script execution, defaults to /bin/sh. CDIST_REMOTE_SHELL - Selects shell for remote scirpt execution, defaults to /bin/sh. + Selects shell for remote script execution, defaults to /bin/sh. CDIST_OVERRIDE Allow overwriting type parameters. diff --git a/docs/web/cdist/features.mdwn b/docs/web/cdist/features.mdwn index a97f2013..77c61382 100644 --- a/docs/web/cdist/features.mdwn +++ b/docs/web/cdist/features.mdwn @@ -3,7 +3,7 @@ But cdist ticks differently, here is the feature set that makes it unique: [[!table data=""" Keywords | Description Simplicity | There is only one type to extend cdist called ***type*** -Design | Type and core cleanly seperated +Design | Type and core cleanly separated Design | Sticks completly to the KISS (keep it simple and stupid) paradigma Design | Meaningful error messages - do not lose time debugging error messages Design | Consistency in behaviour, naming and documentation diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 28f41da7..df4617bb 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -67,7 +67,7 @@ Use [messaging](/software/cdist/man/3.0.0/man7/cdist-messaging.html) instead. ### Updating from 2.2 to 2.3 -No incompatiblities. +No incompatibilities. ### Updating from 2.1 to 2.2 @@ -134,7 +134,7 @@ Have a look at the update guide for [[2.0 to 2.1|2.0-to-2.1]]. ### Updating from 1.3 to 1.5 -No incompatiblities. +No incompatibilities. ### Updating from 1.2 to 1.3 @@ -142,7 +142,7 @@ Rename **gencode** of every type to **gencode-remote**. ### Updating from 1.1 to 1.2 -No incompatiblities. +No incompatibilities. ### Updating from 1.0 to 1.1 diff --git a/docs/web/cdist/update/2.0-to-2.1.mdwn b/docs/web/cdist/update/2.0-to-2.1.mdwn index 1d0037ab..3b5f5dc4 100644 --- a/docs/web/cdist/update/2.0-to-2.1.mdwn +++ b/docs/web/cdist/update/2.0-to-2.1.mdwn @@ -10,7 +10,7 @@ explorers and manifest to custom directories. This document will guide you to a successful update. -## Preperation +## Preparation As for every software and system you use in production, you should first of all make a backup of your data. To prevent any breakage, it is @@ -35,7 +35,7 @@ Now try to merge upstream into the new branch. % git merge origin/2.1 Fix any conflicts that may have been occurred due to local changes -and then **git add** and *git commit** those changes. This should seldomly +and then **git add** and *git commit** those changes. This should seldom occur and if, it's mostly for people hacking on the cdist core. ## Move "conf" directory From 49506406fd6ff3ead0c69bebaf038a68b0f48153 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Aug 2016 09:27:12 +0200 Subject: [PATCH 0304/1332] Fix spelling. --- docs/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 9d7bc427..1ab5e321 100644 --- a/docs/changelog +++ b/docs/changelog @@ -82,7 +82,7 @@ next: * Type __consul_agent: Use systemd for Debian 8 (Nico Schottelius) * Type __firewalld_rule: Ensure firewalld package is present (David Hürlimann) * Type __locale: Support CentOS (David Hürlimann) - * Type __staged_file: Fix comparision operator (Nico Schottelius) + * Type __staged_file: Fix comparison operator (Nico Schottelius) * Type __user_groups: Support old Linux versions (Daniel Heule) 3.1.12: 2015-03-19 @@ -269,7 +269,7 @@ next: 3.0.1: 2014-01-14 * Core: Copy only files, not directories (Steven Armstrong) * Core: Allow hostnames to start with / (Nico Schottelius) - * Type __line: Remove unecessary backslash escape (Nico Schottelius) + * Type __line: Remove unnecessary backslash escape (Nico Schottelius) * Type __directory: Add messaging support (Daniel Heule) * Type __directory: Do not generate code if mode is 0xxx (Daniel Heule) * Type __package: Fix typo in optional parameter ptype (Daniel Heule) From 94d37913d125ea3fba01f2eef69db61fa0e51766 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Aug 2016 10:36:40 +0200 Subject: [PATCH 0305/1332] Fix Makefile tabulation. --- docs/src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/Makefile b/docs/src/Makefile index 800a80d8..2ecf7a32 100644 --- a/docs/src/Makefile +++ b/docs/src/Makefile @@ -11,7 +11,7 @@ _BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) - $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) + $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. From e7e7cfdce26c0c5badbe25237e90c65221fc1e62 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Aug 2016 18:49:14 +0200 Subject: [PATCH 0306/1332] Update changelog for release 4.3.1. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 1ab5e321..ba0ce9c5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.3.1: 2016-08-22 * Documentation: Spelling fixes (Darko Poljak) * Type __filesystem: Spelling fixes (Dmitry Bogatov) * Core: Add target_host file to cache since cache dir name can be hash (Darko Poljak) From bc0efa9c4e3c22a7a9e788a2a1a7ef3a4980334f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Aug 2016 19:07:13 +0200 Subject: [PATCH 0307/1332] Remove extra whitespace. --- docs/web/cdist/support.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web/cdist/support.mdwn b/docs/web/cdist/support.mdwn index 4c89ee79..4f92853b 100644 --- a/docs/web/cdist/support.mdwn +++ b/docs/web/cdist/support.mdwn @@ -18,7 +18,7 @@ you can join the [cdist group](http://www.linkedin.com/groups/cdist-configuration-management-3952797). ### Chat -Chat with us: [ungleich chat] (https://chat.ungleich.ch/channel/cdist). +Chat with us: [ungleich chat](https://chat.ungleich.ch/channel/cdist). ### Commercial support From cd8373fe506cec09944a95d515538f0111a2b349 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Tue, 23 Aug 2016 15:55:07 +0200 Subject: [PATCH 0308/1332] Hotfix: Changed source of consul 0.5.1 --- cdist/conf/type/__consul/files/versions/0.5.1/source | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul/files/versions/0.5.1/source b/cdist/conf/type/__consul/files/versions/0.5.1/source index f02a1103..a47eb69c 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.1/source +++ b/cdist/conf/type/__consul/files/versions/0.5.1/source @@ -1 +1 @@ -https://dl.bintray.com/mitchellh/consul/0.5.1_linux_amd64.zip +https://releases.hashicorp.com/consul/0.5.1/consul_0.5.1_linux_amd64.zip From 428c06c8d39ab7777cc1bece34dd0ae23f924d2a Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Tue, 23 Aug 2016 16:40:13 +0200 Subject: [PATCH 0309/1332] Hotfix: Changed sources of all consul version + cksum files --- cdist/conf/type/__consul/files/versions/0.4.1/cksum | 2 +- cdist/conf/type/__consul/files/versions/0.4.1/source | 2 +- cdist/conf/type/__consul/files/versions/0.5.0/cksum | 2 +- cdist/conf/type/__consul/files/versions/0.5.0/source | 2 +- cdist/conf/type/__consul/files/versions/0.5.1/cksum | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__consul/files/versions/0.4.1/cksum b/cdist/conf/type/__consul/files/versions/0.4.1/cksum index edba1a68..3e114ece 100644 --- a/cdist/conf/type/__consul/files/versions/0.4.1/cksum +++ b/cdist/conf/type/__consul/files/versions/0.4.1/cksum @@ -1 +1 @@ -428915666 15738724 consul +2024850362 4073679 consul diff --git a/cdist/conf/type/__consul/files/versions/0.4.1/source b/cdist/conf/type/__consul/files/versions/0.4.1/source index b1e9908d..7fb949c8 100644 --- a/cdist/conf/type/__consul/files/versions/0.4.1/source +++ b/cdist/conf/type/__consul/files/versions/0.4.1/source @@ -1 +1 @@ -https://dl.bintray.com/mitchellh/consul/0.4.1_linux_amd64.zip +https://releases.hashicorp.com/consul/0.4.1/consul_0.4.1_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.5.0/cksum b/cdist/conf/type/__consul/files/versions/0.5.0/cksum index fe9888ae..66bb482a 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.0/cksum +++ b/cdist/conf/type/__consul/files/versions/0.5.0/cksum @@ -1 +1 @@ -131560372 17734417 consul +915590436 4669655 consul diff --git a/cdist/conf/type/__consul/files/versions/0.5.0/source b/cdist/conf/type/__consul/files/versions/0.5.0/source index 00a209a5..dc1c33c4 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.0/source +++ b/cdist/conf/type/__consul/files/versions/0.5.0/source @@ -1 +1 @@ -https://dl.bintray.com/mitchellh/consul/0.5.0_linux_amd64.zip +https://releases.hashicorp.com/consul/0.5.0/consul_0.5.0_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/0.5.1/cksum b/cdist/conf/type/__consul/files/versions/0.5.1/cksum index a176ed43..c1c59011 100644 --- a/cdist/conf/type/__consul/files/versions/0.5.1/cksum +++ b/cdist/conf/type/__consul/files/versions/0.5.1/cksum @@ -1 +1 @@ -2564582176 18232733 consul +190723740 4802625 consul From 232a9098518151c98356dc7a6d4d28b0c4cbc827 Mon Sep 17 00:00:00 2001 From: smwalter Date: Wed, 24 Aug 2016 17:34:18 +0900 Subject: [PATCH 0310/1332] change documentation from git://git.schottelius.org/cdist to git://github.com/ungleich/cdist because git.schottelius.org does not exist. --- cdist/conf/type/__cdist/man.rst | 2 +- docs/src/cdist-quickstart.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__cdist/man.rst b/cdist/conf/type/__cdist/man.rst index f02f848a..72b11e78 100644 --- a/cdist/conf/type/__cdist/man.rst +++ b/cdist/conf/type/__cdist/man.rst @@ -47,7 +47,7 @@ EXAMPLES __cdist /home/cdist/cdist # Use alternative source - __cdist --source "git://git.schottelius.org/cdist" /home/cdist/cdist + __cdist --source "git://github.com/telmich/cdist" /home/cdist/cdist AUTHORS diff --git a/docs/src/cdist-quickstart.rst b/docs/src/cdist-quickstart.rst index 7c967691..0020568d 100644 --- a/docs/src/cdist-quickstart.rst +++ b/docs/src/cdist-quickstart.rst @@ -56,7 +56,7 @@ code into your shell to get started and configure localhost:: # Get cdist # Mirrors can be found on # http://www.nico.schottelius.org/software/cdist/install/#index2h4 - git clone git://git.schottelius.org/cdist + git clone git://github.com/ungleich/cdist # Create manifest (maps configuration to host(s) cd cdist From 72001b237e060d47ec63d95060d9a4a1ec128337 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 24 Aug 2016 13:46:47 +0200 Subject: [PATCH 0311/1332] Remove relict comment. --- cdist/emulator.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 2c5e567b..b04ed130 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -166,8 +166,6 @@ class Emulator(object): self.parameters[key] = value if self.cdist_object.exists and 'CDIST_OVERRIDE' not in self.env: - # make existing requirements a set, so we can compare it - # later with new requirements if self.cdist_object.parameters != self.parameters: errmsg = ("Object %s already exists with conflicting " "parameters:\n%s: %s\n%s: %s" % ( From 3b91443f813a154e3dc0e7afa523b1e6970607aa Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Fri, 2 Sep 2016 11:39:22 -0400 Subject: [PATCH 0312/1332] __hostname: openbsd support --- cdist/conf/type/__hostname/gencode-remote | 4 ++-- cdist/conf/type/__hostname/manifest | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index c1808de0..4eb08723 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -40,7 +40,7 @@ case "$os" in exit 0 fi ;; - scientific|centos) + scientific|centos|openbsd) if [ "$name_sysconfig" = "$name_should" -a "$name_running" = "$name_should" ]; then exit 0 fi @@ -64,7 +64,7 @@ else echo "hostname '$name_should'" echo "printf '%s\n' '$name_should' > /etc/hostname" ;; - centos) + centos|openbsd) echo "hostname '$name_should'" ;; suse) diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 842075e0..823d2f7e 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -23,7 +23,14 @@ os=$(cat "$__global/explorer/os") if [ -f "$__object/parameter/name" ]; then name_should="$(cat "$__object/parameter/name")" else - name_should="$(echo "${__target_host%%.*}")" + case "$os" in + openbsd) + name_should="$(echo "${__target_host}")" + ;; + *) + name_should="$(echo "${__target_host%%.*}")" + ;; + esac fi @@ -45,6 +52,9 @@ case "$os" in --key HOSTNAME \ --value "$name_should" --exact_delimiter ;; + openbsd) + echo "$name_should" | __file /etc/myname --source - + ;; *) not_supported ;; From 1a4bec21bff07413a070503c1a215d4d91acb8b6 Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Fri, 2 Sep 2016 11:21:05 -0400 Subject: [PATCH 0313/1332] __package: call __package_pkg_openbsd on openbsd --- cdist/conf/type/__package/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__package/manifest b/cdist/conf/type/__package/manifest index c745f85f..525691bb 100755 --- a/cdist/conf/type/__package/manifest +++ b/cdist/conf/type/__package/manifest @@ -43,6 +43,7 @@ else gentoo) type="emerge" ;; suse) type="zypper" ;; openwrt) type="opkg" ;; + openbsd) type="pkg_openbsd" ;; *) echo "Don't know how to manage packages on: $os" >&2 exit 1 From db32d0de3a62044ce23c036cca0d79ffe34a90a5 Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Fri, 2 Sep 2016 11:13:37 -0400 Subject: [PATCH 0314/1332] __package_pkg_openbsd: support --version --- .../type/__package_pkg_openbsd/gencode-remote | 22 +++++++++++++++---- cdist/conf/type/__package_pkg_openbsd/man.rst | 3 +++ .../__package_pkg_openbsd/parameter/optional | 1 + 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index dea7f711..5ba5f7ef 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -29,6 +29,10 @@ os_version="$(cat "$__global/explorer/os_version")" machine="$(cat "$__global/explorer/machine")" +if [ -f "$__object/parameter/version" ]; then + version="$(cat "$__object/parameter/version")" +fi + if [ -f "$__object/parameter/flavor" ]; then flavor="$(cat "$__object/parameter/flavor")" fi @@ -42,6 +46,16 @@ else name="$__object_id" fi +if [ -n "$version" -a -n "$flavor" ]; then + pkgid="$name-$version-$flavor" +elif [ -n "$version" ]; then + pkgid="$name-$version" +elif [ -n "$flavor" ]; then + pkgid="$name--$flavor" +else + pkgid="$name" +fi + state_should="$(cat "$__object/parameter/state")" pkg_version="$(cat "$__object/explorer/pkg_version")" @@ -65,8 +79,8 @@ case "$state_should" in # use this because pkg_add doesn't properly handle errors cat << eof export PKG_PATH="$pkg_path" -status=\$(pkg_add "$pkgopts" "$name--$flavor" 2>&1) -pkg_info | grep "^${name}.*${flavor}" > /dev/null 2>&1 +status=\$(pkg_add "$pkgopts" "$pkgid" 2>&1) +pkg_info | grep "^${name}.*${version}.*${flavor}" > /dev/null 2>&1 # We didn't find the package in the list of 'installed packages', so it failed # This is necessary because pkg_add doesn't return properly @@ -83,8 +97,8 @@ eof absent) # use this because pkg_add doesn't properly handle errors cat << eof -status=\$(pkg_delete "$pkgopts" "$name--$flavor") -pkg_info | grep "^${name}.*${flavor}" > /dev/null 2>&1 +status=\$(pkg_delete "$pkgopts" "$pkgid") +pkg_info | grep "^${name}.*${version}.*${flavor}" > /dev/null 2>&1 # We found the package in the list of 'installed packages' # This would indicate that pkg_delete failed, send the output of pkg_delete diff --git a/cdist/conf/type/__package_pkg_openbsd/man.rst b/cdist/conf/type/__package_pkg_openbsd/man.rst index 0814029f..dcfd0719 100644 --- a/cdist/conf/type/__package_pkg_openbsd/man.rst +++ b/cdist/conf/type/__package_pkg_openbsd/man.rst @@ -24,6 +24,9 @@ name flavor If supplied, use to avoid ambiguity. +version + If supplied, use to avoid ambiguity. + state Either "present" or "absent", defaults to "present" diff --git a/cdist/conf/type/__package_pkg_openbsd/parameter/optional b/cdist/conf/type/__package_pkg_openbsd/parameter/optional index 43278d16..6a5f9277 100644 --- a/cdist/conf/type/__package_pkg_openbsd/parameter/optional +++ b/cdist/conf/type/__package_pkg_openbsd/parameter/optional @@ -1,4 +1,5 @@ name +version flavor state pkg_path From 1875bce52e9da62a4f0eb7bd3922c32a26dd7f86 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Thu, 1 Sep 2016 17:47:51 +0300 Subject: [PATCH 0315/1332] Add support for guixsd into os explorer --- cdist/conf/explorer/os | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index 550192d4..094685ea 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -39,6 +39,11 @@ if [ -f /etc/cdist-preos ]; then exit 0 fi +if [ -d /gnu/store ]; then + echo guixsd + exit 0 +fi + ### Debian and derivatives if grep -q ^DISTRIB_ID=Ubuntu /etc/lsb-release 2>/dev/null; then echo ubuntu From 493c8d61f400653ce235cbd27d717e51656a0e9b Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Sun, 11 Sep 2016 22:23:06 -0400 Subject: [PATCH 0316/1332] __user_groups: refactor, support FreeBSD --- .../type/__user_groups/explorer/oldusermod | 7 ++-- cdist/conf/type/__user_groups/gencode-remote | 37 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/cdist/conf/type/__user_groups/explorer/oldusermod b/cdist/conf/type/__user_groups/explorer/oldusermod index bf43fcec..248d3922 100644 --- a/cdist/conf/type/__user_groups/explorer/oldusermod +++ b/cdist/conf/type/__user_groups/explorer/oldusermod @@ -22,7 +22,8 @@ os="$($__explorer/os)" if [ "$os" = "netbsd" ]; then echo netbsd - exit +elif [ "$os" = "freebsd" ]; then + echo freebsd +else + usermod --help | grep -q -- '-A group' && echo true || echo false fi - -usermod --help | grep -q -- '-A group' && echo true || echo false diff --git a/cdist/conf/type/__user_groups/gencode-remote b/cdist/conf/type/__user_groups/gencode-remote index 8b13f32c..6728228c 100755 --- a/cdist/conf/type/__user_groups/gencode-remote +++ b/cdist/conf/type/__user_groups/gencode-remote @@ -23,19 +23,6 @@ state_should="$(cat "$__object/parameter/state")" oldusermod="$(cat "$__object/explorer/oldusermod")" os=$(cat "$__global/explorer/os") -if [ "$os" = "netbsd" ]; then - # NetBSD does not have a command to remove a user from a group - oldusermod="true" - addparam="-G" - delparam=";;#" -elif [ "$oldusermod" = "true" ]; then - addparam="-A" - delparam="-R" -else - addparam="-a" - delparam="-d" -fi - mkdir "$__object/files" # file has to be sorted for comparison with `comm` sort "$__object/parameter/group" > "$__object/files/group.sorted" @@ -43,11 +30,9 @@ sort "$__object/parameter/group" > "$__object/files/group.sorted" case "$state_should" in present) changed_groups="$(comm -13 "$__object/explorer/group" "$__object/files/group.sorted")" - action="$addparam" ;; absent) changed_groups="$(comm -12 "$__object/explorer/group" "$__object/files/group.sorted")" - action="$delparam" ;; esac @@ -57,9 +42,25 @@ if [ -z "$changed_groups" ]; then fi for group in $changed_groups; do - if [ "$oldusermod" = "true" ]; then - echo "usermod $action \"$group\" \"$user\"" + if [ "$os" = "netbsd" ]; then + case "$state_should" in + present) echo "usermod -G \"$group\" \"$user\"" ;; + absent) echo 'NetBSD does not have a command to remove a user from a group' >&2 ; exit 1 ;; + esac + elif [ "$os" = "freebsd" ]; then + case "$state_should" in + present) echo "pw groupmod \"$group\" -m \"$user\"" ;; + absent) echo "pw groupmod \"$group\" -d \"$user\"" ;; + esac + elif [ "$oldusermod" = "true" ]; then + case "$state_should" in + present) echo "usermod -A \"$group\" \"$user\"" ;; + absent) echo "usermod -R \"$group\" \"$user\"" ;; + esac else - echo "gpasswd $action \"$user\" \"$group\"" + case "$state_should" in + present) echo "gpasswd -a \"$group\" \"$user\"" ;; + absent) echo "gpasswd -d \"$group\" \"$user\"" ;; + esac fi done From f7381e261ae12eedfd9746937145ce0e28e78d08 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 17 Sep 2016 09:48:15 +0200 Subject: [PATCH 0317/1332] Add new type __firewalld_start. --- .../type/__firewalld_start/gencode-remote | 84 +++++++++++++++++++ cdist/conf/type/__firewalld_start/man.rst | 53 ++++++++++++ cdist/conf/type/__firewalld_start/manifest | 23 +++++ .../parameter/default/bootstate | 1 + .../parameter/default/startstate | 1 + .../type/__firewalld_start/parameter/optional | 2 + cdist/conf/type/__firewalld_start/singleton | 0 7 files changed, 164 insertions(+) create mode 100644 cdist/conf/type/__firewalld_start/gencode-remote create mode 100644 cdist/conf/type/__firewalld_start/man.rst create mode 100644 cdist/conf/type/__firewalld_start/manifest create mode 100644 cdist/conf/type/__firewalld_start/parameter/default/bootstate create mode 100644 cdist/conf/type/__firewalld_start/parameter/default/startstate create mode 100644 cdist/conf/type/__firewalld_start/parameter/optional create mode 100644 cdist/conf/type/__firewalld_start/singleton diff --git a/cdist/conf/type/__firewalld_start/gencode-remote b/cdist/conf/type/__firewalld_start/gencode-remote new file mode 100644 index 00000000..7a3b6298 --- /dev/null +++ b/cdist/conf/type/__firewalld_start/gencode-remote @@ -0,0 +1,84 @@ +#!/bin/sh +# +# 2016 Darko Poljak(darko.poljak at ungleich.ch) +# +# 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 . +# +# + +startstate="$(cat "$__object/parameter/startstate")" +init=$(cat "$__global/explorer/init") + +os=$(cat "$__global/explorer/os") +os_version=$(cat "$__global/explorer/os_version") +name="firewalld" + +case "${startstate}" in + present) + cmd="start" + ;; + absent) + cmd="stop" + ;; + *) + echo "Unknown startstate: ${startstate}" >&2 + exit 1 + ;; +esac + +if [ "$init" = 'systemd' ]; then + # this handles ALL linux distros with systemd + # e.g. archlinux, gentoo in some cases, new RHEL and SLES versions + echo "systemctl \"$cmd\" \"$name\"" +else + case "$os" in + debian) + case "$os_version" in + [1-7]*) + echo "service \"$name\" \"$cmd\"" + ;; + 8*) + echo "systemctl \"$cmd\" \"$name\"" + ;; + *) + echo "Unsupported version $os_version of $os" >&2 + exit 1 + ;; + esac + ;; + + gentoo) + echo service \"$name\" \"$cmd\" + ;; + + amazon|scientific|centos|fedora|owl|redhat|suse) + echo service \"$name\" \"$cmd\" + ;; + + openwrt) + echo "/etc/init.d/\"$name\" \"$cmd\"" + ;; + + ubuntu) + echo "service \"$name\" \"$cmd\"" + ;; + + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; + esac +fi diff --git a/cdist/conf/type/__firewalld_start/man.rst b/cdist/conf/type/__firewalld_start/man.rst new file mode 100644 index 00000000..03232b72 --- /dev/null +++ b/cdist/conf/type/__firewalld_start/man.rst @@ -0,0 +1,53 @@ +cdist-type__firewalld_start(7) +============================= + +NAME +---- +cdist-type__firewalld_start - start and enable firewalld + + +DESCRIPTION +----------- +This cdist type allows you to start and enable firewalld. + + +REQUIRED PARAMETERS +------------------- +None + +OPTIONAL PARAMETERS +------------------- +startstate + 'present' or 'absent', start/stop firewalld. Default is 'present'. +bootstate + 'present' or 'absent', enable/disable firewalld on boot. Default is 'present'. + + +EXAMPLES +-------- + +.. code-block:: sh + + # start and enable firewalld + __firewalld_start + + # only enable firewalld to start on boot + __firewalld_start --startstate present --bootstate absent + + +SEE ALSO +-------- +:strong:`firewalld`\ (8) + + +AUTHORS +------- +Darko Poljak + + +COPYING +------- +Copyright \(C) 2016 Darko Poljak. 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/__firewalld_start/manifest b/cdist/conf/type/__firewalld_start/manifest new file mode 100644 index 00000000..2c6a0219 --- /dev/null +++ b/cdist/conf/type/__firewalld_start/manifest @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2016 Darko Poljak (darko.poljak at ungleich.ch) +# +# 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 . + +bootstate="$(cat "$__object/parameter/bootstate")" + +__package firewalld +require="__package/firewalld" __start_on_boot firewalld --state "${bootstate}" diff --git a/cdist/conf/type/__firewalld_start/parameter/default/bootstate b/cdist/conf/type/__firewalld_start/parameter/default/bootstate new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__firewalld_start/parameter/default/bootstate @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__firewalld_start/parameter/default/startstate b/cdist/conf/type/__firewalld_start/parameter/default/startstate new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__firewalld_start/parameter/default/startstate @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__firewalld_start/parameter/optional b/cdist/conf/type/__firewalld_start/parameter/optional new file mode 100644 index 00000000..934c7d0d --- /dev/null +++ b/cdist/conf/type/__firewalld_start/parameter/optional @@ -0,0 +1,2 @@ +bootstate +startstate diff --git a/cdist/conf/type/__firewalld_start/singleton b/cdist/conf/type/__firewalld_start/singleton new file mode 100644 index 00000000..e69de29b From f87d31f42375c13a059fb306baf111eedf48533b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 17 Sep 2016 17:33:53 +0200 Subject: [PATCH 0318/1332] Update changelog: new type __firewalld_start. --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index ba0ce9c5..dac0e205 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * New type: __firewalld_start: start/stop firewalld and/or enable/disable start on boot (Darko Poljak) + 4.3.1: 2016-08-22 * Documentation: Spelling fixes (Darko Poljak) * Type __filesystem: Spelling fixes (Dmitry Bogatov) From 74652cec1327e12271675d712cb47ca49b0d0bbf Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 21 Sep 2016 19:22:24 +0200 Subject: [PATCH 0319/1332] Write more informative warning messages. --- cdist/config.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index e20f1a7c..b0131601 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -266,12 +266,10 @@ class Config(object): host_name = socket.gethostbyaddr(ip_addr)[0] log.debug("derived host_name for host \"{}\": {}".format( host, host_name)) - except socket.gaierror as e: - log.warn("host_name: {}".format(e)) - # in case of error provide empty value - host_name = '' - except socket.herror as e: - log.warn("host_name: {}".format(e)) + except (socket.gaierror, socket.herror) as e: + log.warn("Could not derive host_name for {}" + ", $host_name will be empty. Error is: {}".format( + host, e)) # in case of error provide empty value host_name = '' @@ -280,9 +278,12 @@ class Config(object): log.debug("derived host_fqdn for host \"{}\": {}".format( host, host_fqdn)) except socket.herror as e: - log.warn("host_fqdn: {}".format(e)) + log.warn("Could not derive host_fqdn for {}" + ", $host_fqdn will be empty. Error is: {}".format( + host, e)) # in case of error provide empty value host_fqdn = '' + target_host = (host, host_name, host_fqdn) local = cdist.exec.local.Local( From bee55935700b51b037d0216b5f034fe3d382c6ef Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 4 Oct 2016 11:29:48 +0200 Subject: [PATCH 0320/1332] use /etc/os-release instead of /etc/SuSE-release --- cdist/conf/explorer/os_version | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/conf/explorer/os_version b/cdist/conf/explorer/os_version index 58f750b0..380782cc 100755 --- a/cdist/conf/explorer/os_version +++ b/cdist/conf/explorer/os_version @@ -61,7 +61,11 @@ case "$($__explorer/os)" in cat /etc/slackware-version ;; suse) - cat /etc/SuSE-release + if [ -f /etc/os-release ]; then + cat /etc/os-release + else + cat /etc/SuSE-release + fi ;; ubuntu) lsb_release -sr From 8e967424de8bff0de7707043fb94b0ae80e4b48e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 5 Oct 2016 23:22:36 +0200 Subject: [PATCH 0321/1332] consul syslog config option should be called enable_syslog instead Signed-off-by: Steven Armstrong --- cdist/conf/type/__consul_agent/man.rst | 2 +- cdist/conf/type/__consul_agent/manifest | 2 +- cdist/conf/type/__consul_agent/parameter/boolean | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__consul_agent/man.rst b/cdist/conf/type/__consul_agent/man.rst index 8285cb25..d75425d7 100644 --- a/cdist/conf/type/__consul_agent/man.rst +++ b/cdist/conf/type/__consul_agent/man.rst @@ -106,7 +106,7 @@ rejoin-after-leave server used to control if an agent is in server or client mode -syslog +enable-syslog enables logging to syslog verify-incoming diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index b4d1d75c..e98d770b 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -98,7 +98,7 @@ for param in $(ls "$__object/parameter/"); do key="$(echo "${param%-*}" | tr '-' '_')" printf ' ,"%s": "%s"\n' "$key" "$destination" ;; - disable-remote-exec|disable-update-check|leave-on-terminate|rejoin-after-leave|server|syslog|verify-incoming|verify-outgoing) + disable-remote-exec|disable-update-check|leave-on-terminate|rejoin-after-leave|server|enable-syslog|verify-incoming|verify-outgoing) # handle boolean parameters key="$(echo "$param" | tr '-' '_')" printf ' ,"%s": true\n' "$key" diff --git a/cdist/conf/type/__consul_agent/parameter/boolean b/cdist/conf/type/__consul_agent/parameter/boolean index 9efecf49..91f7f17e 100644 --- a/cdist/conf/type/__consul_agent/parameter/boolean +++ b/cdist/conf/type/__consul_agent/parameter/boolean @@ -3,6 +3,6 @@ disable-update-check leave-on-terminate rejoin-after-leave server -syslog +enable-syslog verify-incoming verify-outgoing From 88b436b4c17f594cbcd747b936961da0b674d570 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 6 Oct 2016 23:34:50 +0200 Subject: [PATCH 0322/1332] changelog++ Signed-off-by: Steven Armstrong --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index dac0e205..61fc93cf 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,8 @@ Changelog next: * New type: __firewalld_start: start/stop firewalld and/or enable/disable start on boot (Darko Poljak) + * Bugfix __consul_agent: config option was misnamed 'syslog' instead of + 'enable_syslog' (Steven Armstrong) 4.3.1: 2016-08-22 * Documentation: Spelling fixes (Darko Poljak) From d49af95d3c3665ebb86465862449292bf04aa03e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 8 Oct 2016 11:40:32 +0200 Subject: [PATCH 0323/1332] Add warning message for faulty dependencies case. --- cdist/conf/type/__firewalld_start/man.rst | 2 +- cdist/emulator.py | 28 +++++++++- cdist/test/config/__init__.py | 16 ++++++ .../fixtures/manifest/init-deps-resolver | 8 +++ cdist/test/config/fixtures/type/__a/.keep | 0 cdist/test/config/fixtures/type/__b/.keep | 0 cdist/test/config/fixtures/type/__c/.keep | 0 cdist/test/config/fixtures/type/__d/.keep | 0 cdist/test/config/fixtures/type/__e/.keep | 0 cdist/test/config/fixtures/type/__f/.keep | 0 cdist/test/config/fixtures/type/__g/.keep | 0 cdist/test/config/fixtures/type/__g/manifest | 1 + cdist/test/config/fixtures/type/__h/.keep | 0 cdist/test/config/fixtures/type/__h/manifest | 3 ++ cdist/test/config/fixtures/type/__i/.keep | 0 cdist/test/config/fixtures/type/__j/.keep | 0 cdist/test/emulator/__init__.py | 54 +++++++++++++++++++ docs/src/man1/cdist.rst | 29 ++++++++++ 18 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 cdist/test/config/fixtures/manifest/init-deps-resolver create mode 100644 cdist/test/config/fixtures/type/__a/.keep create mode 100644 cdist/test/config/fixtures/type/__b/.keep create mode 100644 cdist/test/config/fixtures/type/__c/.keep create mode 100644 cdist/test/config/fixtures/type/__d/.keep create mode 100644 cdist/test/config/fixtures/type/__e/.keep create mode 100644 cdist/test/config/fixtures/type/__f/.keep create mode 100644 cdist/test/config/fixtures/type/__g/.keep create mode 100644 cdist/test/config/fixtures/type/__g/manifest create mode 100644 cdist/test/config/fixtures/type/__h/.keep create mode 100644 cdist/test/config/fixtures/type/__h/manifest create mode 100644 cdist/test/config/fixtures/type/__i/.keep create mode 100644 cdist/test/config/fixtures/type/__j/.keep diff --git a/cdist/conf/type/__firewalld_start/man.rst b/cdist/conf/type/__firewalld_start/man.rst index 03232b72..74199cd6 100644 --- a/cdist/conf/type/__firewalld_start/man.rst +++ b/cdist/conf/type/__firewalld_start/man.rst @@ -1,5 +1,5 @@ cdist-type__firewalld_start(7) -============================= +============================== NAME ---- diff --git a/cdist/emulator.py b/cdist/emulator.py index b04ed130..6744de8b 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -84,6 +84,10 @@ class Emulator(object): self.type_name = os.path.basename(argv[0]) self.cdist_type = core.CdistType(self.type_base_path, self.type_name) + # If set then object alreay exists and this var holds existing + # requirements. + self._existing_reqs = None + self.__init_log() def run(self): @@ -166,6 +170,9 @@ class Emulator(object): self.parameters[key] = value if self.cdist_object.exists and 'CDIST_OVERRIDE' not in self.env: + # Make existing requirements a set so that we can compare it + # later with new requirements. + self._existing_reqs = set(self.cdist_object.requirements) if self.cdist_object.parameters != self.parameters: errmsg = ("Object %s already exists with conflicting " "parameters:\n%s: %s\n%s: %s" % ( @@ -243,7 +250,7 @@ class Emulator(object): return cdist_object.name def record_requirements(self): - """record requirements""" + """Record requirements.""" # Inject the predecessor, but not if its an override # (this would leed to an circular dependency) @@ -267,6 +274,7 @@ class Emulator(object): # so do not set a requirement pass + reqs = set() if "require" in self.env: requirements = self.env['require'] self.log.debug("reqs = " + requirements) @@ -274,7 +282,23 @@ class Emulator(object): # Ignore empty fields - probably the only field anyway if len(requirement) == 0: continue - self.record_requirement(requirement) + object_name = self.record_requirement(requirement) + reqs.add(object_name) + if self._existing_reqs is not None: + # If object exists then compare existing and new requirements. + if self._existing_reqs != reqs: + warnmsg = ("Object {} already exists with requirements:\n" + "{}: {}\n" + "{}: {}\n" + "Dependency resolver could not handle dependencies " + "as expected.".format( + self.cdist_object.name, + " ".join(self.cdist_object.source), + self._existing_reqs, + self.object_source, + reqs + )) + self.log.warning(warnmsg) def record_auto_requirements(self): """An object shall automatically depend on all objects that it diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index db753f41..af1aa38f 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -177,6 +177,22 @@ class ConfigRunTestCase(test.CdistTestCase): dryrun.run() # if we are here, dryrun works like expected + def test_desp_resolver(self): + """Test to show dependency resolver warning message.""" + local = cdist.exec.local.Local( + target_host=self.target_host, + base_root_path=self.host_base_path, + host_dir_name=self.hostdir, + exec_path=os.path.abspath(os.path.join( + my_dir, '../../../scripts/cdist')), + initial_manifest=os.path.join( + fixtures, 'manifest/init-deps-resolver'), + add_conf_dirs=[fixtures]) + + # dry_run is ok for dependency testing + config = cdist.config.Config(local, self.remote, dry_run=True) + config.run() + # Currently the resolving code will simply detect that this object does # not exist. It should probably check if the type is a singleton as well diff --git a/cdist/test/config/fixtures/manifest/init-deps-resolver b/cdist/test/config/fixtures/manifest/init-deps-resolver new file mode 100644 index 00000000..f67ab61c --- /dev/null +++ b/cdist/test/config/fixtures/manifest/init-deps-resolver @@ -0,0 +1,8 @@ +__a a +require="__e/e" __b b +require="__f/f" __c c +__e e +__f f +require="__c/c" __d d +__g g +__h h diff --git a/cdist/test/config/fixtures/type/__a/.keep b/cdist/test/config/fixtures/type/__a/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__b/.keep b/cdist/test/config/fixtures/type/__b/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__c/.keep b/cdist/test/config/fixtures/type/__c/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__d/.keep b/cdist/test/config/fixtures/type/__d/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__e/.keep b/cdist/test/config/fixtures/type/__e/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__f/.keep b/cdist/test/config/fixtures/type/__f/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__g/.keep b/cdist/test/config/fixtures/type/__g/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__g/manifest b/cdist/test/config/fixtures/type/__g/manifest new file mode 100644 index 00000000..107dbda4 --- /dev/null +++ b/cdist/test/config/fixtures/type/__g/manifest @@ -0,0 +1 @@ +require="__c/c __d/d" __a a diff --git a/cdist/test/config/fixtures/type/__h/.keep b/cdist/test/config/fixtures/type/__h/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__h/manifest b/cdist/test/config/fixtures/type/__h/manifest new file mode 100644 index 00000000..ce3d8fb7 --- /dev/null +++ b/cdist/test/config/fixtures/type/__h/manifest @@ -0,0 +1,3 @@ +# require="__b/b" __a a +require="__j/j" __i i +__j j diff --git a/cdist/test/config/fixtures/type/__i/.keep b/cdist/test/config/fixtures/type/__i/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__j/.keep b/cdist/test/config/fixtures/type/__j/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 4fd0ed40..51de3180 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -499,6 +499,60 @@ class StdinTestCase(test.CdistTestCase): self.assertEqual(random_string, stdin_saved_by_emulator) +class EmulatorAlreadyExistingRequirementsWarnTestCase(test.CdistTestCase): + + def setUp(self): + self.temp_dir = self.mkdtemp() + handle, self.script = self.mkstemp(dir=self.temp_dir) + os.close(handle) + base_path = self.temp_dir + hostdir = cdist.str_hash(self.target_host[0]) + host_base_path = os.path.join(base_path, hostdir) + + self.local = local.Local( + target_host=self.target_host, + base_root_path=host_base_path, + host_dir_name=hostdir, + exec_path=test.cdist_exec_path, + add_conf_dirs=[conf_dir]) + self.local.create_files_dirs() + + self.manifest = core.Manifest(self.target_host, self.local) + self.env = self.manifest.env_initial_manifest(self.script) + self.env['__cdist_object_marker'] = self.local.object_marker_name + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_object_existing_requirements_req_none(self): + """Test to show dependency resolver warning message.""" + argv = ['__directory', 'spam'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', 'eggs'] + self.env['require'] = '__directory/spam' + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', 'eggs'] + if 'require' in self.env: + del self.env['require'] + emu = emulator.Emulator(argv, env=self.env) + + def test_object_existing_requirements_none_req(self): + """Test to show dependency resolver warning message.""" + argv = ['__directory', 'spam'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', 'eggs'] + if 'require' in self.env: + del self.env['require'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', 'eggs'] + self.env['require'] = '__directory/spam' + emu = emulator.Emulator(argv, env=self.env) + + if __name__ == '__main__': import unittest unittest.main() diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 52562e14..9cc28011 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -246,6 +246,35 @@ connection. In this case ssh will disable multiplexing. This limit is controlled with sshd :strong:`MaxSessions` configuration options. For more details refer to :strong:`sshd_config`\ (5). +When requirements for the same object are defined in different manifests (see +example below) in init manifest and in some other type manifest and they differs +then dependency resolver cannot detect dependencies right. This happends because +cdist cannot prepare all objects first and then run objects because some +object can depend on the result of type explorer(s) and explorers are executed +during object run. cdist will detect such case and write warning message. +Example for such a case: + +.. code-block:: sh + + init manifest: + __a a + require="__e/e" __b b + require="__f/f" __c c + __e e + __f f + require="__c/c" __d d + __g g + __h h + + type __g manifest: + require="__c/c __d/d" __a a + + Warning message: + .WARNING: cdisttesthost: Object __a/a already exists with requirements: + /usr/home/darko/ungleich/cdist/cdist/test/config/fixtures/manifest/init-deps-resolver /tmp/tmp.cdist.test.ozagkg54/local/759547ff4356de6e3d9e08522b0d0807/data/conf/type/__g/manifest: set() + /tmp/tmp.cdist.test.ozagkg54/local/759547ff4356de6e3d9e08522b0d0807/data/conf/type/__g/manifest: {'__c/c', '__d/d'} + Dependency resolver could not handle dependencies as expected. + COPYING ------- Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is From c4e89eb2457d79e0af3ae100367439be668124a3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 8 Oct 2016 11:44:55 +0200 Subject: [PATCH 0324/1332] Fix spelling. --- docs/src/man1/cdist.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 9cc28011..5a30c321 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -248,7 +248,7 @@ options. For more details refer to :strong:`sshd_config`\ (5). When requirements for the same object are defined in different manifests (see example below) in init manifest and in some other type manifest and they differs -then dependency resolver cannot detect dependencies right. This happends because +then dependency resolver cannot detect dependencies right. This happens because cdist cannot prepare all objects first and then run objects because some object can depend on the result of type explorer(s) and explorers are executed during object run. cdist will detect such case and write warning message. From ddd8eab06f182819bb07bebe0d3ba24b3756f23c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 8 Oct 2016 11:45:50 +0200 Subject: [PATCH 0325/1332] Remove extra dot. --- docs/src/man1/cdist.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 5a30c321..c80b3386 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -270,7 +270,7 @@ Example for such a case: require="__c/c __d/d" __a a Warning message: - .WARNING: cdisttesthost: Object __a/a already exists with requirements: + WARNING: cdisttesthost: Object __a/a already exists with requirements: /usr/home/darko/ungleich/cdist/cdist/test/config/fixtures/manifest/init-deps-resolver /tmp/tmp.cdist.test.ozagkg54/local/759547ff4356de6e3d9e08522b0d0807/data/conf/type/__g/manifest: set() /tmp/tmp.cdist.test.ozagkg54/local/759547ff4356de6e3d9e08522b0d0807/data/conf/type/__g/manifest: {'__c/c', '__d/d'} Dependency resolver could not handle dependencies as expected. From aa4c3dc7bda3e3a29c0cb67a503e35fb86955d2b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 10 Oct 2016 12:25:10 +0200 Subject: [PATCH 0326/1332] Update changelog. --- docs/changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog b/docs/changelog index 61fc93cf..4ea8cddd 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,11 @@ Changelog --------- next: + * Core: Add warning message for faulty dependencies case (Darko Poljak) + * Explorer os_version: Use /etc/os-release instead of /etc/SuSE-release (Daniel Heule) + * Type __package: Call __package_pkg_openbsd on openbsd (Andres Erbsen) + * Type __package_pkg_openbsd: Support --version (Andres Erbsen) + * Type __hostname: Support openbsd (Andres Erbsen) * New type: __firewalld_start: start/stop firewalld and/or enable/disable start on boot (Darko Poljak) * Bugfix __consul_agent: config option was misnamed 'syslog' instead of 'enable_syslog' (Steven Armstrong) From ce4803a201ffe7bdb3526556b8ed086218b83d81 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 12 Oct 2016 16:56:29 +0200 Subject: [PATCH 0327/1332] telmich -> ungleich --- cdist/conf/type/__cdist/man.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__cdist/man.rst b/cdist/conf/type/__cdist/man.rst index 72b11e78..9e1c72cb 100644 --- a/cdist/conf/type/__cdist/man.rst +++ b/cdist/conf/type/__cdist/man.rst @@ -30,7 +30,7 @@ username source Select the source from which to clone cdist from. - Defaults to "git://github.com/telmich/cdist.git". + Defaults to "git://github.com/ungleich/cdist.git". branch @@ -47,7 +47,7 @@ EXAMPLES __cdist /home/cdist/cdist # Use alternative source - __cdist --source "git://github.com/telmich/cdist" /home/cdist/cdist + __cdist --source "git://github.com/ungleich/cdist" /home/cdist/cdist AUTHORS From 67d93f3e0a693783bf7af00837d3dd841fc84c62 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 12 Oct 2016 16:59:45 +0200 Subject: [PATCH 0328/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 4ea8cddd..5a23cc6e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Documentation: Update no longer existing links (Simon Walter) * Core: Add warning message for faulty dependencies case (Darko Poljak) * Explorer os_version: Use /etc/os-release instead of /etc/SuSE-release (Daniel Heule) * Type __package: Call __package_pkg_openbsd on openbsd (Andres Erbsen) From aceb4ac13d66d71190c2747aea85b1550b2c9b73 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 12 Oct 2016 20:15:07 +0200 Subject: [PATCH 0329/1332] Update telmich -> ungleich and mailing list refs. --- cdist/conf/type/__cdist/parameter/default/source | 2 +- cdist/conf/type/__cdistmarker/gencode-remote | 2 +- cdist/conf/type/__git/man.rst | 2 +- docs/src/cdist-hacker.rst | 6 +++--- docs/web/cdist/install.mdwn | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__cdist/parameter/default/source b/cdist/conf/type/__cdist/parameter/default/source index d669308f..3f8e31ad 100644 --- a/cdist/conf/type/__cdist/parameter/default/source +++ b/cdist/conf/type/__cdist/parameter/default/source @@ -1 +1 @@ -git://github.com/telmich/cdist.git +git://github.com/ungleich/cdist.git diff --git a/cdist/conf/type/__cdistmarker/gencode-remote b/cdist/conf/type/__cdistmarker/gencode-remote index 92ea582b..5e889e52 100755 --- a/cdist/conf/type/__cdistmarker/gencode-remote +++ b/cdist/conf/type/__cdistmarker/gencode-remote @@ -2,7 +2,7 @@ # # Copyright (C) 2011 Daniel Maher (phrawzty+cdist at gmail.com) # -# This file is part of cdist (https://github.com/telmich/cdist/). +# 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 diff --git a/cdist/conf/type/__git/man.rst b/cdist/conf/type/__git/man.rst index 64adfd2f..17e9c623 100644 --- a/cdist/conf/type/__git/man.rst +++ b/cdist/conf/type/__git/man.rst @@ -44,7 +44,7 @@ EXAMPLES __git /home/services/dokuwiki --source git://github.com/splitbrain/dokuwiki.git # Checkout cdist, stay on branch 2.1 - __git /home/nico/cdist --source git://github.com/telmich/cdist.git --branch 2.1 + __git /home/nico/cdist --source git://github.com/ungleich/cdist.git --branch 2.1 AUTHORS diff --git a/docs/src/cdist-hacker.rst b/docs/src/cdist-hacker.rst index efc5da4b..d7d6a056 100644 --- a/docs/src/cdist-hacker.rst +++ b/docs/src/cdist-hacker.rst @@ -50,8 +50,8 @@ work nor kill the authors brain: the other needs to be improved. As soon as your work meets these requirements, write a mail -for inclusion to the mailinglist **cdist at cdist -- at -- l.schottelius.org** -or open a pull request at http://github.com/telmich/cdist. +for inclusion to the mailinglist **cdist-configuration-management at googlegroups.com** +or open a pull request at http://github.com/ungleich/cdist. How to submit a new type @@ -77,7 +77,7 @@ The following workflow works fine for most developers .. code-block:: sh # get latest upstream master branch - git clone https://github.com/telmich/cdist.git + git clone https://github.com/ungleich/cdist.git # update if already existing cd cdist; git fetch -v; git merge origin/master diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index cff2d369..0ced26db 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -29,7 +29,7 @@ immediately. To install cdist, execute the following commands: - git clone https://github.com/telmich/cdist.git + git clone https://github.com/ungleich/cdist.git cd cdist export PATH=$PATH:$(pwd -P)/bin From 54f752a42a07beba13e970635b822b11aea9d908 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 13 Oct 2016 18:51:43 +0200 Subject: [PATCH 0330/1332] Release 4.3.2 --- docs/changelog | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/changelog b/docs/changelog index 5a23cc6e..1b7de44f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.3.2: 2016-10-13 * Documentation: Update no longer existing links (Simon Walter) * Core: Add warning message for faulty dependencies case (Darko Poljak) * Explorer os_version: Use /etc/os-release instead of /etc/SuSE-release (Daniel Heule) @@ -9,8 +9,7 @@ next: * Type __package_pkg_openbsd: Support --version (Andres Erbsen) * Type __hostname: Support openbsd (Andres Erbsen) * New type: __firewalld_start: start/stop firewalld and/or enable/disable start on boot (Darko Poljak) - * Bugfix __consul_agent: config option was misnamed 'syslog' instead of - 'enable_syslog' (Steven Armstrong) + * Bugfix __consul_agent: config option was misnamed 'syslog' instead of 'enable_syslog' (Steven Armstrong) 4.3.1: 2016-08-22 * Documentation: Spelling fixes (Darko Poljak) From acf94abe2639d3132489b7c52134f4ccc05be6bd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 13 Oct 2016 21:24:29 +0200 Subject: [PATCH 0331/1332] pep8 --- cdist/install.py | 7 ++++--- scripts/cdist | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cdist/install.py b/cdist/install.py index 4530029a..bec8d24a 100644 --- a/cdist/install.py +++ b/cdist/install.py @@ -29,9 +29,10 @@ class Install(cdist.config.Config): """Short name for object list retrieval. In install mode, we only care about install objects. """ - for cdist_object in cdist.core.CdistObject.list_objects(self.local.object_path, - self.local.type_path): + for cdist_object in cdist.core.CdistObject.list_objects( + self.local.object_path, self.local.type_path): if cdist_object.cdist_type.is_install: yield cdist_object else: - self.log.debug("Running in install mode, ignoring non install object: {0}".format(cdist_object)) + self.log.debug("Running in install mode, ignoring non install" + "object: {0}".format(cdist_object)) diff --git a/scripts/cdist b/scripts/cdist index badf0f76..0acfe06c 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -164,7 +164,7 @@ def commandline(): # Install parser['install'] = parser['sub'].add_parser('install', add_help=False, - parents=[parser['config']]) + parents=[parser['config']]) parser['install'].set_defaults(func=cdist.install.Install.commandline) for p in parser: From 750f90db4c4dfbe4bcfb83fb62562e2c0133059e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 13 Oct 2016 21:35:41 +0200 Subject: [PATCH 0332/1332] Make install command beta. --- cdist/__init__.py | 20 ++++++++++++++------ scripts/cdist | 6 ++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index 9068ae69..b6f5c8cb 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -59,16 +59,24 @@ class UnresolvableRequirementsError(cdist.Error): class CdistBetaRequired(cdist.Error): """Beta functionality is used but beta is not enabled""" - def __init__(self, command, arg): + def __init__(self, command, arg=None): self.command = command self.arg = arg def __str__(self): - err_msg = ("\'{}\' argument of \'{}\' command is beta, but beta is " - "not enabled. If you want to use it please enable beta " - "functionalities by using the -b/--enable-beta command " - "line flag.") - return err_msg.format(self.arg, self.command) + if self.arg is None: + err_msg = ("\'{}\' command is beta, but beta is " + "not enabled. If you want to use it please enable beta " + "functionalities by using the -b/--enable-beta command " + "line flag.") + fmt_args = [self.command, ] + else: + err_msg = ("\'{}\' argument of \'{}\' command is beta, but beta " + "is not enabled. If you want to use it please enable " + "beta functionalities by using the -b/--enable-beta " + "command line flag.") + fmt_args = [self.arg, self.command, ] + return err_msg.format(*fmt_args) class CdistObjectError(Error): diff --git a/scripts/cdist b/scripts/cdist index 0acfe06c..9f8d326d 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -22,6 +22,8 @@ # +# list of beta sub-commands +BETA_COMMANDS = ['install', ] # list of beta arguments for sub-commands BETA_ARGS = { 'config': ['jobs', ], @@ -49,6 +51,10 @@ def check_beta(args_dict): # raise error. if not args_dict['beta']: cmd = args_dict['command'] + # first check if command is beta + if cmd in BETA_COMMANDS: + raise cdist.CdistBetaRequired(cmd) + # then check if command's argument is beta if cmd in BETA_ARGS: for arg in BETA_ARGS[cmd]: if arg in args_dict and args_dict[arg]: From 536a64e56dac0b4c2793c440c551a3f8d0b98ba3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 13 Oct 2016 21:38:34 +0200 Subject: [PATCH 0333/1332] Add install to cdist man page. --- docs/src/man1/cdist.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index c80b3386..45ce339e 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -11,7 +11,7 @@ SYNOPSIS :: - cdist [-h] [-d] [-v] [-V] {banner,config,shell} ... + cdist [-h] [-d] [-v] [-V] {banner,config,shell,install} ... cdist banner [-h] [-d] [-v] @@ -20,6 +20,11 @@ SYNOPSIS [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [host [host ...]] + cdist install [-h] [-d] [-v] [-b] [-c CONF_DIR] [-f HOSTFILE] + [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-p] [-s] + [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] + [host [host ...]] + cdist shell [-h] [-d] [-v] [-s SHELL] @@ -58,9 +63,9 @@ Displays the cdist banner. Useful for printing cdist posters - a must have for every office. -CONFIG ------- -Configure one or more hosts. +CONFIG/INSTALL +-------------- +Configure/install one or more hosts. .. option:: -b, --enable-beta @@ -191,6 +196,8 @@ EXAMPLES usage: __git --source SOURCE [--state STATE] [--branch BRANCH] [--group GROUP] [--owner OWNER] [--mode MODE] object_id + # Install ikq05.ethz.ch with debug enabled + % cdist install -d ikq05.ethz.ch ENVIRONMENT ----------- From ac94d182b6ea2d5676d9a59243399f1e3c78587c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 13 Oct 2016 21:40:09 +0200 Subject: [PATCH 0334/1332] Add install to bash/zsh completions. --- completions/bash/cdist-completion.bash | 4 ++-- completions/zsh/_cdist | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/completions/bash/cdist-completion.bash b/completions/bash/cdist-completion.bash index c756fca8..68f45327 100644 --- a/completions/bash/cdist-completion.bash +++ b/completions/bash/cdist-completion.bash @@ -6,7 +6,7 @@ _cdist() prev="${COMP_WORDS[COMP_CWORD-1]}" prevprev="${COMP_WORDS[COMP_CWORD-2]}" opts="-h --help -d --debug -v --verbose -V --version" - cmds="banner shell config" + cmds="banner shell config install" case "${prevprev}" in shell) @@ -35,7 +35,7 @@ _cdist() COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 ;; - config) + config|install) opts="-h --help -d --debug -v --verbose -b --enable-beta \ -c --conf-dir -f --file -i --initial-manifest -j --jobs \ -n --dry-run -o --out-dir -p --parallel -s --sequential \ diff --git a/completions/zsh/_cdist b/completions/zsh/_cdist index 18fda0f0..dc320224 100644 --- a/completions/zsh/_cdist +++ b/completions/zsh/_cdist @@ -11,7 +11,7 @@ _cdist() case $state in opts_cmds) - _arguments '1:Options and commands:(banner config shell -h --help -d --debug -v --verbose -V --version)' + _arguments '1:Options and commands:(banner config shell install -h --help -d --debug -v --verbose -V --version)' ;; *) case $words[2] in @@ -35,7 +35,7 @@ _cdist() ;; esac ;; - config) + config|install) opts=(-h --help -d --debug -v --verbose -b --enable-beta -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -s --sequential --remote-copy --remote-exec) compadd "$@" -- $opts ;; From a05ae761a400e35c1f851648c0d74a55ab369899 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 14 Oct 2016 21:16:28 +0200 Subject: [PATCH 0335/1332] man.text -> man.rst --- .../type/__cdist_preos/{man.text => man.rst} | 28 +++++--- .../type/__chroot_mount/{man.text => man.rst} | 24 +++---- .../__chroot_umount/{man.text => man.rst} | 25 +++++--- .../{man.text => man.rst} | 29 +++++---- .../conf/type/__install_chroot_mount/man.rst | 1 + .../conf/type/__install_chroot_mount/man.text | 1 - .../conf/type/__install_chroot_umount/man.rst | 1 + .../type/__install_chroot_umount/man.text | 1 - .../__install_config/{man.text => man.rst} | 26 ++++---- cdist/conf/type/__install_file/man.rst | 1 + cdist/conf/type/__install_file/man.text | 1 - .../__install_fstab/{man.text => man.rst} | 31 +++++---- .../{man.text => man.rst} | 29 +++++---- cdist/conf/type/__install_mkfs/man.rst | 62 ++++++++++++++++++ cdist/conf/type/__install_mkfs/man.text | 57 ----------------- .../__install_mount/{man.text => man.rst} | 40 ++++++------ .../type/__install_partition_msdos/man.rst | 64 +++++++++++++++++++ .../type/__install_partition_msdos/man.text | 62 ------------------ .../{man.text => man.rst} | 25 +++++--- .../__install_reboot/{man.text => man.rst} | 24 +++---- .../{man.text => man.rst} | 24 +++---- cdist/conf/type/__install_stage/man.rst | 58 +++++++++++++++++ cdist/conf/type/__install_stage/man.text | 58 ----------------- .../__install_umount/{man.text => man.rst} | 24 +++---- 24 files changed, 367 insertions(+), 329 deletions(-) rename cdist/conf/type/__cdist_preos/{man.text => man.rst} (52%) rename cdist/conf/type/__chroot_mount/{man.text => man.rst} (50%) rename cdist/conf/type/__chroot_umount/{man.text => man.rst} (52%) rename cdist/conf/type/__install_bootloader_grub/{man.text => man.rst} (55%) create mode 120000 cdist/conf/type/__install_chroot_mount/man.rst delete mode 120000 cdist/conf/type/__install_chroot_mount/man.text create mode 120000 cdist/conf/type/__install_chroot_umount/man.rst delete mode 120000 cdist/conf/type/__install_chroot_umount/man.text rename cdist/conf/type/__install_config/{man.text => man.rst} (60%) create mode 120000 cdist/conf/type/__install_file/man.rst delete mode 120000 cdist/conf/type/__install_file/man.text rename cdist/conf/type/__install_fstab/{man.text => man.rst} (54%) rename cdist/conf/type/__install_generate_fstab/{man.text => man.rst} (57%) create mode 100644 cdist/conf/type/__install_mkfs/man.rst delete mode 100644 cdist/conf/type/__install_mkfs/man.text rename cdist/conf/type/__install_mount/{man.text => man.rst} (54%) create mode 100644 cdist/conf/type/__install_partition_msdos/man.rst delete mode 100644 cdist/conf/type/__install_partition_msdos/man.text rename cdist/conf/type/__install_partition_msdos_apply/{man.text => man.rst} (52%) rename cdist/conf/type/__install_reboot/{man.text => man.rst} (52%) rename cdist/conf/type/__install_reset_disk/{man.text => man.rst} (50%) create mode 100644 cdist/conf/type/__install_stage/man.rst delete mode 100644 cdist/conf/type/__install_stage/man.text rename cdist/conf/type/__install_umount/{man.text => man.rst} (54%) diff --git a/cdist/conf/type/__cdist_preos/man.text b/cdist/conf/type/__cdist_preos/man.rst similarity index 52% rename from cdist/conf/type/__cdist_preos/man.text rename to cdist/conf/type/__cdist_preos/man.rst index 19caa8e2..8b7d22d6 100644 --- a/cdist/conf/type/__cdist_preos/man.text +++ b/cdist/conf/type/__cdist_preos/man.rst @@ -1,7 +1,5 @@ cdist-type__cdist_preos(7) ========================== -Nico Schottelius - NAME ---- @@ -13,26 +11,38 @@ DESCRIPTION This cdist type creates a directory containing an operating suitable for installation using cdist. + REQUIRED PARAMETERS ------------------- +None + OPTIONAL PARAMETERS ------------------- +None + + EXAMPLES -------- --------------------------------------------------------------------------------- -__cdist_preos /tmp/random_name_for_packaging --------------------------------------------------------------------------------- +.. code-block:: sh + + __cdist_preos /tmp/random_name_for_packaging SEE ALSO -------- -- cdist-type(7) -- cdist-type__cdist(7) +:strong:`cdist-type__cdist`\ (7) + + +AUTHORS +------- +Nico Schottelius COPYING ------- -Copyright \(C) 2015 Nico Schottelius. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +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. diff --git a/cdist/conf/type/__chroot_mount/man.text b/cdist/conf/type/__chroot_mount/man.rst similarity index 50% rename from cdist/conf/type/__chroot_mount/man.text rename to cdist/conf/type/__chroot_mount/man.rst index adce80d9..5ffd7de5 100644 --- a/cdist/conf/type/__chroot_mount/man.text +++ b/cdist/conf/type/__chroot_mount/man.rst @@ -1,7 +1,5 @@ cdist-type__install_chroot_mount(7) =================================== -Steven Armstrong - NAME ---- @@ -15,28 +13,30 @@ Mount and prepare a chroot for running commands within it. REQUIRED PARAMETERS ------------------- -None. +None OPTIONAL PARAMETERS ------------------- -None. +None EXAMPLES -------- --------------------------------------------------------------------------------- -__install_chroot_mount /path/to/chroot --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_chroot_mount /path/to/chroot -SEE ALSO --------- -- cdist-type(7) +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__chroot_umount/man.text b/cdist/conf/type/__chroot_umount/man.rst similarity index 52% rename from cdist/conf/type/__chroot_umount/man.text rename to cdist/conf/type/__chroot_umount/man.rst index a5ca1ef0..a2ea1d9b 100644 --- a/cdist/conf/type/__chroot_umount/man.text +++ b/cdist/conf/type/__chroot_umount/man.rst @@ -1,7 +1,5 @@ cdist-type__install_chroot_umount(7) ==================================== -Steven Armstrong - NAME ---- @@ -15,28 +13,35 @@ Undo what __chroot_mount did. REQUIRED PARAMETERS ------------------- -None. +None OPTIONAL PARAMETERS ------------------- -None. +None EXAMPLES -------- --------------------------------------------------------------------------------- -__install_chroot_umount /path/to/chroot --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_chroot_umount /path/to/chroot SEE ALSO -------- -- cdist-type(7) +:strong:`cdist-type__chroot_mount`\ (7) + + +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__install_bootloader_grub/man.text b/cdist/conf/type/__install_bootloader_grub/man.rst similarity index 55% rename from cdist/conf/type/__install_bootloader_grub/man.text rename to cdist/conf/type/__install_bootloader_grub/man.rst index 858e6a67..625db1d2 100644 --- a/cdist/conf/type/__install_bootloader_grub/man.text +++ b/cdist/conf/type/__install_bootloader_grub/man.rst @@ -1,7 +1,5 @@ cdist-type__install_bootloader_grub(7) ====================================== -Steven Armstrong - NAME ---- @@ -15,33 +13,36 @@ This cdist type allows you to install grub2 bootloader on given disk. REQUIRED PARAMETERS ------------------- -None. +None OPTIONAL PARAMETERS ------------------- -device:: +device The device to install grub to. Defaults to object_id -chroot:: +chroot where to chroot before running grub-install. Defaults to /target. EXAMPLES -------- --------------------------------------------------------------------------------- -__install_bootloader_grub /dev/sda -__install_bootloader_grub /dev/sda --chroot /mnt/foobar --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_bootloader_grub /dev/sda + + __install_bootloader_grub /dev/sda --chroot /mnt/foobar -SEE ALSO --------- -- cdist-type(7) +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__install_chroot_mount/man.rst b/cdist/conf/type/__install_chroot_mount/man.rst new file mode 120000 index 00000000..3267c3db --- /dev/null +++ b/cdist/conf/type/__install_chroot_mount/man.rst @@ -0,0 +1 @@ +../__chroot_mount/man.rst \ No newline at end of file diff --git a/cdist/conf/type/__install_chroot_mount/man.text b/cdist/conf/type/__install_chroot_mount/man.text deleted file mode 120000 index e131fceb..00000000 --- a/cdist/conf/type/__install_chroot_mount/man.text +++ /dev/null @@ -1 +0,0 @@ -../__chroot_mount/man.text \ No newline at end of file diff --git a/cdist/conf/type/__install_chroot_umount/man.rst b/cdist/conf/type/__install_chroot_umount/man.rst new file mode 120000 index 00000000..fa34c4b0 --- /dev/null +++ b/cdist/conf/type/__install_chroot_umount/man.rst @@ -0,0 +1 @@ +../__chroot_umount/man.rst \ No newline at end of file diff --git a/cdist/conf/type/__install_chroot_umount/man.text b/cdist/conf/type/__install_chroot_umount/man.text deleted file mode 120000 index f615c734..00000000 --- a/cdist/conf/type/__install_chroot_umount/man.text +++ /dev/null @@ -1 +0,0 @@ -../__chroot_umount/man.text \ No newline at end of file diff --git a/cdist/conf/type/__install_config/man.text b/cdist/conf/type/__install_config/man.rst similarity index 60% rename from cdist/conf/type/__install_config/man.text rename to cdist/conf/type/__install_config/man.rst index def0439b..0034e85d 100644 --- a/cdist/conf/type/__install_config/man.text +++ b/cdist/conf/type/__install_config/man.rst @@ -1,7 +1,5 @@ cdist-type__install_config(7) ============================= -Steven Armstrong - NAME ---- @@ -17,31 +15,33 @@ cdist config against the /target chroot on the remote host. REQUIRED PARAMETERS ------------------- -None. +None OPTIONAL PARAMETERS ------------------- -chroot:: +chroot where to chroot before running grub-install. Defaults to /target. EXAMPLES -------- --------------------------------------------------------------------------------- -__install_config +.. code-block:: sh -__install_config --chroot /mnt/somewhere --------------------------------------------------------------------------------- + __install_config + + __install_config --chroot /mnt/somewhere -SEE ALSO --------- -- cdist-type(7) +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__install_file/man.rst b/cdist/conf/type/__install_file/man.rst new file mode 120000 index 00000000..c937b8af --- /dev/null +++ b/cdist/conf/type/__install_file/man.rst @@ -0,0 +1 @@ +../__file/man.rst \ No newline at end of file diff --git a/cdist/conf/type/__install_file/man.text b/cdist/conf/type/__install_file/man.text deleted file mode 120000 index ba483161..00000000 --- a/cdist/conf/type/__install_file/man.text +++ /dev/null @@ -1 +0,0 @@ -../__file/man.text \ No newline at end of file diff --git a/cdist/conf/type/__install_fstab/man.text b/cdist/conf/type/__install_fstab/man.rst similarity index 54% rename from cdist/conf/type/__install_fstab/man.text rename to cdist/conf/type/__install_fstab/man.rst index 7c509427..5562c139 100644 --- a/cdist/conf/type/__install_fstab/man.text +++ b/cdist/conf/type/__install_fstab/man.rst @@ -1,7 +1,5 @@ cdist-type__install_fstab(7) ============================ -Steven Armstrong - NAME ---- @@ -16,12 +14,12 @@ to the target machine at ${prefix}/etc/fstab. REQUIRED PARAMETERS ------------------- -None. +None OPTIONAL PARAMETERS ------------------- -prefix:: +prefix The prefix under which to generate the /etc/fstab file. Defaults to /target. @@ -29,20 +27,27 @@ prefix:: EXAMPLES -------- --------------------------------------------------------------------------------- -__install_fstab -__install_fstab --prefix /mnt/target --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_fstab + + __install_fstab --prefix /mnt/target SEE ALSO -------- -- cdist-type(7) -- cdist-type__install_mount(7) -- cdist-type__install_generate_fstab(7) +:strong:`cdist-type__install_generate_fstab`\ (7), +:strong:`cdist-type__install_mount`\ (7) + + +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__install_generate_fstab/man.text b/cdist/conf/type/__install_generate_fstab/man.rst similarity index 57% rename from cdist/conf/type/__install_generate_fstab/man.text rename to cdist/conf/type/__install_generate_fstab/man.rst index d229f4df..b38f8876 100644 --- a/cdist/conf/type/__install_generate_fstab/man.text +++ b/cdist/conf/type/__install_generate_fstab/man.rst @@ -1,7 +1,5 @@ cdist-type__install_generate_fstab(7) ===================================== -Steven Armstrong - NAME ---- @@ -16,37 +14,40 @@ __install_mount definitions. REQUIRED PARAMETERS ------------------- -destination:: +destination The path where to store the generated fstab file. Note that this is a path on the server, where cdist is running, not the target host. OPTIONAL PARAMETERS ------------------- -None. +None BOOLEAN PARAMETERS ------------------- -uuid:: +uuid use UUID instead of device in fstab EXAMPLES -------- --------------------------------------------------------------------------------- -__install_generate_fstab --destination /path/where/you/want/fstab -__install_generate_fstab --uuid --destination /path/where/you/want/fstab --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_generate_fstab --destination /path/where/you/want/fstab + + __install_generate_fstab --uuid --destination /path/where/you/want/fstab -SEE ALSO --------- -- cdist-type(7) +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__install_mkfs/man.rst b/cdist/conf/type/__install_mkfs/man.rst new file mode 100644 index 00000000..6e5c9aa9 --- /dev/null +++ b/cdist/conf/type/__install_mkfs/man.rst @@ -0,0 +1,62 @@ +cdist-type__install_mkfs(7) +=========================== + +NAME +---- +cdist-type__install_mkfs - build a linux file system + + +DESCRIPTION +----------- +This cdist type is a wrapper for the mkfs command. + + +REQUIRED PARAMETERS +------------------- +type + The filesystem type to use. Same as used with mkfs -t. + + +OPTIONAL PARAMETERS +------------------- +device + defaults to object_id + +options + file system-specific options to be passed to the mkfs command + +blocks + the number of blocks to be used for the file system + + +EXAMPLES +-------- + +.. code-block:: sh + + # reiserfs /dev/sda5 + __install_mkfs /dev/sda5 --type reiserfs + + # same thing with explicit device + __install_mkfs whatever --device /dev/sda5 --type reiserfs + + # jfs with journal on /dev/sda2 + __install_mkfs /dev/sda1 --type jfs --options "-j /dev/sda2" + + +SEE ALSO +-------- +:strong:`mkfs`\ (8) + + +AUTHORS +------- +Steven Armstrong + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. 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/__install_mkfs/man.text b/cdist/conf/type/__install_mkfs/man.text deleted file mode 100644 index 3a9a325d..00000000 --- a/cdist/conf/type/__install_mkfs/man.text +++ /dev/null @@ -1,57 +0,0 @@ -cdist-type__install_mkfs(7) -=========================== -Steven Armstrong - - -NAME ----- -cdist-type__install_mkfs - build a linux file system - - -DESCRIPTION ------------ -This cdist type is a wrapper for the mkfs command. - - -REQUIRED PARAMETERS -------------------- -type:: - The filesystem type to use. Same as used with mkfs -t. - - -OPTIONAL PARAMETERS -------------------- -device:: - defaults to object_id - -options:: - file system-specific options to be passed to the mkfs command - -blocks:: - the number of blocks to be used for the file system - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# reiserfs /dev/sda5 -__install_mkfs /dev/sda5 --type reiserfs -# same thing with explicit device -__install_mkfs whatever --device /dev/sda5 --type reiserfs - -# jfs with journal on /dev/sda2 -__install_mkfs /dev/sda1 --type jfs --options "-j /dev/sda2" --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) -- mkfs(8) - - -COPYING -------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_mount/man.text b/cdist/conf/type/__install_mount/man.rst similarity index 54% rename from cdist/conf/type/__install_mount/man.text rename to cdist/conf/type/__install_mount/man.rst index b55cb83e..256cef53 100644 --- a/cdist/conf/type/__install_mount/man.text +++ b/cdist/conf/type/__install_mount/man.rst @@ -1,7 +1,5 @@ cdist-type__install_mount(7) ============================ -Steven Armstrong - NAME ---- @@ -15,24 +13,24 @@ Mounts filesystems in the installer. Collects data to generate /etc/fstab. REQUIRED PARAMETERS ------------------- -device:: +device the device to mount OPTIONAL PARAMETERS ------------------- -dir:: +dir where to mount device. Defaults to object_id. -options:: +options mount options passed to mount(8) and used in /etc/fstab -type:: +type filesystem type passed to mount(8) and used in /etc/fstab. If type is swap, 'dir' is ignored. Defaults to the filesystem used in __install_mkfs for the same 'device'. -prefix:: +prefix the prefix to prepend to 'dir' when mounting in the installer. Defaults to /target. @@ -40,22 +38,28 @@ prefix:: EXAMPLES -------- --------------------------------------------------------------------------------- -__install_mount slash --dir / --device /dev/sda5 --options noatime -require="__install_mount/slash" __install_mount /boot --device /dev/sda1 -__install_mount swap --device /dev/sda2 --type swap -require="__install_mount/slash" __install_mount /tmp --device tmpfs --type tmpfs --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_mount slash --dir / --device /dev/sda5 --options noatime + require="__install_mount/slash" __install_mount /boot --device /dev/sda1 + __install_mount swap --device /dev/sda2 --type swap + require="__install_mount/slash" __install_mount /tmp --device tmpfs --type tmpfs SEE ALSO -------- -- cdist-type(7) -- cdist-type__install_mount_apply(7) -- cdist-type__install_mkfs(7) +:strong:`cdist-type__install_mkfs`\ (7), +:strong:`cdist-type__install_mount_apply` (7) + + +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__install_partition_msdos/man.rst b/cdist/conf/type/__install_partition_msdos/man.rst new file mode 100644 index 00000000..5ebb9218 --- /dev/null +++ b/cdist/conf/type/__install_partition_msdos/man.rst @@ -0,0 +1,64 @@ +cdist-type__install_partition_msdos(7) +====================================== + +NAME +---- +cdist-type__install_partition_msdos - creates msdos partitions + + +DESCRIPTION +----------- +This cdist type allows you to create msdos paritions. + + +REQUIRED PARAMETERS +------------------- +type + the partition type used in fdisk (such as 82 or 83) or "extended" + + +OPTIONAL PARAMETERS +------------------- +partition + defaults to object_id + +bootable + mark partition as bootable, true or false, defaults to false + +size + the size of the partition (such as 32M or 15G, whole numbers + only), '+' for remaining space, or 'n%' for percentage of remaining + (these should only be used after all specific partition sizes are + specified). Defaults to +. + + +EXAMPLES +-------- + +.. code-block:: sh + + # 128MB, linux, bootable + __install_partition_msdos /dev/sda1 --type 83 --size 128M --bootable true + # 512MB, swap + __install_partition_msdos /dev/sda2 --type 82 --size 512M + # 100GB, extended + __install_partition_msdos /dev/sda3 --type extended --size 100G + # 10GB, linux + __install_partition_msdos /dev/sda5 --type 83 --size 10G + # 50% of the free space of the extended partition, linux + __install_partition_msdos /dev/sda6 --type 83 --size 50% + # rest of the extended partition, linux + __install_partition_msdos /dev/sda7 --type 83 --size + + + +AUTHORS +------- +Steven Armstrong + + +COPYING +------- +Copyright \(C) 2011 Steven Armstrong. 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/__install_partition_msdos/man.text b/cdist/conf/type/__install_partition_msdos/man.text deleted file mode 100644 index 82d81ac5..00000000 --- a/cdist/conf/type/__install_partition_msdos/man.text +++ /dev/null @@ -1,62 +0,0 @@ -cdist-type__install_partition_msdos(7) -====================================== -Steven Armstrong - - -NAME ----- -cdist-type__install_partition_msdos - creates msdos partitions - - -DESCRIPTION ------------ -This cdist type allows you to create msdos paritions. - - -REQUIRED PARAMETERS -------------------- -type:: - the partition type used in fdisk (such as 82 or 83) or "extended" - - -OPTIONAL PARAMETERS -------------------- -partition:: - defaults to object_id -bootable:: - mark partition as bootable, true or false, defaults to false -size:: - the size of the partition (such as 32M or 15G, whole numbers - only), '+' for remaining space, or 'n%' for percentage of remaining - (these should only be used after all specific partition sizes are - specified). Defaults to +. - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -# 128MB, linux, bootable -__install_partition_msdos /dev/sda1 --type 83 --size 128M --bootable true -# 512MB, swap -__install_partition_msdos /dev/sda2 --type 82 --size 512M -# 100GB, extended -__install_partition_msdos /dev/sda3 --type extended --size 100G -# 10GB, linux -__install_partition_msdos /dev/sda5 --type 83 --size 10G -# 50% of the free space of the extended partition, linux -__install_partition_msdos /dev/sda6 --type 83 --size 50% -# rest of the extended partition, linux -__install_partition_msdos /dev/sda7 --type 83 --size + --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_partition_msdos_apply/man.text b/cdist/conf/type/__install_partition_msdos_apply/man.rst similarity index 52% rename from cdist/conf/type/__install_partition_msdos_apply/man.text rename to cdist/conf/type/__install_partition_msdos_apply/man.rst index 5399afb7..80740fde 100644 --- a/cdist/conf/type/__install_partition_msdos_apply/man.text +++ b/cdist/conf/type/__install_partition_msdos_apply/man.rst @@ -1,7 +1,5 @@ cdist-type__install_partition_msdos_apply(7) ============================================ -Steven Armstrong - NAME ---- @@ -20,23 +18,30 @@ None OPTIONAL PARAMETERS ------------------- -None. +None EXAMPLES -------- --------------------------------------------------------------------------------- -__install_partition_msdos_apply --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_partition_msdos_apply SEE ALSO -------- -- cdist-type(7) -- cdist-type__install_partition_msdos_apply(7) +:strong:`cdist-type__install_partition_msdos_apply`\ (7) + + +AUTHORS +------- +Steven Armstrong + COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__install_reboot/man.text b/cdist/conf/type/__install_reboot/man.rst similarity index 52% rename from cdist/conf/type/__install_reboot/man.text rename to cdist/conf/type/__install_reboot/man.rst index 91aec19a..ecf78ca7 100644 --- a/cdist/conf/type/__install_reboot/man.text +++ b/cdist/conf/type/__install_reboot/man.rst @@ -1,7 +1,5 @@ cdist-type__install_reboot(7) ============================= -Steven Armstrong - NAME ---- @@ -15,29 +13,31 @@ This cdist type allows you to reboot a machine. REQUIRED PARAMETERS ------------------- -None. +None OPTIONAL PARAMETERS ------------------- -options:: +options options to pass to the reboot command. e.g. -f EXAMPLES -------- --------------------------------------------------------------------------------- -__install_reboot --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_reboot -SEE ALSO --------- -- cdist-type(7) +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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/__install_reset_disk/man.text b/cdist/conf/type/__install_reset_disk/man.rst similarity index 50% rename from cdist/conf/type/__install_reset_disk/man.text rename to cdist/conf/type/__install_reset_disk/man.rst index 542d68ba..fadeec71 100644 --- a/cdist/conf/type/__install_reset_disk/man.text +++ b/cdist/conf/type/__install_reset_disk/man.rst @@ -1,7 +1,5 @@ cdist-type__install_reset_disk(7) ================================= -Steven Armstrong - NAME ---- @@ -17,27 +15,29 @@ Remove mdadm superblock. REQUIRED PARAMETERS ------------------- -None. +None OPTIONAL PARAMETERS ------------------- -None. +None EXAMPLES -------- --------------------------------------------------------------------------------- -__install_reset_disk /dev/sdb --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_reset_disk /dev/sdb -SEE ALSO --------- -- cdist-type(7) +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2012 Steven Armstrong. 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/__install_stage/man.rst b/cdist/conf/type/__install_stage/man.rst new file mode 100644 index 00000000..6c68c543 --- /dev/null +++ b/cdist/conf/type/__install_stage/man.rst @@ -0,0 +1,58 @@ +cdist-type__install_stage(7) +============================ + +NAME +---- +cdist-type__install_stage - download and unpack a stage file + + +DESCRIPTION +----------- +Downloads a operating system stage using curl and unpacks it to /target +using tar. The stage tarball is expected to be gzip compressed. + + +REQUIRED PARAMETERS +------------------- +uri + The uri from which to fetch the tarball. + Can be anything understood by curl, e.g: + | http://path/to/stage.tgz + | tftp:///path/to/stage.tgz + | file:///local/path/stage.tgz + + +OPTIONAL PARAMETERS +------------------- +target + where to unpack the tarball to. Defaults to /target. + + +BOOLEAN PARAMETERS +------------------ +insecure + run curl in insecure mode so it does not check the servers ssl certificate + + +EXAMPLES +-------- + +.. code-block:: sh + + __install_stage --uri tftp:///path/to/stage.tgz + __install_stage --uri http://path/to/stage.tgz --target /mnt/foobar + __install_stage --uri file:///path/to/stage.tgz --target /target + __install_stage --uri https://path/to/stage.tgz --target /mnt/foobar --insecure + + +AUTHORS +------- +Steven Armstrong + + +COPYING +------- +Copyright \(C) 2011 - 2013 Steven Armstrong. 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/__install_stage/man.text b/cdist/conf/type/__install_stage/man.text deleted file mode 100644 index 289c8621..00000000 --- a/cdist/conf/type/__install_stage/man.text +++ /dev/null @@ -1,58 +0,0 @@ -cdist-type__install_stage(7) -============================ -Steven Armstrong - - -NAME ----- -cdist-type__install_stage - download and unpack a stage file - - -DESCRIPTION ------------ -Downloads a operating system stage using curl and unpacks it to /target -using tar. The stage tarball is expected to be gzip compressed. - - -REQUIRED PARAMETERS -------------------- -uri:: - The uri from which to fetch the tarball. - Can be anything understood by curl, e.g: - http://path/to/stage.tgz - tftp:///path/to/stage.tgz - file:///local/path/stage.tgz - - -OPTIONAL PARAMETERS -------------------- -target:: - where to unpack the tarball to. Defaults to /target. - - -BOOLEAN PARAMETERS ------------------- -insecure:: - run curl in insecure mode so it does not check the servers ssl certificate - - -EXAMPLES --------- - --------------------------------------------------------------------------------- -__install_stage --uri tftp:///path/to/stage.tgz -__install_stage --uri http://path/to/stage.tgz --target /mnt/foobar -__install_stage --uri file:///path/to/stage.tgz --target /target -__install_stage --uri https://path/to/stage.tgz --target /mnt/foobar --insecure --------------------------------------------------------------------------------- - - -SEE ALSO --------- -- cdist-type(7) - - -COPYING -------- -Copyright \(C) 2011 - 2013 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__install_umount/man.text b/cdist/conf/type/__install_umount/man.rst similarity index 54% rename from cdist/conf/type/__install_umount/man.text rename to cdist/conf/type/__install_umount/man.rst index 8d9d1f55..59f63449 100644 --- a/cdist/conf/type/__install_umount/man.text +++ b/cdist/conf/type/__install_umount/man.rst @@ -1,7 +1,5 @@ cdist-type__install_umount(7) ============================= -Steven Armstrong - NAME ---- @@ -15,29 +13,31 @@ This cdist type allows you to recursively umount the given target directory. REQUIRED PARAMETERS ------------------- -None. +None OPTIONAL PARAMETERS ------------------- -target:: +target the mount point to umount. Defaults to object_id EXAMPLES -------- --------------------------------------------------------------------------------- -__install_umount /target --------------------------------------------------------------------------------- +.. code-block:: sh + + __install_umount /target -SEE ALSO --------- -- cdist-type(7) +AUTHORS +------- +Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2011 Steven Armstrong. 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. From 93c80c9f4d7336fe8f79420ca7bd8cc117933557 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 15 Oct 2016 19:04:14 +0200 Subject: [PATCH 0336/1332] Remove outdated __cdist_preos. --- cdist/conf/type/__cdist_preos/man.rst | 48 ----------- cdist/conf/type/__cdist_preos/manifest | 79 ------------------- .../__cdist_preos/parameter/default/branch | 1 - .../__cdist_preos/parameter/default/source | 1 - .../__cdist_preos/parameter/default/username | 1 - .../type/__cdist_preos/parameter/optional | 4 - 6 files changed, 134 deletions(-) delete mode 100644 cdist/conf/type/__cdist_preos/man.rst delete mode 100755 cdist/conf/type/__cdist_preos/manifest delete mode 100644 cdist/conf/type/__cdist_preos/parameter/default/branch delete mode 100644 cdist/conf/type/__cdist_preos/parameter/default/source delete mode 100644 cdist/conf/type/__cdist_preos/parameter/default/username delete mode 100644 cdist/conf/type/__cdist_preos/parameter/optional diff --git a/cdist/conf/type/__cdist_preos/man.rst b/cdist/conf/type/__cdist_preos/man.rst deleted file mode 100644 index 8b7d22d6..00000000 --- a/cdist/conf/type/__cdist_preos/man.rst +++ /dev/null @@ -1,48 +0,0 @@ -cdist-type__cdist_preos(7) -========================== - -NAME ----- -cdist-type__cdist - Manage cdist installations - - -DESCRIPTION ------------ -This cdist type creates a directory containing an operating -suitable for installation using cdist. - - -REQUIRED PARAMETERS -------------------- -None - - -OPTIONAL PARAMETERS -------------------- -None - - -EXAMPLES --------- - -.. code-block:: sh - - __cdist_preos /tmp/random_name_for_packaging - - -SEE ALSO --------- -:strong:`cdist-type__cdist`\ (7) - - -AUTHORS -------- -Nico Schottelius - - -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. diff --git a/cdist/conf/type/__cdist_preos/manifest b/cdist/conf/type/__cdist_preos/manifest deleted file mode 100755 index 78166b38..00000000 --- a/cdist/conf/type/__cdist_preos/manifest +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -# -# 2015 Nico Schottelius (nico-cdist at schottelius.org) -# -# 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 . -# -# - -destination="/$__object_id" - -os=$(cat "$__global/explorer/os") - -case "$os" in - archlinux) - kernel=/boot/vmlinuz-linux - initramfs=/boot/initramfs-linux-fallback.img - required_pkg="cdrkit syslinux" - ;; - *) - echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 - echo "Please contribute an implementation for it if you can." >&2 - exit 1 - ;; -esac - -# Our root -__directory "$destination" \ - --mode 0755 - -for rootdir in boot bin etc lib; do - require="__directory/$destination" __directory "$destination/$rootdir" \ - --mode 0755 -done - -require="__directory/$destination/etc" __cdistmarker \ - --destination "$destination/etc/cdist-configured" - -for pkg in $required_pkg; do - __package "$pkg" --state present -done - -# Create full dependency chain, because we don't know which file depends on which package -export CDIST_ORDER_DEPENDENCY=1 - -require="__directory/$destination/boot" __file "$destination/boot/linux" \ - --source "$kernel" --mode 0644 - -require="__directory/$destination/boot" __file "$destination/boot/initramfs" \ - --source "$initramfs" --mode 0644 - -require="__directory/$destination/boot" __file "$destination/boot/syslinux.cfg" \ - - - PROMPT 1 - TIMEOUT 50 - DEFAULT arch - - LABEL arch - LINUX ../vmlinuz-linux - APPEND root=/dev/sda2 rw - INITRD ../initramfs-linux.img - - LABEL archfallback - LINUX ../vmlinuz-linux - APPEND root=/dev/sda2 rw - INITRD ../initramfs-linux-fallback.img diff --git a/cdist/conf/type/__cdist_preos/parameter/default/branch b/cdist/conf/type/__cdist_preos/parameter/default/branch deleted file mode 100644 index 1f7391f9..00000000 --- a/cdist/conf/type/__cdist_preos/parameter/default/branch +++ /dev/null @@ -1 +0,0 @@ -master diff --git a/cdist/conf/type/__cdist_preos/parameter/default/source b/cdist/conf/type/__cdist_preos/parameter/default/source deleted file mode 100644 index d669308f..00000000 --- a/cdist/conf/type/__cdist_preos/parameter/default/source +++ /dev/null @@ -1 +0,0 @@ -git://github.com/telmich/cdist.git diff --git a/cdist/conf/type/__cdist_preos/parameter/default/username b/cdist/conf/type/__cdist_preos/parameter/default/username deleted file mode 100644 index a585e141..00000000 --- a/cdist/conf/type/__cdist_preos/parameter/default/username +++ /dev/null @@ -1 +0,0 @@ -cdist diff --git a/cdist/conf/type/__cdist_preos/parameter/optional b/cdist/conf/type/__cdist_preos/parameter/optional deleted file mode 100644 index a5f14343..00000000 --- a/cdist/conf/type/__cdist_preos/parameter/optional +++ /dev/null @@ -1,4 +0,0 @@ -branch -source -username -shell From 75e85379f6f2c6490172c859574569d0fd1fce83 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 27 Oct 2016 18:34:24 +0200 Subject: [PATCH 0337/1332] Order subcommands alphabetically. --- scripts/cdist | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 9f8d326d..68084ca4 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -159,6 +159,11 @@ def commandline(): default=os.environ.get('CDIST_REMOTE_EXEC')) parser['config'].set_defaults(func=cdist.config.Config.commandline) + # Install + parser['install'] = parser['sub'].add_parser('install', add_help=False, + parents=[parser['config']]) + parser['install'].set_defaults(func=cdist.install.Install.commandline) + # Shell parser['shell'] = parser['sub'].add_parser( 'shell', parents=[parser['loglevel']]) @@ -168,11 +173,6 @@ def commandline(): ' should be POSIX compatible shell.')) parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) - # Install - parser['install'] = parser['sub'].add_parser('install', add_help=False, - parents=[parser['config']]) - parser['install'].set_defaults(func=cdist.install.Install.commandline) - for p in parser: parser[p].epilog = ( "Get cdist at http://www.nico.schottelius.org/software/cdist/") From c293a9b2cea5c59a3098d49c3df7e4d2c71a3956 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 1 Nov 2016 08:11:37 +0100 Subject: [PATCH 0338/1332] Add missing param. --- cdist/install.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/install.py b/cdist/install.py index bec8d24a..b88ad016 100644 --- a/cdist/install.py +++ b/cdist/install.py @@ -30,7 +30,8 @@ class Install(cdist.config.Config): In install mode, we only care about install objects. """ for cdist_object in cdist.core.CdistObject.list_objects( - self.local.object_path, self.local.type_path): + self.local.object_path, self.local.type_path, + self.local.object_marker_name): if cdist_object.cdist_type.is_install: yield cdist_object else: From ca9dd7338adfd371705f27793d8bd20e99762d8d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 2 Nov 2016 13:35:48 +0100 Subject: [PATCH 0339/1332] Support IPv6 in python code. --- cdist/exec/remote.py | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 9c70bdf4..f374262f 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -32,6 +32,43 @@ import cdist import cdist.exec.util as exec_util +# check whether addr is IPv6 +try: + # python 3.3+ + import ipaddress + + def _is_ipv6(addr): + try: + return ipaddress.ip_address(addr).version == 6 + except ValueError: + return False +except ImportError: + # fallback for older python versions + import socket + + def _is_ipv6(addr): + try: + socket.inet_aton(addr) + return False + except socket.error: + pass + try: + socket.inet_pton(socket.AF_INET6, addr) + return True + except socket.error: + pass + return False + + +def _wrap_addr(addr): + """If addr is IPv6 then return addr wrapped between '[' and ']', + otherwise return it intact.""" + if _is_ipv6(addr): + return "".join(("[", addr, "]", )) + else: + return addr + + class DecodeError(cdist.Error): def __init__(self, command): self.command = command @@ -118,12 +155,12 @@ class Remote(object): command = self._copy.split() path = os.path.join(source, f) command.extend([path, '{0}:{1}'.format( - self.target_host[0], destination)]) + _wrap_addr(self.target_host[0]), destination)]) self._run_command(command) else: command = self._copy.split() command.extend([source, '{0}:{1}'.format( - self.target_host[0], destination)]) + _wrap_addr(self.target_host[0]), destination)]) self._run_command(command) def transfer_dir_parallel(self, source, destination, jobs): @@ -145,7 +182,7 @@ class Remote(object): command = self._copy.split() path = os.path.join(source, f) command.extend([path, '{0}:{1}'.format( - self.target_host[0], destination)]) + _wrap_addr(self.target_host[0]), destination)]) commands.append(command) results = [ pool.apply_async(self._run_command, (cmd,)) From 4ddf6557e3d9b269650c35ee7e11040b4e747932 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 2 Nov 2016 13:55:25 +0100 Subject: [PATCH 0340/1332] IPv6 fix in gencode scripts. --- cdist/conf/type/__file/gencode-local | 11 ++++++++++- cdist/conf/type/__jail_freebsd10/gencode-local | 11 ++++++++++- cdist/conf/type/__jail_freebsd9/gencode-local | 11 ++++++++++- cdist/conf/type/__pf_ruleset/gencode-local | 14 ++++++++++++-- 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index ed7482cb..674650b7 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -66,8 +66,17 @@ destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template" DONE if [ "$upload_file" ]; then echo upload >> "$__messages_out" + # IPv6 fix + case "${__target_host}" in + *:*) + my_target_host="[${__target_host}]" + ;; + *) + my_target_host="${__target_host}" + ;; + esac cat << DONE -$__remote_copy "$source" "${__target_host}:\$destination_upload" +$__remote_copy "$source" "${my_target_host}:\$destination_upload" DONE fi # move uploaded file into place diff --git a/cdist/conf/type/__jail_freebsd10/gencode-local b/cdist/conf/type/__jail_freebsd10/gencode-local index d4b89730..766692a2 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-local +++ b/cdist/conf/type/__jail_freebsd10/gencode-local @@ -43,7 +43,16 @@ basepresent="$(cat "$__object/explorer/basepresent")" if [ "$state" = "present" ]; then if [ "$basepresent" = "NONE" ]; then - echo "$__remote_copy" "${jailbase}" "$__target_host:${remotebase}" + # IPv6 fix + case "${__target_host}" in + *:*) + my_target_host="[${__target_host}]" + ;; + *) + my_target_host="${__target_host}" + ;; + esac + echo "$__remote_copy" "${jailbase}" "${my_target_host}:${remotebase}" fi # basepresent=NONE fi # state=present diff --git a/cdist/conf/type/__jail_freebsd9/gencode-local b/cdist/conf/type/__jail_freebsd9/gencode-local index 08c7b7bf..35b6f789 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-local +++ b/cdist/conf/type/__jail_freebsd9/gencode-local @@ -39,7 +39,16 @@ basepresent="$(cat "$__object/explorer/basepresent")" if [ "$state" = "present" ]; then if [ "$basepresent" = "NONE" ]; then - echo "$__remote_copy" "${jailbase}" "$__target_host:${remotebase}" + # IPv6 fix + case "${__target_host}" in + *:*) + my_target_host="[${__target_host}]" + ;; + *) + my_target_host="${__target_host}" + ;; + esac + echo "$__remote_copy" "${jailbase}" "${my_target_host}:${remotebase}" fi # basepresent=NONE fi # state=present diff --git a/cdist/conf/type/__pf_ruleset/gencode-local b/cdist/conf/type/__pf_ruleset/gencode-local index c2495509..307c89ec 100644 --- a/cdist/conf/type/__pf_ruleset/gencode-local +++ b/cdist/conf/type/__pf_ruleset/gencode-local @@ -59,12 +59,22 @@ case $uname in ;; esac +# IPv6 fix +case "${__target_host}" in + *:*) + my_target_host="[${__target_host}]" + ;; + *) + my_target_host="${__target_host}" + ;; +esac + if [ -n "${cksum}" ]; then if [ ! "\${currentSum}" = "${cksum}" ]; then - $__remote_copy "${source}" "$__target_host:${rcvar}.new" + $__remote_copy "${source}" "${my_target_host}:${rcvar}.new" fi else # File just doesn't exist yet - $__remote_copy "${source}" "$__target_host:${rcvar}.new" + $__remote_copy "${source}" "${my_target_host}:${rcvar}.new" fi EOF From 9268062de5eab5c01fdb69acdba92d99228b807f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 3 Nov 2016 13:26:50 +0100 Subject: [PATCH 0341/1332] Fix target_host vars in Code. --- cdist/config.py | 1 + cdist/core/code.py | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index b0131601..b8d0672c 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -285,6 +285,7 @@ class Config(object): host_fqdn = '' target_host = (host, host_name, host_fqdn) + log.debug("target_host: {}".format(target_host)) local = cdist.exec.local.Local( target_host=target_host, diff --git a/cdist/core/code.py b/cdist/core/code.py index cfc1316a..e9e2edf0 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -100,9 +100,7 @@ class Code(object): """ # target_host is tuple (target_host, target_hostname, target_fqdn) def __init__(self, target_host, local, remote): - self.target_host = target_host[0] - self.target_hostname = target_host[1] - self.target_fqdn = target_host[2] + self.target_host = target_host self.local = local self.remote = remote self.env = { From 39c3ac43ec7c278d72e573495ab6b9fbffc33883 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 4 Nov 2016 09:53:00 +0200 Subject: [PATCH 0342/1332] __package_upgrade_all shouldn't dist-upgrade by default. also add clean. --- .../type/__package_upgrade_all/gencode-remote | 15 +++++++++++++-- .../type/__package_upgrade_all/parameter/boolean | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 cdist/conf/type/__package_upgrade_all/parameter/boolean diff --git a/cdist/conf/type/__package_upgrade_all/gencode-remote b/cdist/conf/type/__package_upgrade_all/gencode-remote index 9dd3ddf6..3e25f45f 100755 --- a/cdist/conf/type/__package_upgrade_all/gencode-remote +++ b/cdist/conf/type/__package_upgrade_all/gencode-remote @@ -24,6 +24,10 @@ type="$__object/parameter/type" +apt_clean="$__object/parameter/apt-clean" + +apt_dist_upgrade="$__object/parameter/apt-dist-upgrade" + if [ -f "$type" ]; then type="$(cat "$type")" else @@ -48,8 +52,15 @@ case "$type" in echo "yum --quiet clean all" ;; apt) - echo $aptget dist-upgrade - echo "apt-get --quiet autoclean" + if [ -f "$apt_dist_upgrade" ] + then echo $aptget dist-upgrade + else echo $aptget upgrade + fi + + if [ -f "$apt_clean" ] + then echo "apt-get --quiet clean" + else echo "apt-get --quiet autoclean" + fi ;; pacman) echo "pacman --noprogressbar --noconfirm --sync --sysupgrade" diff --git a/cdist/conf/type/__package_upgrade_all/parameter/boolean b/cdist/conf/type/__package_upgrade_all/parameter/boolean new file mode 100644 index 00000000..7a56a34b --- /dev/null +++ b/cdist/conf/type/__package_upgrade_all/parameter/boolean @@ -0,0 +1,2 @@ +apt-clean +apt-dist-upgrade From 4ef057c65dfb696342d1ca47ee07bd820d2057b9 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 4 Nov 2016 10:14:42 +0200 Subject: [PATCH 0343/1332] add docs --- cdist/conf/type/__package_upgrade_all/man.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cdist/conf/type/__package_upgrade_all/man.rst b/cdist/conf/type/__package_upgrade_all/man.rst index 62cbc43d..e9e2b8ce 100644 --- a/cdist/conf/type/__package_upgrade_all/man.rst +++ b/cdist/conf/type/__package_upgrade_all/man.rst @@ -28,6 +28,15 @@ type * pacman for Arch Linux +BOOLEAN PARAMETERS +------------------ +apt-dist-upgrade + Do dist-upgrade instead of upgrade. + +apt-clean + Clean out the local repository of retrieved package files. + + EXAMPLES -------- From 6ce6c7830bcc0e360349d071b00f2aecbf099dd2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 5 Nov 2016 16:38:49 +0100 Subject: [PATCH 0344/1332] Better test for IPv6 address. --- cdist/conf/type/__file/gencode-local | 15 +++++++-------- cdist/conf/type/__jail_freebsd10/gencode-local | 15 +++++++-------- cdist/conf/type/__jail_freebsd9/gencode-local | 15 +++++++-------- cdist/conf/type/__pf_ruleset/gencode-local | 15 +++++++-------- 4 files changed, 28 insertions(+), 32 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 674650b7..c9e0fa2c 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -67,14 +67,13 @@ DONE if [ "$upload_file" ]; then echo upload >> "$__messages_out" # IPv6 fix - case "${__target_host}" in - *:*) - my_target_host="[${__target_host}]" - ;; - *) - my_target_host="${__target_host}" - ;; - esac + echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' + if [ $? -eq 0 ] + then + my_target_host="[${__target_host}]" + else + my_target_host="${__target_host}" + fi cat << DONE $__remote_copy "$source" "${my_target_host}:\$destination_upload" DONE diff --git a/cdist/conf/type/__jail_freebsd10/gencode-local b/cdist/conf/type/__jail_freebsd10/gencode-local index 766692a2..bdd0ffd7 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-local +++ b/cdist/conf/type/__jail_freebsd10/gencode-local @@ -44,14 +44,13 @@ basepresent="$(cat "$__object/explorer/basepresent")" if [ "$state" = "present" ]; then if [ "$basepresent" = "NONE" ]; then # IPv6 fix - case "${__target_host}" in - *:*) - my_target_host="[${__target_host}]" - ;; - *) - my_target_host="${__target_host}" - ;; - esac + echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' + if [ $? -eq 0 ] + then + my_target_host="[${__target_host}]" + else + my_target_host="${__target_host}" + fi echo "$__remote_copy" "${jailbase}" "${my_target_host}:${remotebase}" fi # basepresent=NONE fi # state=present diff --git a/cdist/conf/type/__jail_freebsd9/gencode-local b/cdist/conf/type/__jail_freebsd9/gencode-local index 35b6f789..ce9b215e 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-local +++ b/cdist/conf/type/__jail_freebsd9/gencode-local @@ -40,14 +40,13 @@ basepresent="$(cat "$__object/explorer/basepresent")" if [ "$state" = "present" ]; then if [ "$basepresent" = "NONE" ]; then # IPv6 fix - case "${__target_host}" in - *:*) - my_target_host="[${__target_host}]" - ;; - *) - my_target_host="${__target_host}" - ;; - esac + echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' + if [ $? -eq 0 ] + then + my_target_host="[${__target_host}]" + else + my_target_host="${__target_host}" + fi echo "$__remote_copy" "${jailbase}" "${my_target_host}:${remotebase}" fi # basepresent=NONE fi # state=present diff --git a/cdist/conf/type/__pf_ruleset/gencode-local b/cdist/conf/type/__pf_ruleset/gencode-local index 307c89ec..d14a6045 100644 --- a/cdist/conf/type/__pf_ruleset/gencode-local +++ b/cdist/conf/type/__pf_ruleset/gencode-local @@ -60,14 +60,13 @@ case $uname in esac # IPv6 fix -case "${__target_host}" in - *:*) - my_target_host="[${__target_host}]" - ;; - *) - my_target_host="${__target_host}" - ;; -esac +echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' +if [ $? -eq 0 ] +then + my_target_host="[${__target_host}]" +else + my_target_host="${__target_host}" +fi if [ -n "${cksum}" ]; then if [ ! "\${currentSum}" = "${cksum}" ]; then From 28f2672c2d667918fe284996fe30823362d7ba43 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 6 Nov 2016 11:27:24 +0100 Subject: [PATCH 0345/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 9519f2b3..721bad6a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Type __package_upgrade_all: do not dist-upgrade by default, add apt-clean and apt-dist-upgrade options (Ander Punnar) * All: Merge install feature from 4.0-pre-not-stable (Darko Poljak) 4.3.2: 2016-10-13 From 6fd9dac14511954ffa946d117ef2d6dbbf4985f5 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Mon, 7 Nov 2016 11:19:48 +0200 Subject: [PATCH 0346/1332] add __apt_mark --- cdist/conf/type/__apt_mark/gencode-remote | 37 +++++++++++++++ cdist/conf/type/__apt_mark/man.rst | 47 +++++++++++++++++++ cdist/conf/type/__apt_mark/parameter/optional | 1 + cdist/conf/type/__apt_mark/parameter/required | 1 + 4 files changed, 86 insertions(+) create mode 100644 cdist/conf/type/__apt_mark/gencode-remote create mode 100644 cdist/conf/type/__apt_mark/man.rst create mode 100644 cdist/conf/type/__apt_mark/parameter/optional create mode 100644 cdist/conf/type/__apt_mark/parameter/required diff --git a/cdist/conf/type/__apt_mark/gencode-remote b/cdist/conf/type/__apt_mark/gencode-remote new file mode 100644 index 00000000..76e87660 --- /dev/null +++ b/cdist/conf/type/__apt_mark/gencode-remote @@ -0,0 +1,37 @@ +#!/bin/sh +# +# 2016 Ander Punnar (cdist at kvlt.ee) +# +# 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/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +state="$(cat "$__object/parameter/state")" + +case "$state" in + auto|manual|hold|unhold) + echo "apt-mark $state $name" + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__apt_mark/man.rst b/cdist/conf/type/__apt_mark/man.rst new file mode 100644 index 00000000..8daed6e3 --- /dev/null +++ b/cdist/conf/type/__apt_mark/man.rst @@ -0,0 +1,47 @@ +cdist-type__apt_mark(7) +====================== + +NAME +---- +cdist-type__apt_mark - set package state as 'auto', 'manual', 'hold' or 'unhold' + + +DESCRIPTION +----------- +See apt-mark(8) for details. + + +REQUIRED PARAMETERS +------------------- +state + Possible states are 'auto', 'manual', 'hold' and 'unhold'. + + +OPTIONAL PARAMETERS +------------------- +name + If supplied, use the name and not the object id as the package name. + + +EXAMPLES +-------- + +.. code-block:: sh + + # hold package + __apt_mark quagga --state hold + # unhold package + __apt_mark quagga --state unhold + + +AUTHORS +------- +Ander Punnar + + +COPYING +------- +Copyright \(C) 2016 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/__apt_mark/parameter/optional b/cdist/conf/type/__apt_mark/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/cdist/conf/type/__apt_mark/parameter/optional @@ -0,0 +1 @@ +name diff --git a/cdist/conf/type/__apt_mark/parameter/required b/cdist/conf/type/__apt_mark/parameter/required new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__apt_mark/parameter/required @@ -0,0 +1 @@ +state From 6f69cd6a1178d225faa5bbfe80e4e2322e74022f Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Mon, 7 Nov 2016 13:36:27 +0200 Subject: [PATCH 0347/1332] fix man --- cdist/conf/type/__apt_mark/man.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_mark/man.rst b/cdist/conf/type/__apt_mark/man.rst index 8daed6e3..35ab2677 100644 --- a/cdist/conf/type/__apt_mark/man.rst +++ b/cdist/conf/type/__apt_mark/man.rst @@ -1,5 +1,5 @@ cdist-type__apt_mark(7) -====================== +======================= NAME ---- From 45e45016a7062c632e126ca74aef86e8526f24d7 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Mon, 7 Nov 2016 15:45:54 +0200 Subject: [PATCH 0348/1332] retrieve the mark before with an explorer --- cdist/conf/type/__apt_mark/explorer/state | 27 +++++++++++++++++++++++ cdist/conf/type/__apt_mark/gencode-remote | 14 ++++++++---- 2 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 cdist/conf/type/__apt_mark/explorer/state diff --git a/cdist/conf/type/__apt_mark/explorer/state b/cdist/conf/type/__apt_mark/explorer/state new file mode 100644 index 00000000..3b70003a --- /dev/null +++ b/cdist/conf/type/__apt_mark/explorer/state @@ -0,0 +1,27 @@ +#!/bin/sh +# +# 2016 Ander Punnar (cdist at kvlt.ee) +# +# 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/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +apt-mark showhold | grep -q $name && echo hold || echo unhold diff --git a/cdist/conf/type/__apt_mark/gencode-remote b/cdist/conf/type/__apt_mark/gencode-remote index 76e87660..d83e96d9 100644 --- a/cdist/conf/type/__apt_mark/gencode-remote +++ b/cdist/conf/type/__apt_mark/gencode-remote @@ -24,14 +24,20 @@ else name="$__object_id" fi -state="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" -case "$state" in +state_is="$(cat "$__object/explorer/state")" + +if [ "$state_should" = "$state_is" ]; then + exit 0 +fi + +case "$state_should" in auto|manual|hold|unhold) - echo "apt-mark $state $name" + echo "apt-mark $state_should $name" ;; *) - echo "Unknown state: $state" >&2 + echo "Unknown state: $state_should" >&2 exit 1 ;; esac From b3cf70ae4297af854ef3d7561d85357cdb048cf8 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Mon, 7 Nov 2016 15:51:50 +0200 Subject: [PATCH 0349/1332] remove auto and manual states --- cdist/conf/type/__apt_mark/gencode-remote | 2 +- cdist/conf/type/__apt_mark/man.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__apt_mark/gencode-remote b/cdist/conf/type/__apt_mark/gencode-remote index d83e96d9..d97e2c7a 100644 --- a/cdist/conf/type/__apt_mark/gencode-remote +++ b/cdist/conf/type/__apt_mark/gencode-remote @@ -33,7 +33,7 @@ if [ "$state_should" = "$state_is" ]; then fi case "$state_should" in - auto|manual|hold|unhold) + hold|unhold) echo "apt-mark $state_should $name" ;; *) diff --git a/cdist/conf/type/__apt_mark/man.rst b/cdist/conf/type/__apt_mark/man.rst index 35ab2677..7aa2a519 100644 --- a/cdist/conf/type/__apt_mark/man.rst +++ b/cdist/conf/type/__apt_mark/man.rst @@ -3,7 +3,7 @@ cdist-type__apt_mark(7) NAME ---- -cdist-type__apt_mark - set package state as 'auto', 'manual', 'hold' or 'unhold' +cdist-type__apt_mark - set package state as 'hold' or 'unhold' DESCRIPTION @@ -14,7 +14,7 @@ See apt-mark(8) for details. REQUIRED PARAMETERS ------------------- state - Possible states are 'auto', 'manual', 'hold' and 'unhold'. + Either "hold" or "unhold". OPTIONAL PARAMETERS From 35975582f09b2a22e18e2ae71071b80c7d2fc40c Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Mon, 7 Nov 2016 16:55:51 +0200 Subject: [PATCH 0350/1332] suppress output --- cdist/conf/type/__apt_mark/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_mark/gencode-remote b/cdist/conf/type/__apt_mark/gencode-remote index d97e2c7a..14505809 100644 --- a/cdist/conf/type/__apt_mark/gencode-remote +++ b/cdist/conf/type/__apt_mark/gencode-remote @@ -34,7 +34,7 @@ fi case "$state_should" in hold|unhold) - echo "apt-mark $state_should $name" + echo "apt-mark $state_should $name > /dev/null" ;; *) echo "Unknown state: $state_should" >&2 From c4996396c689d5d53a46ec7230fbb31cd97dbac9 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Tue, 22 Nov 2016 18:21:03 +0100 Subject: [PATCH 0351/1332] __user type: fix for FreeBSD --- cdist/conf/type/__user/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index 463fbe49..223d4d46 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -104,7 +104,7 @@ if [ "$state" = "present" ]; then if [ $# -gt 0 ]; then echo mod >> "$__messages_out" if [ "$os" = "freebsd" ]; then - echo pw usermod "$@" "$name" + echo pw usermod "$@" -n "$name" else echo usermod "$@" "$name" fi @@ -125,7 +125,7 @@ if [ "$state" = "present" ]; then done if [ "$os" = "freebsd" ]; then - echo pw useradd "$@" "$name" + echo pw useradd "$@" -n "$name" else echo useradd "$@" "$name" fi From 6bc250399671ff51b3c111b4f2cb5ae57e0683da Mon Sep 17 00:00:00 2001 From: Carlos Ortigoza Dempster Date: Fri, 25 Nov 2016 14:15:00 -0400 Subject: [PATCH 0352/1332] Adding consul 0.7.0 files --- cdist/conf/type/__consul/files/versions/0.7.0/cksum | 1 + cdist/conf/type/__consul/files/versions/0.7.0/source | 1 + 2 files changed, 2 insertions(+) create mode 100644 cdist/conf/type/__consul/files/versions/0.7.0/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.7.0/source diff --git a/cdist/conf/type/__consul/files/versions/0.7.0/cksum b/cdist/conf/type/__consul/files/versions/0.7.0/cksum new file mode 100644 index 00000000..3bffeedb --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.7.0/cksum @@ -0,0 +1 @@ +695240564 24003648 consul diff --git a/cdist/conf/type/__consul/files/versions/0.7.0/source b/cdist/conf/type/__consul/files/versions/0.7.0/source new file mode 100644 index 00000000..ad610fc7 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.7.0/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/0.7.0/consul_0.7.0_linux_amd64.zip From 39f69ddedf8392eef8c30002e47bd4ac25d384a8 Mon Sep 17 00:00:00 2001 From: Carlos Ortigoza Dempster Date: Fri, 25 Nov 2016 14:19:01 -0400 Subject: [PATCH 0353/1332] Adding consul 0.7.1 files to __consul type --- cdist/conf/type/__consul/files/versions/0.7.1/cksum | 1 + cdist/conf/type/__consul/files/versions/0.7.1/source | 1 + 2 files changed, 2 insertions(+) create mode 100644 cdist/conf/type/__consul/files/versions/0.7.1/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.7.1/source diff --git a/cdist/conf/type/__consul/files/versions/0.7.1/cksum b/cdist/conf/type/__consul/files/versions/0.7.1/cksum new file mode 100644 index 00000000..476bd9f6 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.7.1/cksum @@ -0,0 +1 @@ +3128343188 28402769 consul diff --git a/cdist/conf/type/__consul/files/versions/0.7.1/source b/cdist/conf/type/__consul/files/versions/0.7.1/source new file mode 100644 index 00000000..6ba2e7bf --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.7.1/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/0.7.1/consul_0.7.1_linux_amd64.zip From 835e281c9c8229fca959bb18dfc5ca77dd4ae7d7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 27 Nov 2016 17:02:51 +0100 Subject: [PATCH 0354/1332] Notice IPv6 address [] notation. --- docs/src/cdist-remote-exec-copy.rst | 5 +++++ docs/src/cdist-type.rst | 6 ++++++ docs/src/man1/cdist.rst | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/docs/src/cdist-remote-exec-copy.rst b/docs/src/cdist-remote-exec-copy.rst index 882f0bc2..bb818310 100644 --- a/docs/src/cdist-remote-exec-copy.rst +++ b/docs/src/cdist-remote-exec-copy.rst @@ -17,6 +17,11 @@ passing them to cdist with the --remote-exec and/or --remote-copy arguments. For __remote_exec, the custom implementation must behave as if it where ssh. For __remote_copy, it must behave like scp. +Please notice, custom implementations should work like ssh/scp so __remote_copy +must support IPv6 addresses enclosed in square brackets. For __remote_exec you +must take into account that for some options (like -L) IPv6 addresses can be +specified by enclosed in square brackets (see :strong:`ssh`\ (1) and +:strong:`scp`\ (1)). With this simple interface the user can take total control of how cdist interacts with the target when required, while the default implementation diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 62694fd8..1ff82ce0 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -251,6 +251,12 @@ script, you can write to stderr: # Output to be saved by cdist for execution on the target echo "touch /etc/cdist-configured" +Notice: if you use __remote_copy or __remote_exec directly in your scripts +then for IPv6 address with __remote_copy execution you should enclose IPv6 +address in square brackets. The same applies to __remote_exec if it behaves +the same as ssh for some options where colon is a delimiter, as for -L ssh +option (see :strong:`ssh`\ (1) and :strong:`scp`\ (1)). + Variable access from the generated scripts ------------------------------------------ diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 45ce339e..f3cb672c 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -157,6 +157,12 @@ cdist/conf The distribution configuration directory. It contains official types and explorers. This path is relative to cdist installation directory. +NOTES +----- +cdist detects if host is specified by IPv6 address. If so then remote_copy +command is executed with host address enclosed in square brackets +(see :strong:`scp`\ (1)). + EXAMPLES -------- From ed4e18713201f19e1df1bf3f67cbdae1862e8f28 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 27 Nov 2016 17:11:14 +0100 Subject: [PATCH 0355/1332] Update changelog. --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index 721bad6a..b5959d77 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,7 +2,11 @@ Changelog --------- next: + * Type __consul: add source and cksum files for Consul 0.7.0 and 0.7.1 (Carlos Ortigoza) + * Type __user: FreeBSD fix (Kamila Součková) + * New type: __apt_mark (Ander Punnar) * Type __package_upgrade_all: do not dist-upgrade by default, add apt-clean and apt-dist-upgrade options (Ander Punnar) + * Core: fix target_host vars (Darko Poljak) * All: Merge install feature from 4.0-pre-not-stable (Darko Poljak) 4.3.2: 2016-10-13 From 36244b8a11d56106e8a041cc7b066a5debbf826b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 28 Nov 2016 08:02:33 +0100 Subject: [PATCH 0356/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index b5959d77..07278241 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Core, types: support IPv6 (Darko Poljak) * Type __consul: add source and cksum files for Consul 0.7.0 and 0.7.1 (Carlos Ortigoza) * Type __user: FreeBSD fix (Kamila Součková) * New type: __apt_mark (Ander Punnar) From ca424a34e6f94261d681a588e6403673b965fc28 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 28 Nov 2016 08:13:59 +0100 Subject: [PATCH 0357/1332] Fix shell IPv6 testing (for -e). --- cdist/conf/type/__file/gencode-local | 3 +-- cdist/conf/type/__jail_freebsd10/gencode-local | 3 +-- cdist/conf/type/__jail_freebsd9/gencode-local | 3 +-- cdist/conf/type/__pf_ruleset/gencode-local | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index c9e0fa2c..4caa6df6 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -67,8 +67,7 @@ DONE if [ "$upload_file" ]; then echo upload >> "$__messages_out" # IPv6 fix - echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' - if [ $? -eq 0 ] + if $(echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$') then my_target_host="[${__target_host}]" else diff --git a/cdist/conf/type/__jail_freebsd10/gencode-local b/cdist/conf/type/__jail_freebsd10/gencode-local index bdd0ffd7..8c1687a9 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-local +++ b/cdist/conf/type/__jail_freebsd10/gencode-local @@ -44,8 +44,7 @@ basepresent="$(cat "$__object/explorer/basepresent")" if [ "$state" = "present" ]; then if [ "$basepresent" = "NONE" ]; then # IPv6 fix - echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' - if [ $? -eq 0 ] + if $(echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$') then my_target_host="[${__target_host}]" else diff --git a/cdist/conf/type/__jail_freebsd9/gencode-local b/cdist/conf/type/__jail_freebsd9/gencode-local index ce9b215e..67420a6f 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-local +++ b/cdist/conf/type/__jail_freebsd9/gencode-local @@ -40,8 +40,7 @@ basepresent="$(cat "$__object/explorer/basepresent")" if [ "$state" = "present" ]; then if [ "$basepresent" = "NONE" ]; then # IPv6 fix - echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' - if [ $? -eq 0 ] + if $(echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$') then my_target_host="[${__target_host}]" else diff --git a/cdist/conf/type/__pf_ruleset/gencode-local b/cdist/conf/type/__pf_ruleset/gencode-local index d14a6045..2db2ae06 100644 --- a/cdist/conf/type/__pf_ruleset/gencode-local +++ b/cdist/conf/type/__pf_ruleset/gencode-local @@ -60,8 +60,7 @@ case $uname in esac # IPv6 fix -echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' -if [ $? -eq 0 ] +if $(echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$') then my_target_host="[${__target_host}]" else From f473b671b1b885ec8c91258e447dff86801d5ed0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 29 Nov 2016 07:43:53 +0100 Subject: [PATCH 0358/1332] Update AUTHORS in cdist man page. --- docs/src/man1/cdist.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index f3cb672c..ff09ea2f 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -245,7 +245,8 @@ The following exit values shall be returned: AUTHORS ------- -Nico Schottelius +Originally written by Nico Schottelius +and Steven Armstrong . CAVEATS ------- From e7c3c157245d6a4d9aa9c36b92c9b768e50517b9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Nov 2016 23:19:53 +0100 Subject: [PATCH 0359/1332] Deprecate -d, make -v log level counter. --- docs/src/man1/cdist.rst | 5 +++-- scripts/cdist | 30 ++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index ff09ea2f..08c49446 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -46,11 +46,12 @@ All commands accept the following options: .. option:: -d, --debug - Set log level to debug + Set log level to debug (deprecated, use -vvv instead) .. option:: -v, --verbose - Set log level to info, be more verbose + Increase log level, be more verbose. The order of levels from lowest to + greatest are: ERROR, WARNING, INFO, DEBUG. .. option:: -V, --version diff --git a/scripts/cdist b/scripts/cdist index 68084ca4..22acb033 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -21,6 +21,8 @@ # # +import collections +import logging # list of beta sub-commands BETA_COMMANDS = ['install', ] @@ -61,6 +63,15 @@ def check_beta(args_dict): raise cdist.CdistBetaRequired(cmd, arg) +_verbosity_level = { + 0: logging.ERROR, + 1: logging.WARNING, + 2: logging.INFO, +} +_verbosity_level = collections.defaultdict( + lambda: logging.DEBUG, _verbosity_level) + + def commandline(): """Parse command line""" import argparse @@ -78,11 +89,14 @@ def commandline(): # Options _all_ parsers have in common parser['loglevel'] = argparse.ArgumentParser(add_help=False) parser['loglevel'].add_argument( - '-d', '--debug', help='Set log level to debug', + '-d', '--debug', + help=('Set log level to debug (deprecated, use -vvv instead)'), action='store_true', default=False) parser['loglevel'].add_argument( - '-v', '--verbose', help='Set log level to info, be more verbose', - action='store_true', default=False) + '-v', '--verbose', + help=('Increase log level, be more verbose. The order of levels ' + 'from lowest to greatest are: ERROR, WARNING, INFO, DEBUG.'), + action='count', default=0) # Main subcommand parser parser['main'] = argparse.ArgumentParser( @@ -179,11 +193,12 @@ def commandline(): args = parser['main'].parse_args(sys.argv[1:]) - # Loglevels are handled globally in here and debug wins over verbose - if args.verbose: - logging.root.setLevel(logging.INFO) + # Loglevels are handled globally in here if args.debug: - logging.root.setLevel(logging.DEBUG) + log.warning("-d/--debug is deprecated, use -vvv instead") + args.verbose = 3 + + logging.root.setLevel(_verbosity_level[args.verbose]) log.debug(args) log.info("version %s" % cdist.VERSION) @@ -219,7 +234,6 @@ if __name__ == "__main__": exit_code = 0 try: - import logging import os import re import cdist From b81950741560acf12bd4258c61777cf6f6dd28b9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Nov 2016 23:25:31 +0100 Subject: [PATCH 0360/1332] Better document -v option. --- docs/src/man1/cdist.rst | 5 +++-- scripts/cdist | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 08c49446..4907da55 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -50,8 +50,9 @@ All commands accept the following options: .. option:: -v, --verbose - Increase log level, be more verbose. The order of levels from lowest to - greatest are: ERROR, WARNING, INFO, DEBUG. + Increase log level, be more verbose. Use it more than onceto increase + log level. The order of levels from the lowest to the greatest are: + ERROR, WARNING, INFO, DEBUG. .. option:: -V, --version diff --git a/scripts/cdist b/scripts/cdist index 22acb033..7e755f4c 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -94,8 +94,9 @@ def commandline(): action='store_true', default=False) parser['loglevel'].add_argument( '-v', '--verbose', - help=('Increase log level, be more verbose. The order of levels ' - 'from lowest to greatest are: ERROR, WARNING, INFO, DEBUG.'), + help=('Increase log level, be more verbose. Use it more than once ' + 'to increase log level. The order of levels from the lowest ' + 'to the greatest are: ERROR, WARNING, INFO, DEBUG.'), action='count', default=0) # Main subcommand parser From ab71ab621d20849fa0924bfcd2f846fced5a738f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Nov 2016 23:26:53 +0100 Subject: [PATCH 0361/1332] Fix typo. --- docs/src/man1/cdist.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 4907da55..4970994a 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -50,7 +50,7 @@ All commands accept the following options: .. option:: -v, --verbose - Increase log level, be more verbose. Use it more than onceto increase + Increase log level, be more verbose. Use it more than once to increase log level. The order of levels from the lowest to the greatest are: ERROR, WARNING, INFO, DEBUG. From 8e3281aa7c5cf83c1180f139dbcbcc59e8878268 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Thu, 1 Dec 2016 09:09:57 +0100 Subject: [PATCH 0362/1332] rewrite man page in rst Only minimal changes needed. This was done to satisfy darko-poljak's request here: https://github.com/ungleich/cdist/pull/354#issuecomment-263492801 --- .../type/__package_dpkg/{man.text => man.rst} | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) rename cdist/conf/type/__package_dpkg/{man.text => man.rst} (62%) diff --git a/cdist/conf/type/__package_dpkg/man.text b/cdist/conf/type/__package_dpkg/man.rst similarity index 62% rename from cdist/conf/type/__package_dpkg/man.text rename to cdist/conf/type/__package_dpkg/man.rst index ae98be99..2af69341 100644 --- a/cdist/conf/type/__package_dpkg/man.text +++ b/cdist/conf/type/__package_dpkg/man.rst @@ -1,7 +1,5 @@ cdist-type__package_dpkg(7) ========================== -Tomas Pospisek - NAME ---- @@ -18,27 +16,29 @@ The object given to __package_dpkg must be the name of the deb package. REQUIRED PARAMETERS ------------------- -source:: +source path to the *.deb package EXAMPLES -------- --------------------------------------------------------------------------------- -# Install foo and bar packages -__package_dpkg --source /tmp/foo_0.1_all.deb foo_0.1_all.deb -__package_dpkg --source $__type/files/bar_1.4.deb bar_1.4.deb --------------------------------------------------------------------------------- +.. code-block:: sh + + # Install foo and bar packages + __package_dpkg --source /tmp/foo_0.1_all.deb foo_0.1_all.deb + __package_dpkg --source $__type/files/bar_1.4.deb bar_1.4.deb SEE ALSO -------- -- cdist-type(7) -- cdist-type__package(7) +:strong:`cdist-type`\ (7), :strong:`cdist-type__package`\ (7) +AUTHORS +------- +Tomas Pospisek COPYING ------- Copyright \(C) 2013 Tomas Pospisek. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). -This type is based on __package_apt +This type is based on __package_apt. From 4514bf1bd49e616f179811dfa1f4d7d92efef0d9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 1 Dec 2016 09:14:51 +0100 Subject: [PATCH 0363/1332] greatest -> highest --- docs/src/man1/cdist.rst | 2 +- scripts/cdist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 4970994a..5daedcd4 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -51,7 +51,7 @@ All commands accept the following options: .. option:: -v, --verbose Increase log level, be more verbose. Use it more than once to increase - log level. The order of levels from the lowest to the greatest are: + log level. The order of levels from the lowest to the highest are: ERROR, WARNING, INFO, DEBUG. .. option:: -V, --version diff --git a/scripts/cdist b/scripts/cdist index 7e755f4c..4ff64bb5 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -96,7 +96,7 @@ def commandline(): '-v', '--verbose', help=('Increase log level, be more verbose. Use it more than once ' 'to increase log level. The order of levels from the lowest ' - 'to the greatest are: ERROR, WARNING, INFO, DEBUG.'), + 'to the highest are: ERROR, WARNING, INFO, DEBUG.'), action='count', default=0) # Main subcommand parser From 60906c0228d8f844fd31a4434fd5969ae6fe77a3 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Thu, 1 Dec 2016 09:27:56 +0100 Subject: [PATCH 0364/1332] rewrite man page in rst Only minimal changes needed. This was done to satisfy darko-poljak's request here: https://github.com/ungleich/cdist/pull/360#issuecomment-263491151 --- .../{man.text => man.rst} | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) rename cdist/conf/type/__postgres_extension/{man.text => man.rst} (58%) diff --git a/cdist/conf/type/__postgres_extension/man.text b/cdist/conf/type/__postgres_extension/man.rst similarity index 58% rename from cdist/conf/type/__postgres_extension/man.text rename to cdist/conf/type/__postgres_extension/man.rst index 6d722d68..39aa0837 100644 --- a/cdist/conf/type/__postgres_extension/man.text +++ b/cdist/conf/type/__postgres_extension/man.rst @@ -1,7 +1,5 @@ cdist-type__postgres_extension(7) ================================= -Tomas Pospisek - NAME ---- @@ -16,35 +14,42 @@ The object you need to pass to __postgres_extension consists of the database name and the extension name joined by a colon in the following form: +.. code-block:: + dbname:extension f.ex. +.. code-block:: + rails_test:unaccent OPTIONAL PARAMETERS ------------------- -state:: - Either "present" or "absent", defaults to "present" +state + either "present" or "absent", defaults to "present" EXAMPLES -------- --------------------------------------------------------------------------------- -__postgres_extension rails_test:unaccent -__postgres_extension --present rails_test:unaccent -__postgres_extension --absent rails_test:unaccent --------------------------------------------------------------------------------- +.. code-block:: sh + + __postgres_extension rails_test:unaccent + __postgres_extension --present rails_test:unaccent + __postgres_extension --absent rails_test:unaccent SEE ALSO -------- -- cdist-type(7) -- cdist-type__postgres_database(7) -- http://www.postgresql.org/docs/current/static/sql-createextension.html +:strong:`cdist-type`\ (7), :strong:`cdist-type__postgre_database`\ (7) +Postgres "Create Extension" documentation at: . + +AUTHOR +------- +Tomas Pospisek COPYING ------- From 267d8239c1b43a1485f5e2bbb1d8cc8bc040bfbc Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Thu, 1 Dec 2016 09:50:05 +0100 Subject: [PATCH 0365/1332] remove reference to cdist_type, use GPL3+ as requested by darko-poljak here: https://github.com/ungleich/cdist/pull/360#issuecomment-264110087 --- cdist/conf/type/__postgres_extension/man.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__postgres_extension/man.rst b/cdist/conf/type/__postgres_extension/man.rst index 39aa0837..ead51c83 100644 --- a/cdist/conf/type/__postgres_extension/man.rst +++ b/cdist/conf/type/__postgres_extension/man.rst @@ -43,7 +43,7 @@ EXAMPLES SEE ALSO -------- -:strong:`cdist-type`\ (7), :strong:`cdist-type__postgre_database`\ (7) +:strong:`cdist-type__postgre_database`\ (7) Postgres "Create Extension" documentation at: . @@ -53,5 +53,7 @@ Tomas Pospisek COPYING ------- -Copyright \(C) 2014 Tomas Pospisek. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2014 Tomas Pospisek. 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. From 6bcfdec1545e862339ae0457e6ecd77593e8ca44 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Thu, 1 Dec 2016 09:54:27 +0100 Subject: [PATCH 0366/1332] remove reference to cdist_type, use GPL3+ as requested by darko-poljak here: https://github.com/ungleich/cdist/pull/360#issuecomment-264110087 --- cdist/conf/type/__package_dpkg/man.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__package_dpkg/man.rst b/cdist/conf/type/__package_dpkg/man.rst index 2af69341..fbd5b4b1 100644 --- a/cdist/conf/type/__package_dpkg/man.rst +++ b/cdist/conf/type/__package_dpkg/man.rst @@ -31,7 +31,7 @@ EXAMPLES SEE ALSO -------- -:strong:`cdist-type`\ (7), :strong:`cdist-type__package`\ (7) +:strong:`cdist-type__package`\ (7) AUTHORS ------- @@ -39,6 +39,8 @@ Tomas Pospisek COPYING ------- -Copyright \(C) 2013 Tomas Pospisek. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +Copyright \(C) 2013 Tomas Pospisek. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. This type is based on __package_apt. From 57d83be05452a59939b203398d4fa05c4a16c284 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 1 Dec 2016 15:40:34 +0100 Subject: [PATCH 0367/1332] Update changelog. --- docs/changelog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 07278241..78c4069e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,9 +2,11 @@ Changelog --------- next: + * Core: deprecate -d option and make -v option log level counter (Darko Poljak) + * New type: __postgres_extension (Tomas Pospisek) * Core, types: support IPv6 (Darko Poljak) * Type __consul: add source and cksum files for Consul 0.7.0 and 0.7.1 (Carlos Ortigoza) - * Type __user: FreeBSD fix (Kamila Součková) + * Type __user: FreeBSD fix (Kamila Souckova) * New type: __apt_mark (Ander Punnar) * Type __package_upgrade_all: do not dist-upgrade by default, add apt-clean and apt-dist-upgrade options (Ander Punnar) * Core: fix target_host vars (Darko Poljak) From 4370efdbb86910bb060cb003550347252904ba67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Posp=C3=AD=C5=A1ek?= Date: Fri, 2 Dec 2016 09:39:53 +0100 Subject: [PATCH 0368/1332] Update man.rst fix title as requested here https://github.com/ungleich/cdist/pull/354#issuecomment-264117501 --- cdist/conf/type/__package_dpkg/man.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_dpkg/man.rst b/cdist/conf/type/__package_dpkg/man.rst index fbd5b4b1..65a695b5 100644 --- a/cdist/conf/type/__package_dpkg/man.rst +++ b/cdist/conf/type/__package_dpkg/man.rst @@ -1,5 +1,5 @@ cdist-type__package_dpkg(7) -========================== +=========================== NAME ---- From 3054bae8c2cd847b29416027ecfd38235309b4ab Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Fri, 2 Dec 2016 14:34:01 +0100 Subject: [PATCH 0369/1332] Added __docker type from asteven, implemented debian support --- cdist/conf/type/__docker/man.text | 51 ++++++++++++++ cdist/conf/type/__docker/manifest | 81 ++++++++++++++++++++++ cdist/conf/type/__docker/parameter/boolean | 1 + cdist/conf/type/__docker/singleton | 0 4 files changed, 133 insertions(+) create mode 100644 cdist/conf/type/__docker/man.text create mode 100755 cdist/conf/type/__docker/manifest create mode 100644 cdist/conf/type/__docker/parameter/boolean create mode 100644 cdist/conf/type/__docker/singleton diff --git a/cdist/conf/type/__docker/man.text b/cdist/conf/type/__docker/man.text new file mode 100644 index 00000000..566c2f4c --- /dev/null +++ b/cdist/conf/type/__docker/man.text @@ -0,0 +1,51 @@ +cdist-type__docker(7) +===================== +Steven Armstrong + + +NAME +---- +cdist-type__docker - install docker-engine + + +DESCRIPTION +----------- +Installs latest docker-engine package from dockerproject.org. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +BOOLEAN PARAMETERS +------------------ +experimentel:: + Install the experimentel docker-engine package instead of the latest stable release. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__docker + +# experimentel +__docker --experimental +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +COPYING +------- +Copyright \(C) 2016 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest new file mode 100755 index 00000000..ba13b3e4 --- /dev/null +++ b/cdist/conf/type/__docker/manifest @@ -0,0 +1,81 @@ +#!/bin/sh +# +# 2016 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + centos) + component="main" + if [ -f "$__object/parameter/experimental" ]; then + component="experimental" + fi + export CDIST_ORDER_DEPENDENCY=on + __yum_repo docker \ + --name 'Docker Repository' \ + --baseurl "https://yum.dockerproject.org/repo/$component/centos/\$releasever/" \ + --enabled \ + --gpgcheck \ + --gpgkey 'https://yum.dockerproject.org/gpg' + __package docker-engine + unset CDIST_ORDER_DEPENDENCY + ;; + ubuntu) + component="main" + if [ -f "$__object/parameter/experimental" ]; then + component="experimental" + fi + __package apparmor + __package ca-certificates + __package apt-transport-https + __apt_key docker --keyid 58118E89F3A912897C070ADBF76221572C52609D + export CDIST_ORDER_DEPENDENCY=on + __apt_source docker \ + --uri https://apt.dockerproject.org/repo \ + --distribution "ubuntu-$(cat "$__global/explorer/lsb_codename")" \ + --component "$component" + __package docker-engine + unset CDIST_ORDER_DEPENDENCY + ;; + debian) + component="main" + if [ -f "$__object/parameter/experimental" ]; then + component="experimental" + fi + + __package apt-transport-https + __package ca-certificates + __package gnupg2 + __apt_key docker --keyid 58118E89F3A912897C070ADBF76221572C52609D + export CDIST_ORDER_DEPENDENCY=on + __apt_source docker \ + --uri https://apt.dockerproject.org/repo \ + --distribution "debian-$(cat "$__global/explorer/lsb_codename")" \ + --component "$component" + __package docker-engine + unset CDIST_ORDER_DEPENDENCY + + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__docker/parameter/boolean b/cdist/conf/type/__docker/parameter/boolean new file mode 100644 index 00000000..9839eb20 --- /dev/null +++ b/cdist/conf/type/__docker/parameter/boolean @@ -0,0 +1 @@ +experimental diff --git a/cdist/conf/type/__docker/singleton b/cdist/conf/type/__docker/singleton new file mode 100644 index 00000000..e69de29b From 0fae040f77bc080a9f03f078495f10b09802e4f7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Dec 2016 09:52:49 +0100 Subject: [PATCH 0370/1332] Update changelog: release 4.4.0. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 78c4069e..d9939bf1 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.4.0: 2016-12-03 * Core: deprecate -d option and make -v option log level counter (Darko Poljak) * New type: __postgres_extension (Tomas Pospisek) * Core, types: support IPv6 (Darko Poljak) From d07ad486512896043caebeeb2bc19ae7a22d6233 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Dec 2016 10:21:00 +0100 Subject: [PATCH 0371/1332] Add reference to beta docs. --- docs/web/cdist/documentation.mdwn | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/web/cdist/documentation.mdwn b/docs/web/cdist/documentation.mdwn index 56c2798e..6479a4bb 100644 --- a/docs/web/cdist/documentation.mdwn +++ b/docs/web/cdist/documentation.mdwn @@ -6,4 +6,7 @@ have a look at [all versions](/software/cdist/man). You can also view [speeches about cdist](/software/cdist/speeches). +Checking out beta? Find the docs here: +[beta documentation](/software/cdist/man/beta). + [[!tag cdist unix]] From 8c53ce78f5cf8607b544d53d51da77cbfe7f6dc4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Dec 2016 10:46:49 +0100 Subject: [PATCH 0372/1332] Started the good, the bad and the ugly - code cleanup. --- cdist/config.py | 65 ++-------------------------------------- cdist/util/ipaddr.py | 57 +++++++++++++++++++++++++++++++++++ cdist/util/remoteutil.py | 50 +++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 62 deletions(-) create mode 100644 cdist/util/ipaddr.py create mode 100644 cdist/util/remoteutil.py diff --git a/cdist/config.py b/cdist/config.py index b8d0672c..855aaade 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -34,38 +34,10 @@ import cdist import cdist.exec.local import cdist.exec.remote +import cdist.util.ipaddr as ipaddr from cdist import core - - -def inspect_ssh_mux_opts(): - """Inspect whether or not ssh supports multiplexing options. - - Return string containing multiplexing options if supported. - If ControlPath is supported then placeholder for that path is - specified and can be used for final string formatting. - For example, this function can return string: - "-o ControlMaster=auto -o ControlPersist=125 -o ControlPath={}". - Then it can be formatted: - mux_opts_string.format('/tmp/tmpxxxxxx/ssh-control-path'). - """ - import subprocess - - wanted_mux_opts = { - "ControlPath": "{}", - "ControlMaster": "auto", - "ControlPersist": "125", - } - mux_opts = " ".join([" -o {}={}".format( - x, wanted_mux_opts[x]) for x in wanted_mux_opts]) - try: - subprocess.check_output("ssh {}".format(mux_opts), - stderr=subprocess.STDOUT, shell=True) - except subprocess.CalledProcessError as e: - subproc_output = e.output.decode().lower() - if "bad configuration option" in subproc_output: - return "" - return mux_opts +from cdist.util.remoteutil import inspect_ssh_mux_opts class Config(object): @@ -253,38 +225,7 @@ class Config(object): log.debug("remote_copy for host \"{}\": {}".format( host, remote_copy)) - try: - # getaddrinfo returns a list of 5-tuples: - # (family, type, proto, canonname, sockaddr) - # where sockaddr is: - # (address, port) for AF_INET, - # (address, port, flow_info, scopeid) for AF_INET6 - ip_addr = socket.getaddrinfo( - host, None, type=socket.SOCK_STREAM)[0][4][0] - # gethostbyaddr returns triple - # (hostname, aliaslist, ipaddrlist) - host_name = socket.gethostbyaddr(ip_addr)[0] - log.debug("derived host_name for host \"{}\": {}".format( - host, host_name)) - except (socket.gaierror, socket.herror) as e: - log.warn("Could not derive host_name for {}" - ", $host_name will be empty. Error is: {}".format( - host, e)) - # in case of error provide empty value - host_name = '' - - try: - host_fqdn = socket.getfqdn(host) - log.debug("derived host_fqdn for host \"{}\": {}".format( - host, host_fqdn)) - except socket.herror as e: - log.warn("Could not derive host_fqdn for {}" - ", $host_fqdn will be empty. Error is: {}".format( - host, e)) - # in case of error provide empty value - host_fqdn = '' - - target_host = (host, host_name, host_fqdn) + target_host = ipaddr.resolve_target_addresses(host) log.debug("target_host: {}".format(target_host)) local = cdist.exec.local.Local( diff --git a/cdist/util/ipaddr.py b/cdist/util/ipaddr.py new file mode 100644 index 00000000..7c3c037a --- /dev/null +++ b/cdist/util/ipaddr.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +# 2016 Darko Poljak (darko.poljak 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 . +# +# + +import socket +import logging + + +def resolve_target_addresses(host): + log = logging.getLogger(host) + try: + # getaddrinfo returns a list of 5-tuples: + # (family, type, proto, canonname, sockaddr) + # where sockaddr is: + # (address, port) for AF_INET, + # (address, port, flow_info, scopeid) for AF_INET6 + ip_addr = socket.getaddrinfo( + host, None, type=socket.SOCK_STREAM)[0][4][0] + # gethostbyaddr returns triple + # (hostname, aliaslist, ipaddrlist) + host_name = socket.gethostbyaddr(ip_addr)[0] + log.debug("derived host_name for host \"{}\": {}".format( + host, host_name)) + except (socket.gaierror, socket.herror) as e: + log.warn("Could not derive host_name for {}" + ", $host_name will be empty. Error is: {}".format(host, e)) + # in case of error provide empty value + host_name = '' + + try: + host_fqdn = socket.getfqdn(host) + log.debug("derived host_fqdn for host \"{}\": {}".format( + host, host_fqdn)) + except socket.herror as e: + log.warn("Could not derive host_fqdn for {}" + ", $host_fqdn will be empty. Error is: {}".format(host, e)) + # in case of error provide empty value + host_fqdn = '' + + return (host, host_name, host_fqdn) diff --git a/cdist/util/remoteutil.py b/cdist/util/remoteutil.py new file mode 100644 index 00000000..c18d6705 --- /dev/null +++ b/cdist/util/remoteutil.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# +# 2016 Darko Poljak (darko.poljak 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 . +# +# + + +def inspect_ssh_mux_opts(): + """Inspect whether or not ssh supports multiplexing options. + + Return string containing multiplexing options if supported. + If ControlPath is supported then placeholder for that path is + specified and can be used for final string formatting. + For example, this function can return string: + "-o ControlMaster=auto -o ControlPersist=125 -o ControlPath={}". + Then it can be formatted: + mux_opts_string.format('/tmp/tmpxxxxxx/ssh-control-path'). + """ + import subprocess + + wanted_mux_opts = { + "ControlPath": "{}", + "ControlMaster": "auto", + "ControlPersist": "125", + } + mux_opts = " ".join([" -o {}={}".format( + x, wanted_mux_opts[x]) for x in wanted_mux_opts]) + try: + subprocess.check_output("ssh {}".format(mux_opts), + stderr=subprocess.STDOUT, shell=True) + except subprocess.CalledProcessError as e: + subproc_output = e.output.decode().lower() + if "bad configuration option" in subproc_output: + return "" + return mux_opts From b24adcbe202fdb1d59e6ccdea08a39a012e8c244 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Dec 2016 14:03:24 +0100 Subject: [PATCH 0373/1332] Fix changelog style. --- docs/changelog | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/changelog b/docs/changelog index d9939bf1..168282aa 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,14 +2,14 @@ Changelog --------- 4.4.0: 2016-12-03 - * Core: deprecate -d option and make -v option log level counter (Darko Poljak) + * Core: Deprecate -d option and make -v option log level counter (Darko Poljak) * New type: __postgres_extension (Tomas Pospisek) - * Core, types: support IPv6 (Darko Poljak) - * Type __consul: add source and cksum files for Consul 0.7.0 and 0.7.1 (Carlos Ortigoza) + * Core, types: Support IPv6 (Darko Poljak) + * Type __consul: Add source and cksum files for Consul 0.7.0 and 0.7.1 (Carlos Ortigoza) * Type __user: FreeBSD fix (Kamila Souckova) * New type: __apt_mark (Ander Punnar) - * Type __package_upgrade_all: do not dist-upgrade by default, add apt-clean and apt-dist-upgrade options (Ander Punnar) - * Core: fix target_host vars (Darko Poljak) + * Type __package_upgrade_all: Do not dist-upgrade by default, add apt-clean and apt-dist-upgrade options (Ander Punnar) + * Core: Correct target_host var in code.py (Darko Poljak) * All: Merge install feature from 4.0-pre-not-stable (Darko Poljak) 4.3.2: 2016-10-13 @@ -20,7 +20,7 @@ Changelog * Type __package_pkg_openbsd: Support --version (Andres Erbsen) * Type __hostname: Support openbsd (Andres Erbsen) * New type: __firewalld_start: start/stop firewalld and/or enable/disable start on boot (Darko Poljak) - * Bugfix __consul_agent: config option was misnamed 'syslog' instead of 'enable_syslog' (Steven Armstrong) + * Bugfix __consul_agent: Config option was misnamed 'syslog' instead of 'enable_syslog' (Steven Armstrong) 4.3.1: 2016-08-22 * Documentation: Spelling fixes (Darko Poljak) From e6fc74c081423c8095a3d1e8e72d8ce24699f436 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Dec 2016 18:12:38 +0100 Subject: [PATCH 0374/1332] ugly -> bad --- cdist/config.py | 111 ++++++++++++++++++------------------------- cdist/exec/remote.py | 31 +----------- cdist/hostsource.py | 72 ++++++++++++++++++++++++++++ cdist/util/ipaddr.py | 26 ++++++++++ 4 files changed, 146 insertions(+), 94 deletions(-) create mode 100644 cdist/hostsource.py diff --git a/cdist/config.py b/cdist/config.py index 855aaade..b1a120ca 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -22,15 +22,14 @@ import logging import os -import shutil import sys import time -import pprint import itertools import tempfile import socket import cdist +import cdist.hostsource import cdist.exec.local import cdist.exec.remote @@ -61,55 +60,17 @@ class Config(object): self.local.create_files_dirs() self.remote.create_files_dirs() - @staticmethod - def hostfile_process_line(line): - """Return host from read line or None if no host present.""" - if not line: - return None - # remove comment if present - comment_index = line.find('#') - if comment_index >= 0: - host = line[:comment_index] - else: - host = line - # remove leading and trailing whitespaces - host = host.strip() - # skip empty lines - if host: - return host - else: - return None - @staticmethod def hosts(source): - """Yield hosts from source. - Source can be a sequence or filename (stdin if \'-\'). - In case of filename each line represents one host. - """ - if isinstance(source, str): - import fileinput - try: - for host in fileinput.input(files=(source)): - host = Config.hostfile_process_line(host) - if host: - yield host - except (IOError, OSError, UnicodeError) as e: - raise cdist.Error( - "Error reading hosts from file \'{}\': {}".format( - source, e)) - else: - if source: - for host in source: - yield host + try: + yield from cdist.hostsource.HostSource(source)() + except (IOError, OSError, UnicodeError) as e: + raise cdist.Error( + "Error reading hosts from \'{}\': {}".format( + source, e)) @classmethod - def commandline(cls, args): - """Configure remote system""" - import multiprocessing - - # FIXME: Refactor relict - remove later - log = logging.getLogger("cdist") - + def _check_and_prepare_args(cls, args): if args.manifest == '-' and args.hostfile == '-': raise cdist.Error(("Cannot read both, manifest and host file, " "from stdin")) @@ -134,10 +95,6 @@ class Config(object): import atexit atexit.register(lambda: os.remove(initial_manifest_temp_path)) - process = {} - failed_hosts = [] - time_start = time.time() - # default remote cmd patterns args.remote_exec_pattern = None args.remote_copy_pattern = None @@ -154,10 +111,29 @@ class Config(object): if args_dict['remote_copy'] is None: args.remote_copy_pattern = cdist.REMOTE_COPY + mux_opts + @classmethod + def _base_root_path(cls, args): if args.out_path: base_root_path = args.out_path else: base_root_path = tempfile.mkdtemp() + return base_root_path + + @classmethod + def commandline(cls, args): + """Configure remote system""" + import multiprocessing + + # FIXME: Refactor relict - remove later + log = logging.getLogger("cdist") + + cls._check_and_prepare_args(args) + + process = {} + failed_hosts = [] + time_start = time.time() + + base_root_path = cls._base_root_path(args) hostcnt = 0 for host in itertools.chain(cls.hosts(args.host), @@ -199,6 +175,24 @@ class Config(object): raise cdist.Error("Failed to configure the following hosts: " + " ".join(failed_hosts)) + @classmethod + def _resolve_remote_cmds(cls, args, host_base_path): + control_path = os.path.join(host_base_path, "ssh-control-path") + # If we constructed patterns for remote commands then there is + # placeholder for ssh ControlPath, format it and we have unique + # ControlPath for each host. + # + # If not then use args.remote_exec/copy that user specified. + if args.remote_exec_pattern: + remote_exec = args.remote_exec_pattern.format(control_path) + else: + remote_exec = args.remote_exec + if args.remote_copy_pattern: + remote_copy = args.remote_copy_pattern.format(control_path) + else: + remote_copy = args.remote_copy + return (remote_exec, remote_copy, ) + @classmethod def onehost(cls, host, host_base_path, host_dir_name, args, parallel): """Configure ONE system""" @@ -206,20 +200,7 @@ class Config(object): log = logging.getLogger(host) try: - control_path = os.path.join(host_base_path, "ssh-control-path") - # If we constructed patterns for remote commands then there is - # placeholder for ssh ControlPath, format it and we have unique - # ControlPath for each host. - # - # If not then use args.remote_exec/copy that user specified. - if args.remote_exec_pattern: - remote_exec = args.remote_exec_pattern.format(control_path) - else: - remote_exec = args.remote_exec - if args.remote_copy_pattern: - remote_copy = args.remote_copy_pattern.format(control_path) - else: - remote_copy = args.remote_copy + remote_exec, remote_copy = cls._resolve_remote_cmds(host_base_path) log.debug("remote_exec for host \"{}\": {}".format( host, remote_exec)) log.debug("remote_copy for host \"{}\": {}".format( diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index f374262f..74a33f73 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -30,40 +30,13 @@ import multiprocessing import cdist import cdist.exec.util as exec_util - - -# check whether addr is IPv6 -try: - # python 3.3+ - import ipaddress - - def _is_ipv6(addr): - try: - return ipaddress.ip_address(addr).version == 6 - except ValueError: - return False -except ImportError: - # fallback for older python versions - import socket - - def _is_ipv6(addr): - try: - socket.inet_aton(addr) - return False - except socket.error: - pass - try: - socket.inet_pton(socket.AF_INET6, addr) - return True - except socket.error: - pass - return False +import cdist.util.ipaddr as ipaddr def _wrap_addr(addr): """If addr is IPv6 then return addr wrapped between '[' and ']', otherwise return it intact.""" - if _is_ipv6(addr): + if ipaddr.is_ipv6(addr): return "".join(("[", addr, "]", )) else: return addr diff --git a/cdist/hostsource.py b/cdist/hostsource.py new file mode 100644 index 00000000..8170536c --- /dev/null +++ b/cdist/hostsource.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +# +# 2016 Darko Poljak (darko.poljak 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 . +# +# + +import fileinput + + +class HostSource(object): + """ + Host source object. + Source can be a sequence or filename (stdin if \'-\'). + In case of filename each line represents one host. + """ + def __init__(self, source): + self.source = source + + def _process_file_line(self, line): + """Return host from read line or None if no host present.""" + if not line: + return None + # remove comment if present + comment_index = line.find('#') + if comment_index >= 0: + host = line[:comment_index] + else: + host = line + # remove leading and trailing whitespaces + host = host.strip() + # skip empty lines + if host: + return host + else: + return None + + def _hosts_from_sequence(self): + for host in self.source: + yield host + + def _hosts_from_file(self): + for line in fileinput.input(files=(self.source)): + host = self._process_file_line(line) + if host: + yield host + + def hosts(self): + if not source: + return + + if isinstance(self.source, str): + yield from self._hosts_from_file() + else: + yield from self._hosts_from_sequence() + + def __call__(self): + yield from self.hosts() diff --git a/cdist/util/ipaddr.py b/cdist/util/ipaddr.py index 7c3c037a..71477682 100644 --- a/cdist/util/ipaddr.py +++ b/cdist/util/ipaddr.py @@ -55,3 +55,29 @@ def resolve_target_addresses(host): host_fqdn = '' return (host, host_name, host_fqdn) + + +# check whether addr is IPv6 +try: + # python 3.3+ + import ipaddress + + def is_ipv6(addr): + try: + return ipaddress.ip_address(addr).version == 6 + except ValueError: + return False +except ImportError: + # fallback for older python versions + def is_ipv6(addr): + try: + socket.inet_aton(addr) + return False + except socket.error: + pass + try: + socket.inet_pton(socket.AF_INET6, addr) + return True + except socket.error: + pass + return False From fc18e0f99cc57a2813bfe9c577566cfc5e4096ac Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Sat, 3 Dec 2016 18:14:58 +0100 Subject: [PATCH 0375/1332] migrated man.text -> man.rst --- .../conf/type/__docker/{man.text => man.rst} | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) rename cdist/conf/type/__docker/{man.text => man.rst} (71%) diff --git a/cdist/conf/type/__docker/man.text b/cdist/conf/type/__docker/man.rst similarity index 71% rename from cdist/conf/type/__docker/man.text rename to cdist/conf/type/__docker/man.rst index 566c2f4c..88786ad7 100644 --- a/cdist/conf/type/__docker/man.text +++ b/cdist/conf/type/__docker/man.rst @@ -1,7 +1,5 @@ cdist-type__docker(7) ===================== -Steven Armstrong - NAME ---- @@ -25,24 +23,23 @@ None. BOOLEAN PARAMETERS ------------------ -experimentel:: +experimentel Install the experimentel docker-engine package instead of the latest stable release. EXAMPLES -------- --------------------------------------------------------------------------------- -__docker +.. code-block:: sh + __docker -# experimentel -__docker --experimental --------------------------------------------------------------------------------- + # experimentel + __docker --experimental -SEE ALSO --------- -- cdist-type(7) +AUTHORS +------- +Steven Armstrong COPYING From d0f5d2c45967429d86002e5526b2bb60cadd3ed6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Dec 2016 18:24:37 +0100 Subject: [PATCH 0376/1332] ugly -> bad --- cdist/argparse.py | 209 ++++++++++++++++++++++++++++++++++++++++++++++ scripts/cdist | 176 ++------------------------------------ 2 files changed, 218 insertions(+), 167 deletions(-) create mode 100644 cdist/argparse.py mode change 100755 => 100644 scripts/cdist diff --git a/cdist/argparse.py b/cdist/argparse.py new file mode 100644 index 00000000..cef3dd5f --- /dev/null +++ b/cdist/argparse.py @@ -0,0 +1,209 @@ +import argparse +import cdist +import multiprocessing +import os +import logging +import collections + + +# list of beta sub-commands +BETA_COMMANDS = ['install', ] +# list of beta arguments for sub-commands +BETA_ARGS = { + 'config': ['jobs', ], +} +EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/" +# Parser others can reuse +parser = None + + +_verbosity_level = { + 0: logging.ERROR, + 1: logging.WARNING, + 2: logging.INFO, +} +_verbosity_level = collections.defaultdict( + lambda: logging.DEBUG, _verbosity_level) + + +def add_beta_command(cmd): + if cmd not in BETA_COMMANDS: + BETA_COMMANDS.append(cmd) + + +def add_beta_arg(cmd, arg): + if cmd in BETA_ARGS: + if arg not in BETA_ARGS[cmd]: + BETA_ARGS[cmd].append(arg) + else: + BETA_ARGS[cmd] = [arg, ] + + +def check_beta(args_dict): + if 'beta' not in args_dict: + args_dict['beta'] = False + # Check only if beta is not enabled: if beta option is specified then + # raise error. + if not args_dict['beta']: + cmd = args_dict['command'] + # first check if command is beta + if cmd in BETA_COMMANDS: + raise cdist.CdistBetaRequired(cmd) + # then check if some command's argument is beta + if cmd in BETA_ARGS: + for arg in BETA_ARGS[cmd]: + if arg in args_dict and args_dict[arg]: + raise cdist.CdistBetaRequired(cmd, arg) + + +def check_positive_int(value): + import argparse + + try: + val = int(value) + except ValueError: + raise argparse.ArgumentTypeError( + "{} is invalid int value".format(value)) + if val <= 0: + raise argparse.ArgumentTypeError( + "{} is invalid positive int value".format(val)) + return val + + +def get_parsers(): + global parser + + # Construct parser others can reuse + if parser: + return parser + else: + parser = {} + # Options _all_ parsers have in common + parser['loglevel'] = argparse.ArgumentParser(add_help=False) + parser['loglevel'].add_argument( + '-d', '--debug', + help=('Set log level to debug (deprecated, use -vvv instead)'), + action='store_true', default=False) + parser['loglevel'].add_argument( + '-v', '--verbose', + help=('Increase log level, be more verbose. Use it more than once ' + 'to increase log level. The order of levels from the lowest ' + 'to the highest are: ERROR, WARNING, INFO, DEBUG.'), + action='count', default=0) + + parser['beta'] = argparse.ArgumentParser(add_help=False) + parser['beta'].add_argument( + '-b', '--beta', + help=('Enable beta functionalities. ' + 'Can also be enabled using CDIST_BETA env var.'), + action='store_true', dest='beta', + default='CDIST_BETA' in os.environ) + + # Main subcommand parser + parser['main'] = argparse.ArgumentParser( + description='cdist ' + cdist.VERSION, parents=[parser['loglevel']]) + parser['main'].add_argument( + '-V', '--version', help='Show version', action='version', + version='%(prog)s ' + cdist.VERSION) + parser['sub'] = parser['main'].add_subparsers( + title="Commands", dest="command") + + # Banner + parser['banner'] = parser['sub'].add_parser( + 'banner', parents=[parser['loglevel']]) + parser['banner'].set_defaults(func=cdist.banner.banner) + + # Config + parser['config_main'] = argparse.ArgumentParser(add_help=False) + parser['config_main'].add_argument( + '-c', '--conf-dir', + help=('Add configuration directory (can be repeated, ' + 'last one wins)'), action='append') + parser['config_main'].add_argument( + '-i', '--initial-manifest', + help='path to a cdist manifest or \'-\' to read from stdin.', + dest='manifest', required=False) + parser['config_main'].add_argument( + '-j', '--jobs', nargs='?', + type=check_positive_int, + help=('Specify the maximum number of parallel jobs, currently ' + 'only global explorers are supported'), + action='store', dest='jobs', + const=multiprocessing.cpu_count()) + parser['config_main'].add_argument( + '-n', '--dry-run', + help='do not execute code', action='store_true') + parser['config_main'].add_argument( + '-o', '--out-dir', + help='directory to save cdist output in', dest="out_path") + + # remote-copy and remote-exec defaults are environment variables + # if set; if not then None - these will be futher handled after + # parsing to determine implementation default + parser['config_main'].add_argument( + '--remote-copy', + help='Command to use for remote copy (should behave like scp)', + action='store', dest='remote_copy', + default=os.environ.get('CDIST_REMOTE_COPY')) + parser['config_main'].add_argument( + '--remote-exec', + help=('Command to use for remote execution ' + '(should behave like ssh)'), + action='store', dest='remote_exec', + default=os.environ.get('CDIST_REMOTE_EXEC')) + + # Config + parser['config_args'] = argparse.ArgumentParser(add_help=False) + parser['config_args'].add_argument( + 'host', nargs='*', help='host(s) to operate on') + parser['config_args'].add_argument( + '-f', '--file', + help=('Read additional hosts to operate on from specified file ' + 'or from stdin if \'-\' (each host on separate line). ' + 'If no host or host file is specified then, by default, ' + 'read hosts from stdin.'), + dest='hostfile', required=False) + parser['config_args'].add_argument( + '-p', '--parallel', + help='operate on multiple hosts in parallel', + action='store_true', dest='parallel') + parser['config_args'].add_argument( + '-s', '--sequential', + help='operate on multiple hosts sequentially (default)', + action='store_false', dest='parallel') + parser['config'] = parser['sub'].add_parser( + 'config', parents=[parser['loglevel'], parser['beta'], + parser['config_main'], + parser['config_args']]) + parser['config'].set_defaults(func=cdist.config.Config.commandline) + + # Install + parser['install'] = parser['sub'].add_parser('install', add_help=False, + parents=[parser['config']]) + parser['install'].set_defaults(func=cdist.install.Install.commandline) + + # Shell + parser['shell'] = parser['sub'].add_parser( + 'shell', parents=[parser['loglevel']]) + parser['shell'].add_argument( + '-s', '--shell', + help=('Select shell to use, defaults to current shell. Used shell' + ' should be POSIX compatible shell.')) + parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) + + for p in parser: + parser[p].epilog = EPILOG + + return parser + + +def handle_loglevel(args): + if args.debug: + retval = "-d/--debug is deprecated, use -vvv instead" + args.verbose = 3 + else: + retval = None + + logging.root.setLevel(_verbosity_level[args.verbose]) + + return retval diff --git a/scripts/cdist b/scripts/cdist old mode 100755 new mode 100644 index 4ff64bb5..498091b8 --- a/scripts/cdist +++ b/scripts/cdist @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2016 Nico Schottelius (nico-cdist at schottelius.org) # 2016 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. @@ -24,182 +24,25 @@ import collections import logging -# list of beta sub-commands -BETA_COMMANDS = ['install', ] -# list of beta arguments for sub-commands -BETA_ARGS = { - 'config': ['jobs', ], -} - - -def check_positive_int(value): - import argparse - - try: - val = int(value) - except ValueError as e: - raise argparse.ArgumentTypeError( - "{} is invalid int value".format(value)) - if val <= 0: - raise argparse.ArgumentTypeError( - "{} is invalid positive int value".format(val)) - return val - - -def check_beta(args_dict): - if 'beta' not in args_dict: - args_dict['beta'] = False - # Check only if beta is not enabled: if beta option is specified then - # raise error. - if not args_dict['beta']: - cmd = args_dict['command'] - # first check if command is beta - if cmd in BETA_COMMANDS: - raise cdist.CdistBetaRequired(cmd) - # then check if command's argument is beta - if cmd in BETA_ARGS: - for arg in BETA_ARGS[cmd]: - if arg in args_dict and args_dict[arg]: - raise cdist.CdistBetaRequired(cmd, arg) - - -_verbosity_level = { - 0: logging.ERROR, - 1: logging.WARNING, - 2: logging.INFO, -} -_verbosity_level = collections.defaultdict( - lambda: logging.DEBUG, _verbosity_level) - def commandline(): """Parse command line""" - import argparse + import cdist.argparse import cdist.banner import cdist.config import cdist.install import cdist.shell import shutil import os - import multiprocessing - - # Construct parser others can reuse - parser = {} - # Options _all_ parsers have in common - parser['loglevel'] = argparse.ArgumentParser(add_help=False) - parser['loglevel'].add_argument( - '-d', '--debug', - help=('Set log level to debug (deprecated, use -vvv instead)'), - action='store_true', default=False) - parser['loglevel'].add_argument( - '-v', '--verbose', - help=('Increase log level, be more verbose. Use it more than once ' - 'to increase log level. The order of levels from the lowest ' - 'to the highest are: ERROR, WARNING, INFO, DEBUG.'), - action='count', default=0) - - # Main subcommand parser - parser['main'] = argparse.ArgumentParser( - description='cdist ' + cdist.VERSION, parents=[parser['loglevel']]) - parser['main'].add_argument( - '-V', '--version', help='Show version', action='version', - version='%(prog)s ' + cdist.VERSION) - parser['sub'] = parser['main'].add_subparsers( - title="Commands", dest="command") - - # Banner - parser['banner'] = parser['sub'].add_parser( - 'banner', parents=[parser['loglevel']]) - parser['banner'].set_defaults(func=cdist.banner.banner) - - # Config - parser['config'] = parser['sub'].add_parser( - 'config', parents=[parser['loglevel']]) - parser['config'].add_argument( - 'host', nargs='*', help='host(s) to operate on') - parser['config'].add_argument( - '-b', '--enable-beta', - help=('Enable beta functionalities. Beta functionalities ' - 'include the following options: -j/--jobs.'), - action='store_true', dest='beta', default=False) - parser['config'].add_argument( - '-c', '--conf-dir', - help=('Add configuration directory (can be repeated, ' - 'last one wins)'), action='append') - parser['config'].add_argument( - '-f', '--file', - help=('Read additional hosts to operate on from specified file ' - 'or from stdin if \'-\' (each host on separate line). ' - 'If no host or host file is specified then, by default, ' - 'read hosts from stdin.'), - dest='hostfile', required=False) - parser['config'].add_argument( - '-i', '--initial-manifest', - help='Path to a cdist manifest or \'-\' to read from stdin.', - dest='manifest', required=False) - parser['config'].add_argument( - '-j', '--jobs', nargs='?', type=check_positive_int, - help=('Specify the maximum number of parallel jobs, currently ' - 'only global explorers are supported (currently in beta'), - action='store', dest='jobs', - const=multiprocessing.cpu_count()) - parser['config'].add_argument( - '-n', '--dry-run', - help='Do not execute code', action='store_true') - parser['config'].add_argument( - '-o', '--out-dir', - help='Directory to save cdist output in', dest="out_path") - parser['config'].add_argument( - '-p', '--parallel', - help='Operate on multiple hosts in parallel', - action='store_true', dest='parallel') - parser['config'].add_argument( - '-s', '--sequential', - help='Operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') - # remote-copy and remote-exec defaults are environment variables - # if set; if not then None - these will be futher handled after - # parsing to determine implementation default - parser['config'].add_argument( - '--remote-copy', - help='Command to use for remote copy (should behave like scp)', - action='store', dest='remote_copy', - default=os.environ.get('CDIST_REMOTE_COPY')) - parser['config'].add_argument( - '--remote-exec', - help=('Command to use for remote execution ' - '(should behave like ssh)'), - action='store', dest='remote_exec', - default=os.environ.get('CDIST_REMOTE_EXEC')) - parser['config'].set_defaults(func=cdist.config.Config.commandline) - - # Install - parser['install'] = parser['sub'].add_parser('install', add_help=False, - parents=[parser['config']]) - parser['install'].set_defaults(func=cdist.install.Install.commandline) - - # Shell - parser['shell'] = parser['sub'].add_parser( - 'shell', parents=[parser['loglevel']]) - parser['shell'].add_argument( - '-s', '--shell', - help=('Select shell to use, defaults to current shell. Used shell' - ' should be POSIX compatible shell.')) - parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) - - for p in parser: - parser[p].epilog = ( - "Get cdist at http://www.nico.schottelius.org/software/cdist/") + parser = cdist.argparse.get_parsers() args = parser['main'].parse_args(sys.argv[1:]) # Loglevels are handled globally in here - if args.debug: - log.warning("-d/--debug is deprecated, use -vvv instead") - args.verbose = 3 - - logging.root.setLevel(_verbosity_level[args.verbose]) + retval = cdist.argparse.handle_loglevel(args) + if retval: + log.warning(retval) log.debug(args) log.info("version %s" % cdist.VERSION) @@ -219,17 +62,16 @@ def commandline(): parser['main'].print_help() sys.exit(0) - check_beta(vars(args)) + cdist.argparse.check_beta(vars(args)) args.func(args) if __name__ == "__main__": - # Sys is needed for sys.exit() import sys cdistpythonversion = '3.2' if sys.version < cdistpythonversion: - print('Python >= ' + cdistpythonversion + - ' is required on the source host.', file=sys.stderr) + print('Python >= {} is required on the source host.'.format( + cdistpythonversion), file=sys.stderr) sys.exit(1) exit_code = 0 From 2999f1269873245733a612aac82c6e768eba7663 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Dec 2016 18:29:10 +0100 Subject: [PATCH 0377/1332] chmod +x --- scripts/cdist | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/cdist diff --git a/scripts/cdist b/scripts/cdist old mode 100644 new mode 100755 From 609977b7ff8d5659622f3fff8494b8fd8b9aa427 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 4 Dec 2016 20:27:42 +0100 Subject: [PATCH 0378/1332] ugly->bad --- cdist/__init__.py | 4 +- cdist/core/explorer.py | 11 ++--- cdist/exec/remote.py | 80 +++++++++++++++++---------------- cdist/test/exec/remote.py | 4 +- docs/src/cdist-reference.rst.sh | 3 ++ docs/src/man1/cdist.rst | 3 ++ 6 files changed, 54 insertions(+), 51 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index b6f5c8cb..c142230c 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -68,13 +68,13 @@ class CdistBetaRequired(cdist.Error): err_msg = ("\'{}\' command is beta, but beta is " "not enabled. If you want to use it please enable beta " "functionalities by using the -b/--enable-beta command " - "line flag.") + "line flag or setting CDIST_BETA env var.") fmt_args = [self.command, ] else: err_msg = ("\'{}\' argument of \'{}\' command is beta, but beta " "is not enabled. If you want to use it please enable " "beta functionalities by using the -b/--enable-beta " - "command line flag.") + "command line flag or setting CDIST_BETA env var.") fmt_args = [self.arg, self.command, ] return err_msg.format(*fmt_args) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index ef85431c..23996240 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -149,14 +149,9 @@ class Explorer(object): def transfer_global_explorers(self): """Transfer the global explorers to the remote side.""" self.remote.mkdir(self.remote.global_explorer_path) - if self.jobs is None: - self.remote.transfer(self.local.global_explorer_path, - self.remote.global_explorer_path) - else: - self.remote.transfer_dir_parallel( - self.local.global_explorer_path, - self.remote.global_explorer_path, - self.jobs) + self.remote.transfer(self.local.global_explorer_path, + self.remote.global_explorer_path, + self.jobs) self.remote.run(["chmod", "0700", "%s/*" % (self.remote.global_explorer_path)]) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 74a33f73..440aafa7 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -118,57 +118,59 @@ class Remote(object): self.log.debug("Remote mkdir: %s", path) self.run(["mkdir", "-p", path]) - def transfer(self, source, destination): + def transfer(self, source, destination, jobs=None): """Transfer a file or directory to the remote side.""" self.log.debug("Remote transfer: %s -> %s", source, destination) self.rmdir(destination) if os.path.isdir(source): self.mkdir(destination) - for f in glob.glob1(source, '*'): - command = self._copy.split() - path = os.path.join(source, f) - command.extend([path, '{0}:{1}'.format( - _wrap_addr(self.target_host[0]), destination)]) - self._run_command(command) + if jobs: + self._transfer_dir_parallel(source, destination, jobs) + else: + self._transfer_dir_sequential(source, destination) + elif jobs: + raise cdist.Error("Source {} is not a directory".format(source)) else: command = self._copy.split() command.extend([source, '{0}:{1}'.format( _wrap_addr(self.target_host[0]), destination)]) self._run_command(command) - def transfer_dir_parallel(self, source, destination, jobs): - """Transfer a directory to the remote side in parallel mode.""" - self.log.debug("Remote transfer: %s -> %s", source, destination) - self.rmdir(destination) - if os.path.isdir(source): - self.mkdir(destination) - self.log.info("Remote transfer in {} parallel jobs".format( - jobs)) - self.log.debug("Multiprocessing start method is {}".format( - multiprocessing.get_start_method())) - self.log.debug(("Starting multiprocessing Pool for parallel " - "remote transfer")) - with multiprocessing.Pool(jobs) as pool: - self.log.debug("Starting async for parallel transfer") - commands = [] - for f in glob.glob1(source, '*'): - command = self._copy.split() - path = os.path.join(source, f) - command.extend([path, '{0}:{1}'.format( - _wrap_addr(self.target_host[0]), destination)]) - commands.append(command) - results = [ - pool.apply_async(self._run_command, (cmd,)) - for cmd in commands - ] + def _transfer_dir_sequential(self, source, destination): + for f in glob.glob1(source, '*'): + command = self._copy.split() + path = os.path.join(source, f) + command.extend([path, '{0}:{1}'.format( + _wrap_addr(self.target_host[0]), destination)]) + self._run_command(command) - self.log.debug("Waiting async results for parallel transfer") - for r in results: - r.get() # self._run_command returns None - self.log.debug(("Multiprocessing for parallel transfer " - "finished")) - else: - raise cdist.Error("Source {} is not a directory".format(source)) + def _transfer_dir_parallel(self, source, destination, jobs): + """Transfer a directory to the remote side in parallel mode.""" + self.log.info("Remote transfer in {} parallel jobs".format( + jobs)) + self.log.debug("Multiprocessing start method is {}".format( + multiprocessing.get_start_method())) + self.log.debug(("Starting multiprocessing Pool for parallel " + "remote transfer")) + with multiprocessing.Pool(jobs) as pool: + self.log.debug("Starting async for parallel transfer") + commands = [] + for f in glob.glob1(source, '*'): + command = self._copy.split() + path = os.path.join(source, f) + command.extend([path, '{0}:{1}'.format( + _wrap_addr(self.target_host[0]), destination)]) + commands.append(command) + results = [ + pool.apply_async(self._run_command, (cmd,)) + for cmd in commands + ] + + self.log.debug("Waiting async results for parallel transfer") + for r in results: + r.get() # self._run_command returns None + self.log.debug(("Multiprocessing for parallel transfer " + "finished")) def run_script(self, script, env=None, return_output=False): """Run the given script with the given environment on the remote side. diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 45dabb18..371d17e3 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -136,8 +136,8 @@ class RemoteTestCase(test.CdistTestCase): source_file_name = os.path.split(source_file)[-1] filenames.append(source_file_name) target = self.mkdtemp(dir=self.temp_dir) - self.remote.transfer_dir_parallel(source, target, - multiprocessing.cpu_count()) + self.remote.transfer(source, target, + multiprocessing.cpu_count()) # test if the payload files are in the target directory for filename in filenames: self.assertTrue(os.path.isfile(os.path.join(target, filename))) diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index 97b22473..4b94b858 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -273,4 +273,7 @@ CDIST_REMOTE_EXEC CDIST_REMOTE_COPY Use this command for remote copy (should behave like scp). + +CDIST_BETA + Enable beta functionalities. eof diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 5daedcd4..08c856b1 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -236,6 +236,9 @@ CDIST_REMOTE_EXEC CDIST_REMOTE_COPY Use this command for remote copy (should behave like scp). +CDIST_BETA + Enable beta functionalities. + EXIT STATUS ----------- The following exit values shall be returned: From 1ee6c2e7b1dbfe25d26f30a6648ce4d7f5336e1f Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Mon, 5 Dec 2016 07:57:30 +0100 Subject: [PATCH 0379/1332] added line after 33, changed experimentel to experimental --- cdist/conf/type/__docker/man.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker/man.rst b/cdist/conf/type/__docker/man.rst index 88786ad7..80088983 100644 --- a/cdist/conf/type/__docker/man.rst +++ b/cdist/conf/type/__docker/man.rst @@ -23,7 +23,7 @@ None. BOOLEAN PARAMETERS ------------------ -experimentel +experimental Install the experimentel docker-engine package instead of the latest stable release. @@ -31,6 +31,7 @@ EXAMPLES -------- .. code-block:: sh + __docker # experimentel From eb56c6ef59118a30987aa44683644f808a650b6d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 5 Dec 2016 08:53:48 +0100 Subject: [PATCH 0380/1332] experimentel -> experimental --- cdist/conf/type/__docker/man.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__docker/man.rst b/cdist/conf/type/__docker/man.rst index 80088983..42e71af5 100644 --- a/cdist/conf/type/__docker/man.rst +++ b/cdist/conf/type/__docker/man.rst @@ -24,7 +24,7 @@ None. BOOLEAN PARAMETERS ------------------ experimental - Install the experimentel docker-engine package instead of the latest stable release. + Install the experimental docker-engine package instead of the latest stable release. EXAMPLES @@ -34,7 +34,7 @@ EXAMPLES __docker - # experimentel + # experimental __docker --experimental From 0f175bc65a184a89f6b82556bbf71e7c3f3c1ef5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 5 Dec 2016 08:53:59 +0100 Subject: [PATCH 0381/1332] Update changelog. --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index 168282aa..ea3c74c2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,10 @@ Changelog --------- +next: + * New type: __docker (Steven Armstrong) + * New type: __package_dpkg (Tomas Pospisek) + 4.4.0: 2016-12-03 * Core: Deprecate -d option and make -v option log level counter (Darko Poljak) * New type: __postgres_extension (Tomas Pospisek) From 6c1b215db8a78a3ae5a9bad036c605bd5fcc3aee Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 6 Dec 2016 14:27:17 +0100 Subject: [PATCH 0382/1332] Begin parallelizing object prepare and run. --- cdist/config.py | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index b1a120ca..42dd73b8 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -27,6 +27,7 @@ import time import itertools import tempfile import socket +import concurrent.futures import cdist import cdist.hostsource @@ -265,13 +266,14 @@ class Config(object): else: yield cdist_object - def iterate_once(self): + def iterate_once_parallel(self): """ Iterate over the objects once - helper method for iterate_until_finished """ objects_changed = False + cargo = [] for cdist_object in self.object_list(): if cdist_object.requirements_unfinished(cdist_object.requirements): """We cannot do anything for this poor object""" @@ -280,18 +282,38 @@ class Config(object): if cdist_object.state == core.CdistObject.STATE_UNDEF: """Prepare the virgin object""" - self.object_prepare(cdist_object) - objects_changed = True + # self.object_prepare(cdist_object) + # objects_changed = True + cargo.append(cdist_object) - if cdist_object.requirements_unfinished(cdist_object.autorequire): - """The previous step created objects we depend on - - wait for them - """ + if cargo: + with concurrent.futures.ProcessPoolExecutor(self.jobs) as executor: + for x in executor.map(self.object_prepare, cargo): + pass # returns None + objects_changed = True + + cargo.clear() + for cdist_object in self.object_list(): + if cdist_object.requirements_unfinished(cdist_object.requirements): + """We cannot do anything for this poor object""" continue if cdist_object.state == core.CdistObject.STATE_PREPARED: - self.object_run(cdist_object) - objects_changed = True + if cdist_object.requirements_unfinished(cdist_object.autorequire): + """The previous step created objects we depend on - + wait for them + """ + continue + + # self.object_run(cdist_object) + # objects_changed = True + cargo.append(cdist_object) + + if cargo: + with concurrent.futures.ProcessPoolExecutor(self.jobs) as executor: + for x in executor.map(self.object_run, cargo): + pass # returns None + objects_changed = True return objects_changed @@ -304,7 +326,8 @@ class Config(object): objects_changed = True while objects_changed: - objects_changed = self.iterate_once() + if self.jobs: + objects_changed = self.iterate_once_parallel() # Check whether all objects have been finished unfinished_objects = [] From 3e763e9e6c9c07398df10510b11e1167f755d764 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 7 Dec 2016 18:36:19 +0100 Subject: [PATCH 0383/1332] list -> set for beta commands and args --- cdist/argparse.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index cef3dd5f..04f6e6a4 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -6,11 +6,11 @@ import logging import collections -# list of beta sub-commands -BETA_COMMANDS = ['install', ] -# list of beta arguments for sub-commands +# set of beta sub-commands +BETA_COMMANDS = set(('install', )) +# set of beta arguments for sub-commands BETA_ARGS = { - 'config': ['jobs', ], + 'config': set(('jobs', )), } EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/" # Parser others can reuse @@ -27,8 +27,7 @@ _verbosity_level = collections.defaultdict( def add_beta_command(cmd): - if cmd not in BETA_COMMANDS: - BETA_COMMANDS.append(cmd) + BETA_COMMANDS.add(cmd) def add_beta_arg(cmd, arg): @@ -36,7 +35,7 @@ def add_beta_arg(cmd, arg): if arg not in BETA_ARGS[cmd]: BETA_ARGS[cmd].append(arg) else: - BETA_ARGS[cmd] = [arg, ] + BETA_ARGS[cmd] = set((arg, )) def check_beta(args_dict): From 341de216a63e8ae2922fa3aa375026a65d8f52e3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 7 Dec 2016 18:39:43 +0100 Subject: [PATCH 0384/1332] Fix missing vars. --- cdist/config.py | 3 ++- cdist/hostsource.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index b1a120ca..6b57e7bf 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -200,7 +200,8 @@ class Config(object): log = logging.getLogger(host) try: - remote_exec, remote_copy = cls._resolve_remote_cmds(host_base_path) + remote_exec, remote_copy = cls._resolve_remote_cmds( + args, host_base_path) log.debug("remote_exec for host \"{}\": {}".format( host, remote_exec)) log.debug("remote_copy for host \"{}\": {}".format( diff --git a/cdist/hostsource.py b/cdist/hostsource.py index 8170536c..9c2c0616 100644 --- a/cdist/hostsource.py +++ b/cdist/hostsource.py @@ -60,7 +60,7 @@ class HostSource(object): yield host def hosts(self): - if not source: + if not self.source: return if isinstance(self.source, str): From 1952d43073f571ec0b4c1bb19d8203876866fab8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 7 Dec 2016 19:06:51 +0100 Subject: [PATCH 0385/1332] Initial try for parallelization. --- cdist/config.py | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index a20a4840..f3faa03a 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -267,11 +267,44 @@ class Config(object): else: yield cdist_object - def iterate_once_parallel(self): + def iterate_once(self): """ Iterate over the objects once - helper method for iterate_until_finished """ + if self.jobs: + objects_changed = self._iterate_once_parallel() + else: + objects_changed = self._iterate_once_sequential() + return objects_changed + + def _iterate_once_sequential(self): + objects_changed = False + + for cdist_object in self.object_list(): + if cdist_object.requirements_unfinished(cdist_object.requirements): + """We cannot do anything for this poor object""" + continue + + if cdist_object.state == core.CdistObject.STATE_UNDEF: + """Prepare the virgin object""" + + self.object_prepare(cdist_object) + objects_changed = True + + if cdist_object.requirements_unfinished(cdist_object.autorequire): + """The previous step created objects we depend on - + wait for them + """ + continue + + if cdist_object.state == core.CdistObject.STATE_PREPARED: + self.object_run(cdist_object) + objects_changed = True + + return objects_changed + + def _iterate_once_parallel(self): objects_changed = False cargo = [] @@ -300,7 +333,8 @@ class Config(object): continue if cdist_object.state == core.CdistObject.STATE_PREPARED: - if cdist_object.requirements_unfinished(cdist_object.autorequire): + if cdist_object.requirements_unfinished( + cdist_object.autorequire): """The previous step created objects we depend on - wait for them """ @@ -327,8 +361,7 @@ class Config(object): objects_changed = True while objects_changed: - if self.jobs: - objects_changed = self.iterate_once_parallel() + objects_changed = self.iterate_once() # Check whether all objects have been finished unfinished_objects = [] From d17c517a0c220213ea343bf1926a6ff4d8d7dc37 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 7 Dec 2016 22:43:53 +0100 Subject: [PATCH 0386/1332] enable-beta -> beta --- cdist/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index c142230c..6ea02d41 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -67,13 +67,13 @@ class CdistBetaRequired(cdist.Error): if self.arg is None: err_msg = ("\'{}\' command is beta, but beta is " "not enabled. If you want to use it please enable beta " - "functionalities by using the -b/--enable-beta command " + "functionalities by using the -b/--beta command " "line flag or setting CDIST_BETA env var.") fmt_args = [self.command, ] else: err_msg = ("\'{}\' argument of \'{}\' command is beta, but beta " "is not enabled. If you want to use it please enable " - "beta functionalities by using the -b/--enable-beta " + "beta functionalities by using the -b/--beta " "command line flag or setting CDIST_BETA env var.") fmt_args = [self.arg, self.command, ] return err_msg.format(*fmt_args) From 6d765c1ff728098d5570118015bbb21fe0ea4e0f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 7 Dec 2016 23:43:03 +0100 Subject: [PATCH 0387/1332] enable-beta -> beta --- completions/bash/cdist-completion.bash | 2 +- completions/zsh/_cdist | 2 +- docs/src/man1/cdist.rst | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/completions/bash/cdist-completion.bash b/completions/bash/cdist-completion.bash index 68f45327..1c4226c2 100644 --- a/completions/bash/cdist-completion.bash +++ b/completions/bash/cdist-completion.bash @@ -36,7 +36,7 @@ _cdist() return 0 ;; config|install) - opts="-h --help -d --debug -v --verbose -b --enable-beta \ + opts="-h --help -d --debug -v --verbose -b --beta \ -c --conf-dir -f --file -i --initial-manifest -j --jobs \ -n --dry-run -o --out-dir -p --parallel -s --sequential \ --remote-copy --remote-exec" diff --git a/completions/zsh/_cdist b/completions/zsh/_cdist index dc320224..001356d4 100644 --- a/completions/zsh/_cdist +++ b/completions/zsh/_cdist @@ -36,7 +36,7 @@ _cdist() esac ;; config|install) - opts=(-h --help -d --debug -v --verbose -b --enable-beta -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -s --sequential --remote-copy --remote-exec) + opts=(-h --help -d --debug -v --verbose -b --beta -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -s --sequential --remote-copy --remote-exec) compadd "$@" -- $opts ;; *) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 08c856b1..55901300 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -69,10 +69,11 @@ CONFIG/INSTALL -------------- Configure/install one or more hosts. -.. option:: -b, --enable-beta +.. option:: -b, --beta - Enable beta functionalities. Beta functionalities include the - following options: -j/--jobs. + Enable beta functionalities. + + Can also be enabled using CDIST_BETA env var. .. option:: -c CONF_DIR, --conf-dir CONF_DIR From ca3a8ddf67f060414ed3f065791821bd086c3267 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 8 Dec 2016 00:47:07 +0100 Subject: [PATCH 0388/1332] no clear() in python < 3.3; if only one then do it sequentially --- cdist/config.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index f3faa03a..655153be 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -320,13 +320,16 @@ class Config(object): # objects_changed = True cargo.append(cdist_object) - if cargo: + if len(cargo) == 1: + self.object_prepare(cargo[0]) + objects_changed = True + elif cargo: with concurrent.futures.ProcessPoolExecutor(self.jobs) as executor: for x in executor.map(self.object_prepare, cargo): pass # returns None objects_changed = True - cargo.clear() + del cargo[:] for cdist_object in self.object_list(): if cdist_object.requirements_unfinished(cdist_object.requirements): """We cannot do anything for this poor object""" @@ -344,7 +347,10 @@ class Config(object): # objects_changed = True cargo.append(cdist_object) - if cargo: + if len(cargo) == 1: + self.object_run(cargo[0]) + objects_changed = True + elif cargo: with concurrent.futures.ProcessPoolExecutor(self.jobs) as executor: for x in executor.map(self.object_run, cargo): pass # returns None From e6b9fc90bac30090f8ef19512b586770b704767f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 8 Dec 2016 14:11:30 +0100 Subject: [PATCH 0389/1332] Add log messages. --- cdist/config.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 655153be..111fa233 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -279,6 +279,7 @@ class Config(object): return objects_changed def _iterate_once_sequential(self): + self.log.info("Iteration in sequential mode") objects_changed = False for cdist_object in self.object_list(): @@ -305,6 +306,8 @@ class Config(object): return objects_changed def _iterate_once_parallel(self): + self.log.info("Iteration in parallel mode in {} jobs".format( + self.jobs)) objects_changed = False cargo = [] @@ -320,13 +323,17 @@ class Config(object): # objects_changed = True cargo.append(cdist_object) - if len(cargo) == 1: + n = len(cargo) + if n == 1: + self.log.debug("Only one object, preparing sequentially") self.object_prepare(cargo[0]) objects_changed = True elif cargo: + self.log.debug("Preparing {} objects in parallel".format(n)) with concurrent.futures.ProcessPoolExecutor(self.jobs) as executor: for x in executor.map(self.object_prepare, cargo): pass # returns None + self.log.debug("Preparation finished") objects_changed = True del cargo[:] @@ -347,13 +354,17 @@ class Config(object): # objects_changed = True cargo.append(cdist_object) - if len(cargo) == 1: + n = len(cargo) + if n == 1: + self.log.debug("Only one object, running sequentially") self.object_run(cargo[0]) objects_changed = True elif cargo: + self.log.debug("Running {} objects in parallel".format(n)) with concurrent.futures.ProcessPoolExecutor(self.jobs) as executor: for x in executor.map(self.object_run, cargo): pass # returns None + self.log.debug("Running finished") objects_changed = True return objects_changed From 8776a2ee067e6254fd87290cef21bf5f2b669edb Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 8 Dec 2016 17:36:57 +0100 Subject: [PATCH 0390/1332] concurrent.futures -> multiprocessing --- cdist/config.py | 65 ++++++++++++++++++++++++++++++++-------- cdist/core/cdist_type.py | 3 ++ cdist/core/manifest.py | 17 ++++++++++- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 111fa233..ae63531d 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -27,7 +27,7 @@ import time import itertools import tempfile import socket -import concurrent.futures +import multiprocessing import cdist import cdist.hostsource @@ -47,7 +47,7 @@ class Config(object): self.local = local self.remote = remote - self.log = logging.getLogger(self.local.target_host[0]) + self._open_logger() self.dry_run = dry_run self.jobs = jobs @@ -123,7 +123,6 @@ class Config(object): @classmethod def commandline(cls, args): """Configure remote system""" - import multiprocessing # FIXME: Refactor relict - remove later log = logging.getLogger("cdist") @@ -329,11 +328,24 @@ class Config(object): self.object_prepare(cargo[0]) objects_changed = True elif cargo: - self.log.debug("Preparing {} objects in parallel".format(n)) - with concurrent.futures.ProcessPoolExecutor(self.jobs) as executor: - for x in executor.map(self.object_prepare, cargo): - pass # returns None - self.log.debug("Preparation finished") + self.log.debug("Multiprocessing start method is {}".format( + multiprocessing.get_start_method())) + self.log.debug(("Starting multiprocessing Pool for {} parallel " + "objects preparation".format(n))) + with multiprocessing.Pool(self.jobs) as pool: + self.log.debug(("Starting async for parallel object " + "preparation")) + results = [ + pool.apply_async(self.object_prepare, (c,)) + for c in cargo + ] + + self.log.debug(("Waiting async results for parallel object " + "preparation")) + for r in results: + r.get() + self.log.debug(("Multiprocessing for parallel object " + "preparation finished")) objects_changed = True del cargo[:] @@ -360,15 +372,42 @@ class Config(object): self.object_run(cargo[0]) objects_changed = True elif cargo: - self.log.debug("Running {} objects in parallel".format(n)) - with concurrent.futures.ProcessPoolExecutor(self.jobs) as executor: - for x in executor.map(self.object_run, cargo): - pass # returns None - self.log.debug("Running finished") + self.log.debug("Multiprocessing start method is {}".format( + multiprocessing.get_start_method())) + self.log.debug(("Starting multiprocessing Pool for {} parallel " + "object run".format(n))) + with multiprocessing.Pool(self.jobs) as pool: + self.log.debug(("Starting async for parallel object run")) + results = [ + pool.apply_async(self.object_run, (c,)) + for c in cargo + ] + + self.log.debug(("Waiting async results for parallel object " + "run")) + for r in results: + r.get() + self.log.debug(("Multiprocessing for parallel object " + "run finished")) objects_changed = True return objects_changed + def _open_logger(self): + self.log = logging.getLogger(self.local.target_host[0]) + + # logger is not pickable, so remove it when we pickle + def __getstate__(self): + state = self.__dict__.copy() + if 'log' in state: + del state['log'] + return state + + # recreate logger when we unpickle + def __setstate__(self, state): + self.__dict__.update(state) + self._open_logger() + def iterate_until_finished(self): """ Go through all objects and solve them diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index a548f365..14865386 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -79,6 +79,9 @@ class CdistType(object): _instances = {} + def __getnewargs__(self): + return self.base_path, self.name + def __new__(cls, *args, **kwargs): """only one instance of each named type may exist""" # name is second argument diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index a16e9346..92a16190 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -98,7 +98,7 @@ class Manifest(object): self.target_host = target_host self.local = local - self.log = logging.getLogger(self.target_host[0]) + self._open_logger() self.env = { 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), @@ -114,6 +114,21 @@ class Manifest(object): if self.log.getEffectiveLevel() == logging.DEBUG: self.env.update({'__cdist_debug': "yes"}) + def _open_logger(self): + self.log = logging.getLogger(self.target_host[0]) + + # logger is not pickable, so remove it when we pickle + def __getstate__(self): + state = self.__dict__.copy() + if 'log' in state: + del state['log'] + return state + + # recreate logger when we unpickle + def __setstate__(self, state): + self.__dict__.update(state) + self._open_logger() + def env_initial_manifest(self, initial_manifest): env = os.environ.copy() env.update(self.env) From b0911ab87d2444a1cfad050ec48c308abc332d4b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 8 Dec 2016 20:04:17 +0100 Subject: [PATCH 0391/1332] Improve __apt_mark (Ander Punnar from beta) --- .../conf/type/__apt_mark/explorer/apt_version | 31 +++++++++++++++++++ .../__apt_mark/explorer/package_installed | 30 ++++++++++++++++++ cdist/conf/type/__apt_mark/gencode-remote | 13 ++++++++ docs/changelog | 1 + 4 files changed, 75 insertions(+) create mode 100644 cdist/conf/type/__apt_mark/explorer/apt_version create mode 100644 cdist/conf/type/__apt_mark/explorer/package_installed diff --git a/cdist/conf/type/__apt_mark/explorer/apt_version b/cdist/conf/type/__apt_mark/explorer/apt_version new file mode 100644 index 00000000..32a0a58f --- /dev/null +++ b/cdist/conf/type/__apt_mark/explorer/apt_version @@ -0,0 +1,31 @@ +#!/bin/sh +# +# 2016 Ander Punnar (cdist at kvlt.ee) +# +# 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 . +# + +apt_version_is=$(dpkg-query --show --showformat '${Version}' apt) + +# from APT changelog: +# apt (0.8.14.2) UNRELEASED; urgency=low +# provide a 'dpkg --set-selections' wrapper to set/release holds + +apt_version_should=0.8.14.2 + +dpkg --compare-versions $apt_version_should le $apt_version_is \ + && echo 0 \ + || echo 1 diff --git a/cdist/conf/type/__apt_mark/explorer/package_installed b/cdist/conf/type/__apt_mark/explorer/package_installed new file mode 100644 index 00000000..c78ac3a9 --- /dev/null +++ b/cdist/conf/type/__apt_mark/explorer/package_installed @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2016 Ander Punnar (cdist at kvlt.ee) +# +# 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/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +dpkg-query --show --showformat '${Status}' $name 2>/dev/null \ + | grep -q 'ok installed' \ + && echo 0 \ + || echo 1 diff --git a/cdist/conf/type/__apt_mark/gencode-remote b/cdist/conf/type/__apt_mark/gencode-remote index 14505809..c1ac58b3 100644 --- a/cdist/conf/type/__apt_mark/gencode-remote +++ b/cdist/conf/type/__apt_mark/gencode-remote @@ -24,6 +24,19 @@ else name="$__object_id" fi +apt_version="$(cat "$__object/explorer/apt_version")" + +if [ "$apt_version" != '0' ]; then + echo 'APT version not supported' >&2 + exit 1 +fi + +package_installed="$(cat "$__object/explorer/package_installed")" + +if [ "$package_installed" != '0' ]; then + exit 0 +fi + state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" diff --git a/docs/changelog b/docs/changelog index ea3c74c2..41fc1ca9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Type __apt_mark: check supported apt version and if package is installed (Ander Punnar) * New type: __docker (Steven Armstrong) * New type: __package_dpkg (Tomas Pospisek) From a9cd6dc7c2f3ccb18a1623a1b05c51001da62a78 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 8 Dec 2016 20:08:08 +0100 Subject: [PATCH 0392/1332] Fix changelog style --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 41fc1ca9..f0b296cc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,7 +2,7 @@ Changelog --------- next: - * Type __apt_mark: check supported apt version and if package is installed (Ander Punnar) + * Type __apt_mark: Check supported apt version and if package is installed (Ander Punnar) * New type: __docker (Steven Armstrong) * New type: __package_dpkg (Tomas Pospisek) From e5a6599ccb2173a944adc5ac46ad98e7760de0f4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 8 Dec 2016 21:48:59 +0100 Subject: [PATCH 0393/1332] Create mp_pool_run helper function for running in parallel. --- cdist/config.py | 40 ++++++++++++----------------------- cdist/core/explorer.py | 21 ++++++------------ cdist/exec/remote.py | 30 ++++++++++---------------- cdist/mputil.py | 48 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 60 deletions(-) create mode 100644 cdist/mputil.py diff --git a/cdist/config.py b/cdist/config.py index ae63531d..a47811a9 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -28,6 +28,7 @@ import itertools import tempfile import socket import multiprocessing +from cdist.mputil import mp_pool_run import cdist import cdist.hostsource @@ -332,20 +333,12 @@ class Config(object): multiprocessing.get_start_method())) self.log.debug(("Starting multiprocessing Pool for {} parallel " "objects preparation".format(n))) - with multiprocessing.Pool(self.jobs) as pool: - self.log.debug(("Starting async for parallel object " - "preparation")) - results = [ - pool.apply_async(self.object_prepare, (c,)) - for c in cargo - ] - - self.log.debug(("Waiting async results for parallel object " - "preparation")) - for r in results: - r.get() - self.log.debug(("Multiprocessing for parallel object " - "preparation finished")) + args = [ + (c, ) for c in cargo + ] + mp_pool_run(self.object_prepare, args, jobs=self.jobs) + self.log.debug(("Multiprocessing for parallel object " + "preparation finished")) objects_changed = True del cargo[:] @@ -376,19 +369,12 @@ class Config(object): multiprocessing.get_start_method())) self.log.debug(("Starting multiprocessing Pool for {} parallel " "object run".format(n))) - with multiprocessing.Pool(self.jobs) as pool: - self.log.debug(("Starting async for parallel object run")) - results = [ - pool.apply_async(self.object_run, (c,)) - for c in cargo - ] - - self.log.debug(("Waiting async results for parallel object " - "run")) - for r in results: - r.get() - self.log.debug(("Multiprocessing for parallel object " - "run finished")) + args = [ + (c, ) for c in cargo + ] + mp_pool_run(self.object_run, args, jobs=self.jobs) + self.log.debug(("Multiprocessing for parallel object " + "run finished")) objects_changed = True return objects_changed diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 23996240..45afc5c0 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -24,8 +24,7 @@ import logging import os import glob import multiprocessing - -import cdist +from cdist.mputil import mp_pool_run ''' common: @@ -121,18 +120,12 @@ class Explorer(object): multiprocessing.get_start_method())) self.log.debug(("Starting multiprocessing Pool for global " "explorers run")) - with multiprocessing.Pool(self.jobs) as pool: - self.log.debug("Starting async for global explorer run") - results = [ - pool.apply_async(self._run_global_explorer, (e, out_path,)) - for e in self.list_global_explorer_names() - ] - - self.log.debug("Waiting async results for global explorer runs") - for r in results: - r.get() # self._run_global_explorer returns None - self.log.debug(("Multiprocessing run for global explorers " - "finished")) + args = [ + (e, out_path, ) for e in self.list_global_explorer_names() + ] + mp_pool_run(self._run_global_explorer, args, jobs=self.jobs) + self.log.debug(("Multiprocessing run for global explorers " + "finished")) # logger is not pickable, so remove it when we pickle def __getstate__(self): diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 440aafa7..042b7103 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -31,6 +31,7 @@ import multiprocessing import cdist import cdist.exec.util as exec_util import cdist.util.ipaddr as ipaddr +from cdist.mputil import mp_pool_run def _wrap_addr(addr): @@ -152,25 +153,16 @@ class Remote(object): multiprocessing.get_start_method())) self.log.debug(("Starting multiprocessing Pool for parallel " "remote transfer")) - with multiprocessing.Pool(jobs) as pool: - self.log.debug("Starting async for parallel transfer") - commands = [] - for f in glob.glob1(source, '*'): - command = self._copy.split() - path = os.path.join(source, f) - command.extend([path, '{0}:{1}'.format( - _wrap_addr(self.target_host[0]), destination)]) - commands.append(command) - results = [ - pool.apply_async(self._run_command, (cmd,)) - for cmd in commands - ] - - self.log.debug("Waiting async results for parallel transfer") - for r in results: - r.get() # self._run_command returns None - self.log.debug(("Multiprocessing for parallel transfer " - "finished")) + args = [] + for f in glob.glob1(source, '*'): + command = self._copy.split() + path = os.path.join(source, f) + command.extend([path, '{0}:{1}'.format( + _wrap_addr(self.target_host[0]), destination)]) + args.append((command, )) + mp_pool_run(self._run_command, args, jobs=jobs) + self.log.debug(("Multiprocessing for parallel transfer " + "finished")) def run_script(self, script, env=None, return_output=False): """Run the given script with the given environment on the remote side. diff --git a/cdist/mputil.py b/cdist/mputil.py new file mode 100644 index 00000000..24289df2 --- /dev/null +++ b/cdist/mputil.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# +# 2016 Darko Poljak (darko.poljak 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 . +# +# + + +import multiprocessing +import itertools + + +def mp_pool_run(func, args=None, kwds=None, jobs=multiprocessing.cpu_count()): + """ Run func using multiprocessing.Pool with jobs jobs and supplied + iterable of args and kwds with one entry for each parallel func + instance. + Return list of results. + """ + if args and kwds: + fargs = zip(args, kdws) + elif args: + fargs = zip(args, itertools.repeat({})) + elif kwds: + fargs = zip(itertools.repeat(()), kwds) + else: + return [func(), ] + + with multiprocessing.Pool(jobs) as pool: + results = [ + pool.apply_async(func, a, k) + for a, k in fargs + ] + retval = [r.get() for r in results] + return retval From 8d2d538660c4812e170bc63a622910cda5d4a582 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 11 Dec 2016 21:17:22 +0100 Subject: [PATCH 0394/1332] Fix typo. --- cdist/mputil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/mputil.py b/cdist/mputil.py index 24289df2..e564d749 100644 --- a/cdist/mputil.py +++ b/cdist/mputil.py @@ -31,7 +31,7 @@ def mp_pool_run(func, args=None, kwds=None, jobs=multiprocessing.cpu_count()): Return list of results. """ if args and kwds: - fargs = zip(args, kdws) + fargs = zip(args, kwds) elif args: fargs = zip(args, itertools.repeat({})) elif kwds: From 7abb96b48d38ae7ed60981bdaa93300d7bb641fc Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Sun, 11 Dec 2016 22:12:44 +0100 Subject: [PATCH 0395/1332] Created __docker_compose type for cdist Features: - Install __docker_compose --- .../conf/type/__docker_compose/gencode-remote | 5 +++ cdist/conf/type/__docker_compose/man.rst | 45 +++++++++++++++++++ cdist/conf/type/__docker_compose/manifest | 24 ++++++++++ cdist/conf/type/__docker_compose/singleton | 0 4 files changed, 74 insertions(+) create mode 100644 cdist/conf/type/__docker_compose/gencode-remote create mode 100644 cdist/conf/type/__docker_compose/man.rst create mode 100644 cdist/conf/type/__docker_compose/manifest create mode 100644 cdist/conf/type/__docker_compose/singleton diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote new file mode 100644 index 00000000..825dc17a --- /dev/null +++ b/cdist/conf/type/__docker_compose/gencode-remote @@ -0,0 +1,5 @@ +# Download docker-compose file +echo 'curl -L "https://github.com/docker/compose/releases/download/1.9.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose' + +# Change permissions +echo 'chmod +x /usr/local/bin/docker-compose' diff --git a/cdist/conf/type/__docker_compose/man.rst b/cdist/conf/type/__docker_compose/man.rst new file mode 100644 index 00000000..2eb1b964 --- /dev/null +++ b/cdist/conf/type/__docker_compose/man.rst @@ -0,0 +1,45 @@ +cdist-type__docker_compose(7) +============================= + +NAME +---- +cdist-type__docker_compose - install docker-compose + + +DESCRIPTION +----------- +Installs latest docker-compose package from dockerproject.org. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +BOOLEAN PARAMETERS +------------------ +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + __docker_compose + + +AUTHORS +------- +Dominique Roux + + +COPYING +------- +Copyright \(C) 2016 Dominique Roux. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__docker_compose/manifest b/cdist/conf/type/__docker_compose/manifest new file mode 100644 index 00000000..2ff80aca --- /dev/null +++ b/cdist/conf/type/__docker_compose/manifest @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2016 Dominique Roux (dominique.roux at ungleich.ch) +# +# 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 . +# +# + +# Needed packages +__docker +__package curl diff --git a/cdist/conf/type/__docker_compose/singleton b/cdist/conf/type/__docker_compose/singleton new file mode 100644 index 00000000..e69de29b From afd0d8c8c824b1c7d921d68bc7997323111c8bfd Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Mon, 12 Dec 2016 09:09:48 +0100 Subject: [PATCH 0396/1332] Added / Changed license to GPLv3+ --- .../conf/type/__docker_compose/gencode-remote | 20 +++++++++++++++++++ cdist/conf/type/__docker_compose/man.rst | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote index 825dc17a..93609172 100644 --- a/cdist/conf/type/__docker_compose/gencode-remote +++ b/cdist/conf/type/__docker_compose/gencode-remote @@ -1,3 +1,23 @@ +#!/bin/sh +# +# 2016 Dominique Roux (dominique.roux at ungleich.ch) +# +# 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 . +# + # Download docker-compose file echo 'curl -L "https://github.com/docker/compose/releases/download/1.9.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose' diff --git a/cdist/conf/type/__docker_compose/man.rst b/cdist/conf/type/__docker_compose/man.rst index 2eb1b964..4e57b156 100644 --- a/cdist/conf/type/__docker_compose/man.rst +++ b/cdist/conf/type/__docker_compose/man.rst @@ -42,4 +42,4 @@ Dominique Roux COPYING ------- Copyright \(C) 2016 Dominique Roux. Free use of this software is -granted under the terms of the GNU General Public License version 3 (GPLv3). +granted under the terms of the GNU General Public License version 3 or later (GPLv3+). From db50e2e9e28d8782d5bf87078547413babc0caa5 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Mon, 12 Dec 2016 19:43:15 +0100 Subject: [PATCH 0397/1332] Added parameter --version to define the docker-compose version --- cdist/conf/type/__docker_compose/gencode-remote | 5 ++++- cdist/conf/type/__docker_compose/parameter/default/version | 1 + cdist/conf/type/__docker_compose/parameter/optional | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 cdist/conf/type/__docker_compose/parameter/default/version create mode 100644 cdist/conf/type/__docker_compose/parameter/optional diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote index 93609172..f22823d3 100644 --- a/cdist/conf/type/__docker_compose/gencode-remote +++ b/cdist/conf/type/__docker_compose/gencode-remote @@ -18,8 +18,11 @@ # along with cdist. If not, see . # +# Variables +version="$(cat "$__object/parameter/version")" + # Download docker-compose file -echo 'curl -L "https://github.com/docker/compose/releases/download/1.9.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose' +echo 'curl -L "https://github.com/docker/compose/releases/download/'${version}'/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose' # Change permissions echo 'chmod +x /usr/local/bin/docker-compose' diff --git a/cdist/conf/type/__docker_compose/parameter/default/version b/cdist/conf/type/__docker_compose/parameter/default/version new file mode 100644 index 00000000..f8e233b2 --- /dev/null +++ b/cdist/conf/type/__docker_compose/parameter/default/version @@ -0,0 +1 @@ +1.9.0 diff --git a/cdist/conf/type/__docker_compose/parameter/optional b/cdist/conf/type/__docker_compose/parameter/optional new file mode 100644 index 00000000..088eda41 --- /dev/null +++ b/cdist/conf/type/__docker_compose/parameter/optional @@ -0,0 +1 @@ +version From f180cbcb09d42400d110ef605d44b02fbc34327b Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Tue, 13 Dec 2016 08:09:14 +0100 Subject: [PATCH 0398/1332] documented --version parameter --- cdist/conf/type/__docker_compose/man.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker_compose/man.rst b/cdist/conf/type/__docker_compose/man.rst index 4e57b156..29c47fbf 100644 --- a/cdist/conf/type/__docker_compose/man.rst +++ b/cdist/conf/type/__docker_compose/man.rst @@ -18,7 +18,8 @@ None. OPTIONAL PARAMETERS ------------------- -None. +version + Define docker_compose version. BOOLEAN PARAMETERS @@ -33,6 +34,9 @@ EXAMPLES __docker_compose + # Install version 1.9.0-rc4 + __docker_compose --version 1.9.0-rc4 + AUTHORS ------- From d6f972057e7ed5b357a1709627fef4605b2ead1c Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Tue, 13 Dec 2016 08:16:24 +0100 Subject: [PATCH 0399/1332] updated documentation --- cdist/conf/type/__docker_compose/man.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__docker_compose/man.rst b/cdist/conf/type/__docker_compose/man.rst index 29c47fbf..720a306e 100644 --- a/cdist/conf/type/__docker_compose/man.rst +++ b/cdist/conf/type/__docker_compose/man.rst @@ -8,7 +8,7 @@ cdist-type__docker_compose - install docker-compose DESCRIPTION ----------- -Installs latest docker-compose package from dockerproject.org. +Installs docker-compose package. REQUIRED PARAMETERS @@ -19,7 +19,7 @@ None. OPTIONAL PARAMETERS ------------------- version - Define docker_compose version. + Define docker_compose version, defaults to "1.9.0" BOOLEAN PARAMETERS From d597b64705a7c53908b87a6fdb3cb12cad5ebbdc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 13 Dec 2016 11:41:04 +0100 Subject: [PATCH 0400/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index f0b296cc..68be920e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * New type: __docker_compose (Dominique Roux) * Type __apt_mark: Check supported apt version and if package is installed (Ander Punnar) * New type: __docker (Steven Armstrong) * New type: __package_dpkg (Tomas Pospisek) From d9c4a062eeefa3fd275d801127819c1f4ca62f7d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 14 Dec 2016 09:08:43 +0100 Subject: [PATCH 0401/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 68be920e..ec85c50d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Type __cron: no '# marker' for raw_command due to cron security (Daniel Heule) * New type: __docker_compose (Dominique Roux) * Type __apt_mark: Check supported apt version and if package is installed (Ander Punnar) * New type: __docker (Steven Armstrong) From 2b45405898d8adb3b89e9005d21fc7bf69642191 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 16 Dec 2016 08:19:41 +0100 Subject: [PATCH 0402/1332] Update docs for types that used man.rst as symbolic links. --- cdist/conf/type/__chroot_mount/man.rst | 6 +- cdist/conf/type/__chroot_umount/man.rst | 8 +- .../conf/type/__install_chroot_mount/man.rst | 43 ++++++- .../conf/type/__install_chroot_umount/man.rst | 48 +++++++- cdist/conf/type/__install_file/man.rst | 113 +++++++++++++++++- docs/changelog | 1 + docs/src/cdist-type.rst | 25 ++++ 7 files changed, 234 insertions(+), 10 deletions(-) mode change 120000 => 100644 cdist/conf/type/__install_chroot_mount/man.rst mode change 120000 => 100644 cdist/conf/type/__install_chroot_umount/man.rst mode change 120000 => 100644 cdist/conf/type/__install_file/man.rst diff --git a/cdist/conf/type/__chroot_mount/man.rst b/cdist/conf/type/__chroot_mount/man.rst index 5ffd7de5..0d7cdce3 100644 --- a/cdist/conf/type/__chroot_mount/man.rst +++ b/cdist/conf/type/__chroot_mount/man.rst @@ -1,9 +1,9 @@ -cdist-type__install_chroot_mount(7) +cdist-type__chroot_mount(7) =================================== NAME ---- -cdist-type__install_chroot_mount - mount a chroot +cdist-type__chroot_mount - mount a chroot DESCRIPTION @@ -26,7 +26,7 @@ EXAMPLES .. code-block:: sh - __install_chroot_mount /path/to/chroot + __chroot_mount /path/to/chroot AUTHORS diff --git a/cdist/conf/type/__chroot_umount/man.rst b/cdist/conf/type/__chroot_umount/man.rst index a2ea1d9b..ff116da5 100644 --- a/cdist/conf/type/__chroot_umount/man.rst +++ b/cdist/conf/type/__chroot_umount/man.rst @@ -1,9 +1,9 @@ -cdist-type__install_chroot_umount(7) -==================================== +cdist-type__chroot_umount(7) +============================ NAME ---- -cdist-type__install_chroot_umount - unmount a chroot mounted by __chroot_mount +cdist-type__chroot_umount - unmount a chroot mounted by __chroot_mount DESCRIPTION @@ -26,7 +26,7 @@ EXAMPLES .. code-block:: sh - __install_chroot_umount /path/to/chroot + __chroot_umount /path/to/chroot SEE ALSO diff --git a/cdist/conf/type/__install_chroot_mount/man.rst b/cdist/conf/type/__install_chroot_mount/man.rst deleted file mode 120000 index 3267c3db..00000000 --- a/cdist/conf/type/__install_chroot_mount/man.rst +++ /dev/null @@ -1 +0,0 @@ -../__chroot_mount/man.rst \ No newline at end of file diff --git a/cdist/conf/type/__install_chroot_mount/man.rst b/cdist/conf/type/__install_chroot_mount/man.rst new file mode 100644 index 00000000..4054c4c4 --- /dev/null +++ b/cdist/conf/type/__install_chroot_mount/man.rst @@ -0,0 +1,42 @@ +cdist-type__install_chroot_mount(7) +=================================== + +NAME +---- +cdist-type__install_chroot_mount - mount a chroot with install command + + +DESCRIPTION +----------- +Mount and prepare a chroot for running commands within it. + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +None + + +EXAMPLES +-------- + +.. code-block:: sh + + __install_chroot_mount /path/to/chroot + + +AUTHORS +------- +Steven Armstrong + + +COPYING +------- +Copyright \(C) 2012 Steven Armstrong. 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/__install_chroot_umount/man.rst b/cdist/conf/type/__install_chroot_umount/man.rst deleted file mode 120000 index fa34c4b0..00000000 --- a/cdist/conf/type/__install_chroot_umount/man.rst +++ /dev/null @@ -1 +0,0 @@ -../__chroot_umount/man.rst \ No newline at end of file diff --git a/cdist/conf/type/__install_chroot_umount/man.rst b/cdist/conf/type/__install_chroot_umount/man.rst new file mode 100644 index 00000000..2e020c01 --- /dev/null +++ b/cdist/conf/type/__install_chroot_umount/man.rst @@ -0,0 +1,47 @@ +cdist-type__install_chroot_umount(7) +==================================== + +NAME +---- +cdist-type__install_chroot_umount - unmount a chroot mounted by __install_chroot_mount + + +DESCRIPTION +----------- +Undo what __install_chroot_mount did. + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +None + + +EXAMPLES +-------- + +.. code-block:: sh + + __install_chroot_umount /path/to/chroot + + +SEE ALSO +-------- +:strong:`cdist-type__install_chroot_mount`\ (7) + + +AUTHORS +------- +Steven Armstrong + + +COPYING +------- +Copyright \(C) 2012 Steven Armstrong. 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/__install_file/man.rst b/cdist/conf/type/__install_file/man.rst deleted file mode 120000 index c937b8af..00000000 --- a/cdist/conf/type/__install_file/man.rst +++ /dev/null @@ -1 +0,0 @@ -../__file/man.rst \ No newline at end of file diff --git a/cdist/conf/type/__install_file/man.rst b/cdist/conf/type/__install_file/man.rst new file mode 100644 index 00000000..c5409167 --- /dev/null +++ b/cdist/conf/type/__install_file/man.rst @@ -0,0 +1,112 @@ +cdist-type__install_file(7) +=========================== + +NAME +---- +cdist-type__install_file - Manage files with install command. + + +DESCRIPTION +----------- +This cdist type allows you to create files, remove files and set file +attributes on the target. + +If the file already exists on the target, then if it is a: + +regular file, and state is: + present + replace it with the source file if they are not equal + exists + do nothing +symlink + replace it with the source file +directory + replace it with the source file + +In any case, make sure that the file attributes are as specified. + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +state + 'present', 'absent' or 'exists', defaults to 'present' where: + + present + the file is exactly the one from source + absent + the file does not exist + exists + the file from source but only if it doesn't already exist + +group + Group to chgrp to. + +mode + Unix permissions, suitable for chmod. + +owner + User to chown to. + +source + If supplied, copy this file from the host running cdist to the target. + If not supplied, an empty file or directory will be created. + If source is '-' (dash), take what was written to stdin as the file content. + +MESSAGES +-------- +chgrp + Changed group membership +chown + Changed owner +chmod + Changed mode +create + Empty file was created (no --source specified) +remove + File exists, but state is absent, file will be removed by generated code. +upload + File was uploaded + + +EXAMPLES +-------- + +.. code-block:: sh + + # Create /etc/cdist-configured as an empty file + __install_file /etc/cdist-configured + # The same thing + __install_file /etc/cdist-configured --state present + # Use __file from another type + __install_file /etc/issue --source "$__type/files/archlinux" --state present + # Delete existing file + __install_file /etc/cdist-configured --state absent + # Supply some more settings + __install_file /etc/shadow --source "$__type/files/shadow" \ + --owner root --group shadow --mode 0640 \ + --state present + # Provide a default file, but let the user change it + __install_file /home/frodo/.bashrc --source "/etc/skel/.bashrc" \ + --state exists \ + --owner frodo --mode 0600 + # Take file content from stdin + __install_file /tmp/whatever --owner root --group root --mode 644 --source - << DONE + Here goes the content for /tmp/whatever + DONE + + +AUTHORS +------- +Nico Schottelius + + +COPYING +------- +Copyright \(C) 2011-2013 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. diff --git a/docs/changelog b/docs/changelog index ec85c50d..a84ebf10 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Documentation: Update docs for types that used man.rst as symbolic links (Darko Poljak) * Type __cron: no '# marker' for raw_command due to cron security (Daniel Heule) * New type: __docker_compose (Dominique Roux) * Type __apt_mark: Check supported apt version and if package is installed (Ander Punnar) diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 1ff82ce0..2c5f9f6a 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -51,6 +51,19 @@ Example: __myfancysingleton --colour green +Config types +------------ +By default types are used with config command. These are types that are not +flagged by any known command flag. If a type is marked then it will be skipped +with config command. + + +Install types +------------- +If a type is flagged with 'install' flag then it is used only with install command. +With other commands, i.e. config, these types are skipped if used. + + How to write a new type ----------------------- A type consists of @@ -209,6 +222,18 @@ As you can see, the object ID is omitted, because it does not make any sense, if your type can be used only once. +Install - type with install command +----------------------------------- +If you want a type to be used with install command, you must mark it as +install: create the (empty) file "install" in your type directory: + +.. code-block:: sh + + touch cdist/conf/type/__install_NAME/install + +With other commands, i.e. config, it will be skipped if used. + + The type explorers ------------------ If a type needs to explore specific details, it can provide type specific From 7868165e912581a23f4ec6761bb648a61826ca95 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 16 Dec 2016 20:27:00 +0100 Subject: [PATCH 0403/1332] Update changelog. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index a84ebf10..425a32f3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,7 +3,7 @@ Changelog next: * Documentation: Update docs for types that used man.rst as symbolic links (Darko Poljak) - * Type __cron: no '# marker' for raw_command due to cron security (Daniel Heule) + * Type __cron: Remove '# marker' for raw_command due to cron security (Daniel Heule) * New type: __docker_compose (Dominique Roux) * Type __apt_mark: Check supported apt version and if package is installed (Ander Punnar) * New type: __docker (Steven Armstrong) From 4d106550148210fefa4982ae6b8f7e8c7b657ec4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 17 Dec 2016 09:46:44 +0100 Subject: [PATCH 0404/1332] release++ --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 425a32f3..d5519f25 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.4.1: 2016-12-17 * Documentation: Update docs for types that used man.rst as symbolic links (Darko Poljak) * Type __cron: Remove '# marker' for raw_command due to cron security (Daniel Heule) * New type: __docker_compose (Dominique Roux) From 7a5244bf7c5b4fb486de5c69b31e772626d4c5ad Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Wed, 21 Dec 2016 23:03:24 +0100 Subject: [PATCH 0405/1332] Bugfixed __docker_compose: If docker-compose is already running, curl won't override the binary I add an if the file does not exist before download --- cdist/conf/type/__docker_compose/gencode-remote | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote index f22823d3..3f2fb940 100644 --- a/cdist/conf/type/__docker_compose/gencode-remote +++ b/cdist/conf/type/__docker_compose/gencode-remote @@ -22,7 +22,6 @@ version="$(cat "$__object/parameter/version")" # Download docker-compose file -echo 'curl -L "https://github.com/docker/compose/releases/download/'${version}'/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose' - + echo 'if [ ! -e /usr/local/bin/docker-compose ]; then curl -L "https://github.com/docker/compose/releases/download/'${version}'/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose ; fi' # Change permissions echo 'chmod +x /usr/local/bin/docker-compose' From 6fa7bfbfb57dfd29dfaac333f9e172ac6d23aaf1 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Tue, 27 Dec 2016 13:20:57 +0100 Subject: [PATCH 0406/1332] Better bugfix: - Download the docker-compose binary first to /tmp then move it to its target location --- cdist/conf/type/__docker_compose/gencode-remote | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote index 3f2fb940..3424ed6d 100644 --- a/cdist/conf/type/__docker_compose/gencode-remote +++ b/cdist/conf/type/__docker_compose/gencode-remote @@ -22,6 +22,7 @@ version="$(cat "$__object/parameter/version")" # Download docker-compose file - echo 'if [ ! -e /usr/local/bin/docker-compose ]; then curl -L "https://github.com/docker/compose/releases/download/'${version}'/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose ; fi' + echo 'curl -L "https://github.com/docker/compose/releases/download/'${version}'/docker-compose-$(uname -s)-$(uname -m)" -o /tmp/docker-compose' + echo 'mv /tmp/docker-compose /usr/local/bin/docker-compose' # Change permissions echo 'chmod +x /usr/local/bin/docker-compose' From 95b92627aa84bf73744724f02fbffd367c2c6751 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Thu, 29 Dec 2016 14:36:46 +0100 Subject: [PATCH 0407/1332] Added --state absent functionality to docker types Changed types: __docker __docker_compose --- cdist/conf/type/__docker/manifest | 56 ++++++++++--------- .../type/__docker/parameter/default/state | 1 + cdist/conf/type/__docker/parameter/optional | 1 + .../conf/type/__docker_compose/gencode-remote | 13 +++-- cdist/conf/type/__docker_compose/manifest | 11 +++- .../__docker_compose/parameter/default/state | 1 + .../type/__docker_compose/parameter/optional | 1 + 7 files changed, 51 insertions(+), 33 deletions(-) create mode 100644 cdist/conf/type/__docker/parameter/default/state create mode 100644 cdist/conf/type/__docker/parameter/optional create mode 100644 cdist/conf/type/__docker_compose/parameter/default/state diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index ba13b3e4..1f473afb 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -20,38 +20,39 @@ os=$(cat "$__global/explorer/os") +state=$(cat "$__object/parameter/state") case "$os" in - centos) - component="main" + centos) + component="main" + if [ -f "$__object/parameter/experimental" ]; then + component="experimental" + fi + __yum_repo docker \ + --name 'Docker Repository' \ + --baseurl "https://yum.dockerproject.org/repo/$component/centos/\$releasever/" \ + --enabled \ + --gpgcheck 1 \ + --gpgkey 'https://yum.dockerproject.org/gpg' \ + --state ${state} + require="__yum_repo/docker" __package docker-engine --state ${state} + ;; + ubuntu) + component="main" if [ -f "$__object/parameter/experimental" ]; then component="experimental" fi - export CDIST_ORDER_DEPENDENCY=on - __yum_repo docker \ - --name 'Docker Repository' \ - --baseurl "https://yum.dockerproject.org/repo/$component/centos/\$releasever/" \ - --enabled \ - --gpgcheck \ - --gpgkey 'https://yum.dockerproject.org/gpg' - __package docker-engine - unset CDIST_ORDER_DEPENDENCY - ;; - ubuntu) - component="main" - if [ -f "$__object/parameter/experimental" ]; then - component="experimental" - fi - __package apparmor - __package ca-certificates - __package apt-transport-https - __apt_key docker --keyid 58118E89F3A912897C070ADBF76221572C52609D + __package apparmor --state ${state} + __package ca-certificates --state ${state} + __package apt-transport-https --state ${state} + __apt_key docker --keyid 58118E89F3A912897C070ADBF76221572C52609D --state ${state} export CDIST_ORDER_DEPENDENCY=on __apt_source docker \ --uri https://apt.dockerproject.org/repo \ --distribution "ubuntu-$(cat "$__global/explorer/lsb_codename")" \ + --state ${state} \ --component "$component" - __package docker-engine + __package docker-engine --state ${state} unset CDIST_ORDER_DEPENDENCY ;; debian) @@ -60,16 +61,17 @@ case "$os" in component="experimental" fi - __package apt-transport-https - __package ca-certificates - __package gnupg2 - __apt_key docker --keyid 58118E89F3A912897C070ADBF76221572C52609D + __package apt-transport-https --state ${state} + __package ca-certificates --state ${state} + __package gnupg2 --state ${state} + __apt_key docker --keyid 58118E89F3A912897C070ADBF76221572C52609D --state ${state} export CDIST_ORDER_DEPENDENCY=on __apt_source docker \ --uri https://apt.dockerproject.org/repo \ --distribution "debian-$(cat "$__global/explorer/lsb_codename")" \ + --state ${state} \ --component "$component" - __package docker-engine + __package docker-engine --state ${state} unset CDIST_ORDER_DEPENDENCY ;; diff --git a/cdist/conf/type/__docker/parameter/default/state b/cdist/conf/type/__docker/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__docker/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__docker/parameter/optional b/cdist/conf/type/__docker/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__docker/parameter/optional @@ -0,0 +1 @@ +state diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote index 3424ed6d..bd1ad452 100644 --- a/cdist/conf/type/__docker_compose/gencode-remote +++ b/cdist/conf/type/__docker_compose/gencode-remote @@ -20,9 +20,12 @@ # Variables version="$(cat "$__object/parameter/version")" +state="$(cat "$__object/parameter/state")" -# Download docker-compose file - echo 'curl -L "https://github.com/docker/compose/releases/download/'${version}'/docker-compose-$(uname -s)-$(uname -m)" -o /tmp/docker-compose' - echo 'mv /tmp/docker-compose /usr/local/bin/docker-compose' -# Change permissions -echo 'chmod +x /usr/local/bin/docker-compose' +if [ ${state} = "present" ]; then + # Download docker-compose file + echo 'curl -L "https://github.com/docker/compose/releases/download/'${version}'/docker-compose-$(uname -s)-$(uname -m)" -o /tmp/docker-compose' + echo 'mv /tmp/docker-compose /usr/local/bin/docker-compose' + # Change permissions + echo 'chmod +x /usr/local/bin/docker-compose' +fi diff --git a/cdist/conf/type/__docker_compose/manifest b/cdist/conf/type/__docker_compose/manifest index 2ff80aca..113e87e9 100644 --- a/cdist/conf/type/__docker_compose/manifest +++ b/cdist/conf/type/__docker_compose/manifest @@ -19,6 +19,15 @@ # # +state="$(cat "$__object/parameter/state")" + # Needed packages -__docker +__docker --state ${state} __package curl + +if [ ${state} = "absent" ]; then + __file /usr/local/bin/docker-compose --state absent +elif [ ${state} != "present" -a ${state} != "absent" ]; then + echo "Unknown state: $state_should" >&2 + exit 1 +fi diff --git a/cdist/conf/type/__docker_compose/parameter/default/state b/cdist/conf/type/__docker_compose/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__docker_compose/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__docker_compose/parameter/optional b/cdist/conf/type/__docker_compose/parameter/optional index 088eda41..4d595ed7 100644 --- a/cdist/conf/type/__docker_compose/parameter/optional +++ b/cdist/conf/type/__docker_compose/parameter/optional @@ -1 +1,2 @@ +state version From 54a58abcaa23357d14f3825b5e31ee121a7b1ec2 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Thu, 29 Dec 2016 14:47:29 +0100 Subject: [PATCH 0408/1332] Changed man.rst of __docker and __docker_compose - Added state parameter for both types in the man.rst - Changed --state absent behavior of __docker_compose -- only remove docker-compose binary not whole docker --- cdist/conf/type/__docker/man.rst | 9 ++++++++- cdist/conf/type/__docker_compose/man.rst | 7 +++++++ cdist/conf/type/__docker_compose/manifest | 10 +++++----- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__docker/man.rst b/cdist/conf/type/__docker/man.rst index 42e71af5..70b92cc7 100644 --- a/cdist/conf/type/__docker/man.rst +++ b/cdist/conf/type/__docker/man.rst @@ -26,17 +26,24 @@ BOOLEAN PARAMETERS experimental Install the experimental docker-engine package instead of the latest stable release. +state + 'present' or 'absent', defaults to 'present' + EXAMPLES -------- .. code-block:: sh + # Install docker __docker - # experimental + # Install experimental __docker --experimental + # Remove docker + __docker --state absent + AUTHORS ------- diff --git a/cdist/conf/type/__docker_compose/man.rst b/cdist/conf/type/__docker_compose/man.rst index 720a306e..d54b3370 100644 --- a/cdist/conf/type/__docker_compose/man.rst +++ b/cdist/conf/type/__docker_compose/man.rst @@ -21,6 +21,9 @@ OPTIONAL PARAMETERS version Define docker_compose version, defaults to "1.9.0" +state + 'present' or 'absent', defaults to 'present' + BOOLEAN PARAMETERS ------------------ @@ -32,11 +35,15 @@ EXAMPLES .. code-block:: sh + # Install docker-compose __docker_compose # Install version 1.9.0-rc4 __docker_compose --version 1.9.0-rc4 + # Remove docker-compose + __docker_compose --state absent + AUTHORS ------- diff --git a/cdist/conf/type/__docker_compose/manifest b/cdist/conf/type/__docker_compose/manifest index 113e87e9..3ab27c63 100644 --- a/cdist/conf/type/__docker_compose/manifest +++ b/cdist/conf/type/__docker_compose/manifest @@ -22,12 +22,12 @@ state="$(cat "$__object/parameter/state")" # Needed packages -__docker --state ${state} -__package curl - -if [ ${state} = "absent" ]; then +if [ ${state} = "present" ]; then + __docker + __package curl +elif [ ${state} = "absent" ]; then __file /usr/local/bin/docker-compose --state absent -elif [ ${state} != "present" -a ${state} != "absent" ]; then +else echo "Unknown state: $state_should" >&2 exit 1 fi From 0dbe9e14286428437052fa7c9c96ef5335a11b82 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Sat, 31 Dec 2016 11:03:28 +0100 Subject: [PATCH 0409/1332] updated man.rst --- cdist/conf/type/__docker_compose/man.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__docker_compose/man.rst b/cdist/conf/type/__docker_compose/man.rst index d54b3370..38366157 100644 --- a/cdist/conf/type/__docker_compose/man.rst +++ b/cdist/conf/type/__docker_compose/man.rst @@ -9,6 +9,8 @@ cdist-type__docker_compose - install docker-compose DESCRIPTION ----------- Installs docker-compose package. +State 'absent' will not remove docker binary itself +only docker-compose binary will be removed REQUIRED PARAMETERS From 07906451b23abfe4c100d7413d6f362e183cff1d Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Sat, 31 Dec 2016 11:06:06 +0100 Subject: [PATCH 0410/1332] updated man.rst --- cdist/conf/type/__docker_compose/man.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker_compose/man.rst b/cdist/conf/type/__docker_compose/man.rst index 38366157..7386e737 100644 --- a/cdist/conf/type/__docker_compose/man.rst +++ b/cdist/conf/type/__docker_compose/man.rst @@ -9,7 +9,7 @@ cdist-type__docker_compose - install docker-compose DESCRIPTION ----------- Installs docker-compose package. -State 'absent' will not remove docker binary itself +State 'absent' will not remove docker binary itself, only docker-compose binary will be removed From 4742913244ce33c7910b0b20224dba3439292147 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Mon, 2 Jan 2017 11:48:07 +0100 Subject: [PATCH 0411/1332] fixed type --- cdist/conf/type/__docker_compose/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker_compose/manifest b/cdist/conf/type/__docker_compose/manifest index 3ab27c63..559375ef 100644 --- a/cdist/conf/type/__docker_compose/manifest +++ b/cdist/conf/type/__docker_compose/manifest @@ -28,6 +28,6 @@ if [ ${state} = "present" ]; then elif [ ${state} = "absent" ]; then __file /usr/local/bin/docker-compose --state absent else - echo "Unknown state: $state_should" >&2 + echo "Unknown state: ${state}" >&2 exit 1 fi From 0ad767fa293b80960656d2fe2f3ec40b348de454 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 11 Jan 2017 16:44:17 +0100 Subject: [PATCH 0412/1332] fix filter for new cron on sles12 sp2 --- cdist/conf/type/__cron/gencode-remote | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index f5c1cc62..3c3ed6b3 100644 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -3,6 +3,7 @@ # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2013 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Thomas Oettli (otho at sfs.biz) +# 2017 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -57,7 +58,7 @@ state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" # These are the old markers prefix="#cdist:__cron/$__object_id" suffix="#/cdist:__cron/$__object_id" -filter="^# DO NOT EDIT THIS FILE|^# \(.* installed on |^# \(Cron version V" +filter="^# DO NOT EDIT THIS FILE|^# \(.* installed on |^# \(Cron version V|^# \(Cronie version .\..\)$" cat << DONE crontab -u $user -l 2>/dev/null | grep -v -E "$filter" | awk -v prefix="$prefix" -v suffix="$suffix" ' { From 86678b5beb0a292273947c250796035de0814758 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 11 Jan 2017 21:32:52 +0100 Subject: [PATCH 0413/1332] Cleanup __user_groups oldusermod explorer. --- cdist/conf/type/__user_groups/explorer/oldusermod | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/cdist/conf/type/__user_groups/explorer/oldusermod b/cdist/conf/type/__user_groups/explorer/oldusermod index 248d3922..6ef25b13 100644 --- a/cdist/conf/type/__user_groups/explorer/oldusermod +++ b/cdist/conf/type/__user_groups/explorer/oldusermod @@ -18,12 +18,4 @@ # along with cdist. If not, see . # -os="$($__explorer/os)" - -if [ "$os" = "netbsd" ]; then - echo netbsd -elif [ "$os" = "freebsd" ]; then - echo freebsd -else - usermod --help | grep -q -- '-A group' && echo true || echo false -fi +usermod --help | grep -q -- '-A group' && echo true || echo false From 61c45e7eaba64fea0de259c5b3099418aff68cd3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 14 Jan 2017 19:54:52 +0100 Subject: [PATCH 0414/1332] Update changelog. --- docs/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/changelog b/docs/changelog index d5519f25..3ffb0c68 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,12 @@ Changelog --------- +next: + * Type __user_groups: Support FreeBSD (Andres Erbsen) + * Type __cron: Fix filter for new cron on sles12 sp2 (Daniel Heule) + * Type __docker: Support absent state (Dominique Roux) + * Type __docker_compose: Support absent state (Dominique Roux) + 4.4.1: 2016-12-17 * Documentation: Update docs for types that used man.rst as symbolic links (Darko Poljak) * Type __cron: Remove '# marker' for raw_command due to cron security (Daniel Heule) From 2087f7a28aa477a95e69b45a002402a3829bba7c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 20 Jan 2017 15:22:25 +0100 Subject: [PATCH 0415/1332] Un-suppress manifest stdout. --- cdist/core/manifest.py | 6 ++++-- cdist/exec/local.py | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index a16e9346..574884a0 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -138,7 +138,8 @@ class Manifest(object): message_prefix = "initialmanifest" self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest), - message_prefix=message_prefix) + message_prefix=message_prefix, + save_output=False) def env_type_manifest(self, cdist_object): type_manifest = os.path.join(self.local.type_path, @@ -163,4 +164,5 @@ class Manifest(object): if os.path.isfile(type_manifest): self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object), - message_prefix=message_prefix) + message_prefix=message_prefix, + save_output=False) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 93301063..ec7a6ee8 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -212,7 +212,7 @@ class Local(object): try: if save_output: output, errout = exec_util.call_get_output(command, env=env) - self.log.debug("Local stdout: {}".format(output)) + self.log.info("Local stdout: {}".format(output)) # Currently, stderr is not captured. # self.log.debug("Local stderr: {}".format(errout)) if return_output: @@ -231,7 +231,7 @@ class Local(object): message.merge_messages() def run_script(self, script, env=None, return_output=False, - message_prefix=None): + message_prefix=None, save_output=True): """Run the given script with the given environment. Return the output as a string. @@ -240,7 +240,7 @@ class Local(object): command.append(script) return self.run(command=command, env=env, return_output=return_output, - message_prefix=message_prefix) + message_prefix=message_prefix, save_output=save_output) def save_cache(self): destination = os.path.join(self.cache_path, self.hostdir) From 707f220f779fd13fda631bc8c1ed6c3d246bc9f4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 21 Jan 2017 17:23:50 +0100 Subject: [PATCH 0416/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 3ffb0c68..71ca7782 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Core: Fix suppression of manifests' outputs (Darko Poljak) * Type __user_groups: Support FreeBSD (Andres Erbsen) * Type __cron: Fix filter for new cron on sles12 sp2 (Daniel Heule) * Type __docker: Support absent state (Dominique Roux) From b03bed242572fad1931cc90f5bd36bd452d2dff0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 28 Jan 2017 13:49:19 +0100 Subject: [PATCH 0417/1332] Better describe -v option. --- cdist/argparse.py | 8 +++++--- docs/src/man1/cdist.rst | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 04f6e6a4..e2a13c38 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -85,9 +85,11 @@ def get_parsers(): action='store_true', default=False) parser['loglevel'].add_argument( '-v', '--verbose', - help=('Increase log level, be more verbose. Use it more than once ' - 'to increase log level. The order of levels from the lowest ' - 'to the highest are: ERROR, WARNING, INFO, DEBUG.'), + help=('Increase the verbosity level. Every instance of -v ' + 'increments the verbosity level by one. Its default value is ' + '0. There are 4 levels of verbosity. The order of levels ' + 'from the lowest to the highest are: ERROR (0), WARNING (1), ' + 'INFO (2) and DEBUG (3 or higher).'), action='count', default=0) parser['beta'] = argparse.ArgumentParser(add_help=False) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 55901300..adabe052 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -50,9 +50,10 @@ All commands accept the following options: .. option:: -v, --verbose - Increase log level, be more verbose. Use it more than once to increase - log level. The order of levels from the lowest to the highest are: - ERROR, WARNING, INFO, DEBUG. + Increase the verbosity level. Every instance of -v increments the verbosity + level by one. Its default value is 0. There are 4 levels of verbosity. The + order of levels from the lowest to the highest are: ERROR (0), WARNING (1), + INFO (2) and DEBUG (3 or higher). .. option:: -V, --version From 444790aed29a020a57139b199335f2d1830d9022 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 1 Feb 2017 23:10:26 +0100 Subject: [PATCH 0418/1332] explicitly create cache dir Signed-off-by: Steven Armstrong --- cdist/exec/local.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index ec7a6ee8..fd764378 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -149,6 +149,7 @@ class Local(object): self.mkdir(self.global_explorer_out_path) self.mkdir(self.object_path) self.mkdir(self.bin_path) + self.mkdir(self.cache_path) def create_files_dirs(self): self._init_directories() From 574688c6e1f27fdcd3cc69c18b7e36506d528b95 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 2 Feb 2017 19:47:02 +0100 Subject: [PATCH 0419/1332] Rm due to new patch from Dmitry. --- cdist/conf/type/__hosts/man.rst | 55 ------------------- cdist/conf/type/__hosts/manifest | 49 ----------------- .../conf/type/__hosts/parameter/default/state | 1 - cdist/conf/type/__hosts/parameter/optional | 2 - 4 files changed, 107 deletions(-) delete mode 100644 cdist/conf/type/__hosts/man.rst delete mode 100755 cdist/conf/type/__hosts/manifest delete mode 100644 cdist/conf/type/__hosts/parameter/default/state delete mode 100644 cdist/conf/type/__hosts/parameter/optional diff --git a/cdist/conf/type/__hosts/man.rst b/cdist/conf/type/__hosts/man.rst deleted file mode 100644 index f89a619c..00000000 --- a/cdist/conf/type/__hosts/man.rst +++ /dev/null @@ -1,55 +0,0 @@ -cdist-type__hosts(7) -==================== - -NAME ----- - -cdist-type__hosts - manage entries in /etc/hosts - -DESCRIPTION ------------ - -Add or remove entries from */etc/hosts* file. - -OPTIONAL PARAMETERS -------------------- - -state - - If state is ``present``, make *object_id* resolve to *ip*. If - state is ``absent``, *object_id* will no longer resolve to - anything via */etc/hosts*. - -ip - - IP address, to which hostname (=\ *object_id*) must resolve. If - state is ``present``, this parameter is mandatory, if state is - ``absent``, this parameter is silently ignored. - -EXAMPLES --------- - -.. code-block:: sh - - # Now `funny' resolves to 192.168.1.76, - __hosts funny --ip 192.168.1.76 - # and `happy' does not resolve (at least via /etc/hosts) - __hosts happy --state absent - -SEE ALSO --------- - -:strong:`hosts`\ (5) - -AUTHORS -------- - -Dmitry Bogatov - - -COPYING -------- - -Copyright (C) 2015,2016 Dmitry Bogatov. Free use of this software is granted -under the terms of the GNU General Public License version 3 or later -(GPLv3+). diff --git a/cdist/conf/type/__hosts/manifest b/cdist/conf/type/__hosts/manifest deleted file mode 100755 index 99a06c09..00000000 --- a/cdist/conf/type/__hosts/manifest +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# Copyright (C) 2015 Bogatov Dmitry -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -hostname="$__object_id" -state="$(cat "$__object/parameter/state")" - -# First remove all lines for given hostname and then insert again. -# Otherwise, we risk having multiple entries for same hostname. -# -# There is a corner case, which we do not handle. Namely, /etc/hosts -# format allows several host names on single line, like following: -# -# 192.168.15.16 foo bar -# -# If this type manages hostname `foo', then hostname bar will get erased. - -__line "__hosts/delete/${hostname}" \ - --state absent \ - --regex " ${hostname}[ ]*$" \ - --file /etc/hosts -export require="__line/__hosts/delete/${hostname}" - -case "$state" in - absent) - : # Nothing to do - ;; - present) - ip="$(cat "$__object/parameter/ip")" - __line "__hosts/insert/${hostname}" \ - --line "${ip} ${hostname}" \ - --file /etc/hosts - ;; - *) - echo "ERROR: type (${__type##*/}) does not support state \`$state'" - exit 1 -esac diff --git a/cdist/conf/type/__hosts/parameter/default/state b/cdist/conf/type/__hosts/parameter/default/state deleted file mode 100644 index e7f6134f..00000000 --- a/cdist/conf/type/__hosts/parameter/default/state +++ /dev/null @@ -1 +0,0 @@ -present diff --git a/cdist/conf/type/__hosts/parameter/optional b/cdist/conf/type/__hosts/parameter/optional deleted file mode 100644 index 411fc5d2..00000000 --- a/cdist/conf/type/__hosts/parameter/optional +++ /dev/null @@ -1,2 +0,0 @@ -state -ip From c4c2d45e5956cab0d044cff93edc47ffd59f43fe Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Thu, 2 Feb 2017 10:51:21 +0300 Subject: [PATCH 0420/1332] New type: __hosts --- cdist/conf/type/__hosts/man.rst | 57 +++++++++++++++++++ cdist/conf/type/__hosts/manifest | 29 ++++++++++ .../conf/type/__hosts/parameter/default/state | 1 + cdist/conf/type/__hosts/parameter/optional | 2 + docs/changelog | 1 + 5 files changed, 90 insertions(+) create mode 100644 cdist/conf/type/__hosts/man.rst create mode 100755 cdist/conf/type/__hosts/manifest create mode 100644 cdist/conf/type/__hosts/parameter/default/state create mode 100644 cdist/conf/type/__hosts/parameter/optional diff --git a/cdist/conf/type/__hosts/man.rst b/cdist/conf/type/__hosts/man.rst new file mode 100644 index 00000000..20f463e7 --- /dev/null +++ b/cdist/conf/type/__hosts/man.rst @@ -0,0 +1,57 @@ +cdist-type__hosts(7) +==================== + +NAME +---- + +cdist-type__hosts - manage entries in /etc/hosts + +DESCRIPTION +----------- + +Add or remove entries from */etc/hosts* file. + +OPTIONAL PARAMETERS +------------------- + +state + + If state is ``present``, make *object_id* resolve to *ip*. If + state is ``absent``, *object_id* will no longer resolve via + */etc/hosts*, if it was previously configured with this type. + Manually inserted entries are unaffected. + +ip + + IP address, to which hostname (=\ *object_id*) must resolve. If + state is ``present``, this parameter is mandatory, if state is + ``absent``, this parameter is silently ignored. + +EXAMPLES +-------- + +.. code-block:: sh + + # Now `funny' resolves to 192.168.1.76, + __hosts funny --ip 192.168.1.76 + # and `happy' no longer resolve via /etc/hosts if it was + # previously configured via __hosts. + __hosts happy --state absent + +SEE ALSO +-------- + +:strong:`hosts`\ (5) + +AUTHORS +------- + +Dmitry Bogatov + + +COPYING +------- + +Copyright (C) 2015,2016 Dmitry Bogatov. Free use of this software is granted +under the terms of the GNU General Public License version 3 or later +(GPLv3+). diff --git a/cdist/conf/type/__hosts/manifest b/cdist/conf/type/__hosts/manifest new file mode 100755 index 00000000..6fa21608 --- /dev/null +++ b/cdist/conf/type/__hosts/manifest @@ -0,0 +1,29 @@ +#!/bin/sh +# Copyright (C) 2015 Bogatov Dmitry +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +set -ue + +hostname="$__object_id" +state="$(cat "$__object/parameter/state")" +marker="# __hosts/$hostname" + +set -- "__hosts/$hostname" --file /etc/hosts --state "$state" + +if [ "$state" = absent ] ; then + __line "$@" --regex "$marker" +else + ip="$(cat "$__object/parameter/ip")" + __line "$@" --line "$ip $hostname $marker" +fi diff --git a/cdist/conf/type/__hosts/parameter/default/state b/cdist/conf/type/__hosts/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__hosts/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__hosts/parameter/optional b/cdist/conf/type/__hosts/parameter/optional new file mode 100644 index 00000000..411fc5d2 --- /dev/null +++ b/cdist/conf/type/__hosts/parameter/optional @@ -0,0 +1,2 @@ +state +ip diff --git a/docs/changelog b/docs/changelog index 6b869256..44631046 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Type __cron: Fix filter for new cron on sles12 sp2 (Daniel Heule) * Type __docker: Support absent state (Dominique Roux) * Type __docker_compose: Support absent state (Dominique Roux) + * New type: __hosts (Dmitry Bogatov) 4.4.1: 2016-12-17 * Documentation: Update docs for types that used man.rst as symbolic links (Darko Poljak) From 0eda926b8cfd8b66fd9bb40964254f5a2c81eb46 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 2 Feb 2017 19:49:39 +0100 Subject: [PATCH 0421/1332] Fix changelog. --- docs/changelog | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 44631046..e50ed243 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,7 +2,6 @@ Changelog --------- next: - * New type: __hosts: manage entries in /etc/hosts (Dmitry Bogatov) * Core: Fix suppression of manifests' outputs (Darko Poljak) * Type __user_groups: Support FreeBSD (Andres Erbsen) * Type __cron: Fix filter for new cron on sles12 sp2 (Daniel Heule) From 72d73e307d020260d8c22ffde8626d5391235d57 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 2 Feb 2017 19:50:51 +0100 Subject: [PATCH 0422/1332] Fix changelog. --- docs/changelog | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index e50ed243..93e6e24f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -43,7 +43,6 @@ next: * Type __filesystem: Spelling fixes (Dmitry Bogatov) * Core: Add target_host file to cache since cache dir name can be hash (Darko Poljak) * Core: Improve hostfile: support comments, skip empty lines (Darko Poljak) ->>>>>>> ungleich/master 4.3.0: 2016-08-19 * Documentation: Add Parallelization chapter (Darko Poljak) From d5b12467910afaf90146ed8f9f31ddf5f5029fb1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Feb 2017 22:43:27 +0100 Subject: [PATCH 0423/1332] change ControlPersist from 125 to 10 seconds Signed-off-by: Steven Armstrong --- cdist/util/remoteutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/util/remoteutil.py b/cdist/util/remoteutil.py index c18d6705..2bd12fdf 100644 --- a/cdist/util/remoteutil.py +++ b/cdist/util/remoteutil.py @@ -36,7 +36,7 @@ def inspect_ssh_mux_opts(): wanted_mux_opts = { "ControlPath": "{}", "ControlMaster": "auto", - "ControlPersist": "125", + "ControlPersist": "10", } mux_opts = " ".join([" -o {}={}".format( x, wanted_mux_opts[x]) for x in wanted_mux_opts]) From 4a7ef82bf88efa579f6c1b102f96c5185b0400db Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Feb 2017 23:16:16 +0100 Subject: [PATCH 0424/1332] cant depend on build-helper to have cdist.version module Signed-off-by: Steven Armstrong --- setup.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f29a8998..b79e8340 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,20 @@ from distutils.core import setup -import cdist import os import re +# Ensure version is present - the bundled/shipped version contains a static version, +# the git version contains a dynamic version +try: + import cdist.version +except ImportError: + import subprocess + version = subprocess.getoutput('git describe') + with open('cdist/version.py', 'w') as fd: + fd.write('VERSION = "%s"\n' % version) + +import cdist + def data_finder(data_dir): entries = [] for name in os.listdir(data_dir): From d10ba1e587ec91a78ed01dfe5e56f0707e78f114 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Feb 2017 23:38:24 +0100 Subject: [PATCH 0425/1332] Revert "cant depend on build-helper to have cdist.version module" This reverts commit 4a7ef82bf88efa579f6c1b102f96c5185b0400db. --- setup.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/setup.py b/setup.py index b79e8340..f29a8998 100644 --- a/setup.py +++ b/setup.py @@ -1,20 +1,9 @@ from distutils.core import setup +import cdist import os import re -# Ensure version is present - the bundled/shipped version contains a static version, -# the git version contains a dynamic version -try: - import cdist.version -except ImportError: - import subprocess - version = subprocess.getoutput('git describe') - with open('cdist/version.py', 'w') as fd: - fd.write('VERSION = "%s"\n' % version) - -import cdist - def data_finder(data_dir): entries = [] for name in os.listdir(data_dir): From 448126f4989a69a1f2159e8d035ead7032cf2dc0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 17 Feb 2017 12:31:22 +0100 Subject: [PATCH 0426/1332] no need to log stdout at log level info Signed-off-by: Steven Armstrong --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index fd764378..e078dbd2 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -213,7 +213,7 @@ class Local(object): try: if save_output: output, errout = exec_util.call_get_output(command, env=env) - self.log.info("Local stdout: {}".format(output)) + self.log.debug("Local stdout: {}".format(output)) # Currently, stderr is not captured. # self.log.debug("Local stderr: {}".format(errout)) if return_output: From 6d277ef1f1be1b4ab6e2cacbe5912cd4dad7541b Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Tue, 14 Feb 2017 10:23:19 +0300 Subject: [PATCH 0427/1332] New type: __dot_file --- cdist/conf/type/__dot_file/explorer/home | 27 +++++++ .../type/__dot_file/explorer/primary_group | 21 ++++++ cdist/conf/type/__dot_file/man.rst | 75 +++++++++++++++++++ cdist/conf/type/__dot_file/manifest | 65 ++++++++++++++++ .../type/__dot_file/parameter/default/mode | 1 + cdist/conf/type/__dot_file/parameter/optional | 3 + cdist/conf/type/__dot_file/parameter/required | 1 + docs/changelog | 1 + 8 files changed, 194 insertions(+) create mode 100755 cdist/conf/type/__dot_file/explorer/home create mode 100755 cdist/conf/type/__dot_file/explorer/primary_group create mode 100644 cdist/conf/type/__dot_file/man.rst create mode 100755 cdist/conf/type/__dot_file/manifest create mode 100644 cdist/conf/type/__dot_file/parameter/default/mode create mode 100644 cdist/conf/type/__dot_file/parameter/optional create mode 100644 cdist/conf/type/__dot_file/parameter/required diff --git a/cdist/conf/type/__dot_file/explorer/home b/cdist/conf/type/__dot_file/explorer/home new file mode 100755 index 00000000..132cfc71 --- /dev/null +++ b/cdist/conf/type/__dot_file/explorer/home @@ -0,0 +1,27 @@ +#!/bin/sh +# Copyright (C) 2016 Dmitry Bogatov + +# Author: Dmitry Bogatov + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 +# of the License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +set -eu + +user="$(cat "${__object}/parameter/user")" + +if which getent >/dev/null 2>&1; then + line=$(getent passwd "${user}") +else + line=$(grep "^${user}:" /etc/passwd) +fi +printf '%s' "$line" | cut -d: -f6 diff --git a/cdist/conf/type/__dot_file/explorer/primary_group b/cdist/conf/type/__dot_file/explorer/primary_group new file mode 100755 index 00000000..30b303ac --- /dev/null +++ b/cdist/conf/type/__dot_file/explorer/primary_group @@ -0,0 +1,21 @@ +#!/bin/sh +# Copyright (C) 2016 Dmitry Bogatov + +# Author: Dmitry Bogatov + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 +# of the License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +set -eu + +user="$(cat "${__object}/parameter/user")" +id -gn "${user}" diff --git a/cdist/conf/type/__dot_file/man.rst b/cdist/conf/type/__dot_file/man.rst new file mode 100644 index 00000000..211c34a5 --- /dev/null +++ b/cdist/conf/type/__dot_file/man.rst @@ -0,0 +1,75 @@ +cdist-type__dot_file(7) +======================== + +NAME +---- + +cdist-type__dot_file - install file under user's home directory + +DESCRIPTION +----------- + +This type installs a file (=\ *__object_id*) under user's home directory, +providing a way to install per-user configuration files. File owner +and group is deduced from user, for who file is installed. + +Unlike regular __file type, you do not need make any assumptions, +where user's home directory is. + +REQUIRED PARAMETERS +------------------- + +user + + User, for who file is installed + +OPTIONAL PARAMETERS +------------------- + +mode + + forwarded to :bold:`__file` type + +state + + forwarded to :bold:`__file` type + +source + + forwarded to :bold:`__file` type + +MESSAGES +-------- + +This type inherits all messages from :bold:`file` type, and do not add +any new. + +EXAMPLES +-------- + +.. code-block:: sh + + # Install .forward file for user 'alice'. Since state is 'present', + # user is not meant to edit this file, all changes will be overridden. + # It is good idea to put warning about it in file itself. + __dot_file .forward --user alice --source "$__files/forward" + + # Install .muttrc for user 'bob', if not already present. User can safely + # edit it, his changes will not be overwritten. + __dot_file .muttrc --user bob --source "$__files/recommended_mutt_config" --state exists + + + # 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" + +SEE ALSO +-------- + +**cdist-type**\ (7), **cdist-type__file**\ (7) + +COPYING +------- + +Copyright (C) 2015 Dmitry Bogatov. Free use of this software is granted +under the terms of the GNU General Public License version 3 or later +(GPLv3+). diff --git a/cdist/conf/type/__dot_file/manifest b/cdist/conf/type/__dot_file/manifest new file mode 100755 index 00000000..4bc9f179 --- /dev/null +++ b/cdist/conf/type/__dot_file/manifest @@ -0,0 +1,65 @@ +#!/bin/sh +# +# Copyright (C) 2016 Bogatov Dmitry +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +set -eu + +user="$(cat "${__object}/parameter/user")" +home="$(cat "${__object}/explorer/home")" +primary_group="$(cat "${__object}/explorer/primary_group")" + +# 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} +while subpath="$(dirname "${subpath}")" ; do + [ "${subpath}" = . ] && break + set -- "${subpath}" "$@" +done +unset subpath + +export CDIST_ORDER_DEPENDENCY +for dir ; do + __directory "${home}/${dir}" \ + --group "${primary_group}" \ + --owner "${user}" +done + +# These parameters are forwarded to __file type. 'mode' is always +# present, since it have been given default. + +set -- +for p in state mode source ; do + if [ -f "${__object}/parameter/${p}" ] ; then + value="$(cat "${__object}/parameter/${p}")" + set -- "$@" "--${p}" "${value}" + unset value + fi +done + +# If source is `-' we can't just forward it, since stdin is already +# captured by __dot_file. So, we replace '-' with "$__object/stdin". +# +# It means that it is possible for __file to receive --source +# parameter twice, but, since latest wins, it is okay. +source="$(cat "${__object}/parameter/source")" +if [ "${source}" = "-" ] ; then + set -- "$@" --source "${__object}/stdin" +fi +unset source + +__file "${home}/${__object_id}" --owner "$user" --group "$primary_group" "$@" diff --git a/cdist/conf/type/__dot_file/parameter/default/mode b/cdist/conf/type/__dot_file/parameter/default/mode new file mode 100644 index 00000000..e9f960cf --- /dev/null +++ b/cdist/conf/type/__dot_file/parameter/default/mode @@ -0,0 +1 @@ +600 diff --git a/cdist/conf/type/__dot_file/parameter/optional b/cdist/conf/type/__dot_file/parameter/optional new file mode 100644 index 00000000..ccab9fa6 --- /dev/null +++ b/cdist/conf/type/__dot_file/parameter/optional @@ -0,0 +1,3 @@ +state +mode +source diff --git a/cdist/conf/type/__dot_file/parameter/required b/cdist/conf/type/__dot_file/parameter/required new file mode 100644 index 00000000..4eb8387f --- /dev/null +++ b/cdist/conf/type/__dot_file/parameter/required @@ -0,0 +1 @@ +user diff --git a/docs/changelog b/docs/changelog index 93e6e24f..f3e4986c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Type __docker: Support absent state (Dominique Roux) * Type __docker_compose: Support absent state (Dominique Roux) * New type: __hosts (Dmitry Bogatov) + * New type: __dot_file (Dmitry Bogatov) 4.4.1: 2016-12-17 * Documentation: Update docs for types that used man.rst as symbolic links (Darko Poljak) From da4118dcf3101b0b3a2b85ab060dc81c8c78d283 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 8 Mar 2017 19:07:02 +0100 Subject: [PATCH 0428/1332] pep8 --- cdist/argparse.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index e2a13c38..3791e779 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -86,10 +86,10 @@ def get_parsers(): parser['loglevel'].add_argument( '-v', '--verbose', help=('Increase the verbosity level. Every instance of -v ' - 'increments the verbosity level by one. Its default value is ' - '0. There are 4 levels of verbosity. The order of levels ' - 'from the lowest to the highest are: ERROR (0), WARNING (1), ' - 'INFO (2) and DEBUG (3 or higher).'), + 'increments the verbosity level by one. Its default value ' + 'is 0. There are 4 levels of verbosity. The order of levels ' + 'from the lowest to the highest are: ERROR (0), ' + 'WARNING (1), INFO (2) and DEBUG (3 or higher).'), action='count', default=0) parser['beta'] = argparse.ArgumentParser(add_help=False) From 303c681bff7053f2756736d34f639f0f172571b6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 8 Mar 2017 19:08:59 +0100 Subject: [PATCH 0429/1332] Release 4.4.2 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index f3e4986c..b61f818b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) * Type __user_groups: Support FreeBSD (Andres Erbsen) * Type __cron: Fix filter for new cron on sles12 sp2 (Daniel Heule) From 57032af3564d5521a86f331704161664221b0c64 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 8 Mar 2017 19:16:23 +0100 Subject: [PATCH 0430/1332] Fix code-block argument missing. --- cdist/conf/type/__postgres_extension/man.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__postgres_extension/man.rst b/cdist/conf/type/__postgres_extension/man.rst index ead51c83..79645b2b 100644 --- a/cdist/conf/type/__postgres_extension/man.rst +++ b/cdist/conf/type/__postgres_extension/man.rst @@ -14,13 +14,13 @@ The object you need to pass to __postgres_extension consists of the database name and the extension name joined by a colon in the following form: -.. code-block:: +.. code-block:: sh dbname:extension f.ex. -.. code-block:: +.. code-block:: sh rails_test:unaccent From 517493ea9256fd0e934f46bc035cfd71fdda4610 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 8 Mar 2017 19:36:34 +0100 Subject: [PATCH 0431/1332] reStructuredText fixes. --- cdist/conf/type/__dot_file/man.rst | 14 +++++--------- cdist/conf/type/__hosts/man.rst | 2 -- cdist/conf/type/__package_dpkg/man.rst | 8 ++++---- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/cdist/conf/type/__dot_file/man.rst b/cdist/conf/type/__dot_file/man.rst index 211c34a5..ae65eb95 100644 --- a/cdist/conf/type/__dot_file/man.rst +++ b/cdist/conf/type/__dot_file/man.rst @@ -20,28 +20,24 @@ REQUIRED PARAMETERS ------------------- user - User, for who file is installed OPTIONAL PARAMETERS ------------------- mode - - forwarded to :bold:`__file` type + forwarded to :strong:`__file` type state - - forwarded to :bold:`__file` type + forwarded to :strong:`__file` type source - - forwarded to :bold:`__file` type + forwarded to :strong:`__file` type MESSAGES -------- -This type inherits all messages from :bold:`file` type, and do not add +This type inherits all messages from :strong:`file` type, and do not add any new. EXAMPLES @@ -65,7 +61,7 @@ EXAMPLES SEE ALSO -------- -**cdist-type**\ (7), **cdist-type__file**\ (7) +**cdist-type__file**\ (7) COPYING ------- diff --git a/cdist/conf/type/__hosts/man.rst b/cdist/conf/type/__hosts/man.rst index 20f463e7..bece7967 100644 --- a/cdist/conf/type/__hosts/man.rst +++ b/cdist/conf/type/__hosts/man.rst @@ -15,14 +15,12 @@ OPTIONAL PARAMETERS ------------------- state - If state is ``present``, make *object_id* resolve to *ip*. If state is ``absent``, *object_id* will no longer resolve via */etc/hosts*, if it was previously configured with this type. Manually inserted entries are unaffected. ip - IP address, to which hostname (=\ *object_id*) must resolve. If state is ``present``, this parameter is mandatory, if state is ``absent``, this parameter is silently ignored. diff --git a/cdist/conf/type/__package_dpkg/man.rst b/cdist/conf/type/__package_dpkg/man.rst index 65a695b5..df2d86a7 100644 --- a/cdist/conf/type/__package_dpkg/man.rst +++ b/cdist/conf/type/__package_dpkg/man.rst @@ -8,16 +8,16 @@ cdist-type__package_dpkg - Manage packages with dpkg DESCRIPTION ----------- -__package_dpkg is used on Debian and variants (like Ubuntu) to -install packages that are provided locally as *.deb files. +This type is used on Debian and variants (like Ubuntu) to +install packages that are provided locally as \*.deb files. -The object given to __package_dpkg must be the name of the deb package. +The object given to this type must be the name of the deb package. REQUIRED PARAMETERS ------------------- source - path to the *.deb package + path to the \*.deb package EXAMPLES -------- From 46bbafa5095bd3387c82f3d0ad6b42f8d908b699 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Wed, 22 Mar 2017 12:30:00 +0100 Subject: [PATCH 0432/1332] __start_on_boot: add support for devuan --- cdist/conf/type/__start_on_boot/gencode-remote | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index e77132c9..45de5465 100644 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -54,6 +54,9 @@ case "$state_should" in ;; esac ;; + devuan) + echo "update-rc.d \"$name\" defaults >/dev/null" + ;; gentoo) echo rc-update add \"$name\" \"$target_runlevel\" From d3aafc45232cd84a0352b17d1b530974c118c815 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Wed, 19 Apr 2017 11:51:04 +0200 Subject: [PATCH 0433/1332] changed docker-compose version to 1.12.0 --- cdist/conf/type/__docker_compose/parameter/default/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker_compose/parameter/default/version b/cdist/conf/type/__docker_compose/parameter/default/version index f8e233b2..0eed1a29 100644 --- a/cdist/conf/type/__docker_compose/parameter/default/version +++ b/cdist/conf/type/__docker_compose/parameter/default/version @@ -1 +1 @@ -1.9.0 +1.12.0 From 21a29ab5aa7926a478ad9a031532059337af95f5 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Thu, 4 May 2017 17:29:07 +0200 Subject: [PATCH 0434/1332] add __go_get, __golang_from_vendor --- cdist/conf/explorer/kernel_name | 1 + .../conf/type/__go_get/explorer/go-executable | 3 +++ cdist/conf/type/__go_get/gencode-remote | 8 ++++++ cdist/conf/type/__go_get/manifest | 17 ++++++++++++ .../type/__golang_from_vendor/gencode-remote | 26 +++++++++++++++++++ cdist/conf/type/__golang_from_vendor/manifest | 1 + .../parameter/default/version | 1 + .../__golang_from_vendor/parameter/optional | 1 + .../conf/type/__golang_from_vendor/singleton | 0 9 files changed, 58 insertions(+) create mode 100644 cdist/conf/explorer/kernel_name create mode 100644 cdist/conf/type/__go_get/explorer/go-executable create mode 100644 cdist/conf/type/__go_get/gencode-remote create mode 100644 cdist/conf/type/__go_get/manifest create mode 100644 cdist/conf/type/__golang_from_vendor/gencode-remote create mode 100644 cdist/conf/type/__golang_from_vendor/manifest create mode 100644 cdist/conf/type/__golang_from_vendor/parameter/default/version create mode 100644 cdist/conf/type/__golang_from_vendor/parameter/optional create mode 100644 cdist/conf/type/__golang_from_vendor/singleton diff --git a/cdist/conf/explorer/kernel_name b/cdist/conf/explorer/kernel_name new file mode 100644 index 00000000..98ebac2a --- /dev/null +++ b/cdist/conf/explorer/kernel_name @@ -0,0 +1 @@ +uname -s diff --git a/cdist/conf/type/__go_get/explorer/go-executable b/cdist/conf/type/__go_get/explorer/go-executable new file mode 100644 index 00000000..4c84ce07 --- /dev/null +++ b/cdist/conf/type/__go_get/explorer/go-executable @@ -0,0 +1,3 @@ +[ -f /etc/environment ] && . /etc/environment +[ -f /etc/profile ] && . /etc/profile +go version 2>/dev/null || true diff --git a/cdist/conf/type/__go_get/gencode-remote b/cdist/conf/type/__go_get/gencode-remote new file mode 100644 index 00000000..5f1d3aae --- /dev/null +++ b/cdist/conf/type/__go_get/gencode-remote @@ -0,0 +1,8 @@ +package=$__object_id + +cat<&2 && exit 1 + +os=$(cat "$__global/explorer/os") +case $os in + debian|devuan|ubuntu) + __package build-essential + ;; + *) + echo "__go_get: Don't know how to install g++ on $os" >&2 + echo "__go_get: Send a pull request or contact to add support for $os." >&2 + exit 1 + ;; +esac + diff --git a/cdist/conf/type/__golang_from_vendor/gencode-remote b/cdist/conf/type/__golang_from_vendor/gencode-remote new file mode 100644 index 00000000..e372bf61 --- /dev/null +++ b/cdist/conf/type/__golang_from_vendor/gencode-remote @@ -0,0 +1,26 @@ +#!/bin/sh + +version=$(cat "$__object/parameter/version") + +kernel_name=$(cat "$__global/explorer/kernel_name" | tr '[:upper:]' '[:lower:]') +machine=$(cat "$__global/explorer/machine") +case $machine in + x86_64|amd64) + arch=amd64 + ;; + x86) + arch=386 + ;; + *) + arch=$machine # at least try... + ;; +esac + +PACKAGE="go${version}.${kernel_name}-${arch}" +URL="https://storage.googleapis.com/golang/${PACKAGE}.tar.gz" +cat </dev/null)" = "xgo$version" ] && exit 0 # already there +wget --no-verbose "$URL" -O "/tmp/${PACKAGE}.tar.gz" +rm -rf /usr/local/go +tar -C /usr/local -xzf /tmp/${PACKAGE}.tar.gz +EOF diff --git a/cdist/conf/type/__golang_from_vendor/manifest b/cdist/conf/type/__golang_from_vendor/manifest new file mode 100644 index 00000000..9d320830 --- /dev/null +++ b/cdist/conf/type/__golang_from_vendor/manifest @@ -0,0 +1 @@ +__line go_in_path --line 'export PATH=/usr/local/go/bin:$PATH' --file /etc/profile diff --git a/cdist/conf/type/__golang_from_vendor/parameter/default/version b/cdist/conf/type/__golang_from_vendor/parameter/default/version new file mode 100644 index 00000000..a8fdfda1 --- /dev/null +++ b/cdist/conf/type/__golang_from_vendor/parameter/default/version @@ -0,0 +1 @@ +1.8.1 diff --git a/cdist/conf/type/__golang_from_vendor/parameter/optional b/cdist/conf/type/__golang_from_vendor/parameter/optional new file mode 100644 index 00000000..088eda41 --- /dev/null +++ b/cdist/conf/type/__golang_from_vendor/parameter/optional @@ -0,0 +1 @@ +version diff --git a/cdist/conf/type/__golang_from_vendor/singleton b/cdist/conf/type/__golang_from_vendor/singleton new file mode 100644 index 00000000..e69de29b From 8d4fd9e7d81acfc2feee0f65cca3095185d73aa7 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Thu, 4 May 2017 17:43:03 +0200 Subject: [PATCH 0435/1332] add __go_get, __golang_from_vendor manpages --- cdist/conf/type/__go_get/man.rst | 48 ++++++++++++++++++++ cdist/conf/type/__golang_from_vendor/man.rst | 48 ++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 cdist/conf/type/__go_get/man.rst create mode 100644 cdist/conf/type/__golang_from_vendor/man.rst diff --git a/cdist/conf/type/__go_get/man.rst b/cdist/conf/type/__go_get/man.rst new file mode 100644 index 00000000..66d9bdba --- /dev/null +++ b/cdist/conf/type/__go_get/man.rst @@ -0,0 +1,48 @@ +cdist-type__go_get(7) +===================== + +NAME +---- +cdist-type__go_get - Install go packages with go get + + +DESCRIPTION +----------- +This cdist type allows you to install golang packages with go get. +A sufficiently recent version of go must be present on the system. + +The object ID is the go package to be installed. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + __go_get github.com/prometheus/prometheus/cmd/... + + # usually you'd need to require golang from somewhere: + require="__golang_from_vendor" __go_get github.com/prometheus/prometheus/cmd/... + + +AUTHORS +------- +Kamila Součková + + +COPYING +------- +Copyright \(C) 2017 Kamila Součková. 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/__golang_from_vendor/man.rst b/cdist/conf/type/__golang_from_vendor/man.rst new file mode 100644 index 00000000..070710c1 --- /dev/null +++ b/cdist/conf/type/__golang_from_vendor/man.rst @@ -0,0 +1,48 @@ +cdist-type__golang_from_vendor(7) +===================== + +NAME +---- +cdist-type__golang_from_vendor - Install any version of golang from golang.org + + +DESCRIPTION +----------- +This cdist type allows you to install golang from archives provided by https://golang.org/dl/. + +See https://golang.org/dl/ for the list of supported versions, operating systems and architectures. + +This is a singleton type. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +version + The golang version to install, defaults to 1.8.1 + + +EXAMPLES +-------- + +.. code-block:: sh + + __golang_from_vendor --version 1.8.1 + + + +AUTHORS +------- +Kamila Součková + + +COPYING +------- +Copyright \(C) 2017 Kamila Součková. 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. From d1fae4a75e84cdf043d0995609438b99ad950227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Fri, 5 May 2017 14:57:18 +0200 Subject: [PATCH 0436/1332] Update changelog --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index b61f818b..89c0c9b1 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,10 @@ Changelog --------- +next: + * Type __golang_from_vendor: Install golang from https://golang.org/dl/ (Kamila Součková) + * Type __go_get: Install go packages using go get (Kamila Součková) + 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) * Type __user_groups: Support FreeBSD (Andres Erbsen) From 0aec30907760099fa9a029cb67f9e25c68485695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Fri, 5 May 2017 14:58:00 +0200 Subject: [PATCH 0437/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 89c0c9b1..4ef58429 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __golang_from_vendor: Install golang from https://golang.org/dl/ (Kamila Součková) * Type __go_get: Install go packages using go get (Kamila Součková) + * Explorer kernel_name: uname -s 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) From 3e83ee82c9d2efbbcda64c3ae58470bdfa85f89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Fri, 5 May 2017 14:58:27 +0200 Subject: [PATCH 0438/1332] Update changelog --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 4ef58429..292472c9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog next: * Type __golang_from_vendor: Install golang from https://golang.org/dl/ (Kamila Součková) * Type __go_get: Install go packages using go get (Kamila Součková) - * Explorer kernel_name: uname -s + * Explorer kernel_name: uname -s (Kamila Součková) 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) From abd5f11b989d304946570ec3758d8b7800a903bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Fri, 5 May 2017 15:29:48 +0200 Subject: [PATCH 0439/1332] man.rst: fix underline --- cdist/conf/type/__golang_from_vendor/man.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__golang_from_vendor/man.rst b/cdist/conf/type/__golang_from_vendor/man.rst index 070710c1..2b4f065e 100644 --- a/cdist/conf/type/__golang_from_vendor/man.rst +++ b/cdist/conf/type/__golang_from_vendor/man.rst @@ -1,5 +1,5 @@ cdist-type__golang_from_vendor(7) -===================== +================================= NAME ---- From fc9d7af18c4d30006f6847d50a32d627ee9f713a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 16 May 2017 12:09:38 +0200 Subject: [PATCH 0440/1332] Add Devuan support for __sysctl --- cdist/conf/type/__sysctl/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__sysctl/manifest b/cdist/conf/type/__sysctl/manifest index dd317806..ac9117c4 100755 --- a/cdist/conf/type/__sysctl/manifest +++ b/cdist/conf/type/__sysctl/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - redhat|centos|ubuntu|debian|archlinux) + redhat|centos|ubuntu|debian|devuan|archlinux) : ;; *) From ecc169111c7fb8f1749342f4dc92631c0f39deac Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 16 May 2017 12:10:10 +0200 Subject: [PATCH 0441/1332] Also update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 292472c9..524257a7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __golang_from_vendor: Install golang from https://golang.org/dl/ (Kamila Součková) * Type __go_get: Install go packages using go get (Kamila Součková) * Explorer kernel_name: uname -s (Kamila Součková) + * Type __sysctl: Add devuan support (Nico Schottelius) 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) From 1322e85eacdb08bfbd8b3ef6ad785b942cc7b501 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 21 May 2017 20:42:45 +0200 Subject: [PATCH 0442/1332] A new log file --- docs/dev/logs/2017-04-27.execution-order.org | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/dev/logs/2017-04-27.execution-order.org diff --git a/docs/dev/logs/2017-04-27.execution-order.org b/docs/dev/logs/2017-04-27.execution-order.org new file mode 100644 index 00000000..5ee32062 --- /dev/null +++ b/docs/dev/logs/2017-04-27.execution-order.org @@ -0,0 +1,5 @@ +* After constructs don't exist + Flow as implemented on 2013-04-12 has the problem of not allowing + *after* constructs. +* "Type explorer & manifests only" is broken + Doesn't catch external dependencies From cf0ab2a5bdcd68e1804dd9270f55bd91bd5184e8 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Mon, 29 May 2017 16:23:24 +0200 Subject: [PATCH 0443/1332] new type: __daemontools_service --- .../conf/type/__daemontools_service/manifest | 31 +++++++++++++++++++ .../parameter/default/log-run | 1 + .../parameter/default/run | 0 .../parameter/default/run-file | 0 .../parameter/default/servicedir | 1 + .../__daemontools_service/parameter/optional | 4 +++ 6 files changed, 37 insertions(+) create mode 100644 cdist/conf/type/__daemontools_service/manifest create mode 100644 cdist/conf/type/__daemontools_service/parameter/default/log-run create mode 100644 cdist/conf/type/__daemontools_service/parameter/default/run create mode 100644 cdist/conf/type/__daemontools_service/parameter/default/run-file create mode 100644 cdist/conf/type/__daemontools_service/parameter/default/servicedir create mode 100644 cdist/conf/type/__daemontools_service/parameter/optional diff --git a/cdist/conf/type/__daemontools_service/manifest b/cdist/conf/type/__daemontools_service/manifest new file mode 100644 index 00000000..34f45545 --- /dev/null +++ b/cdist/conf/type/__daemontools_service/manifest @@ -0,0 +1,31 @@ +#!/bin/sh + +RUN_PREFIX="#!/bin/sh +exec 2>&1 +exec " # mind the space :D + +name=$__object_id +servicedir=$(cat "$__object/parameter/servicedir") +run=$(cat "$__object/parameter/run") +runfile=$(cat "$__object/parameter/run-file") +logrun=$(cat "$__object/parameter/log-run") + +badusage() { + echo "__daemontools_service/$__object_id: exactly one of --run, --run-file must be set" >&2 + exit 1 +} + +[ -z "$run$runfile" ] && badusage +[ -n "$run" ] && [ -n "$runfile" ] && badusage + +__directory $servicedir/$name/log/main --parents + +echo "$RUN_PREFIX$run" | require="__directory/$servicedir/$name/log/main" __config_file "$servicedir/$name/run" \ + --onchange "svc -t '$servicedir/$name' 2>/dev/null" \ + --mode 755 \ + --source "${runfile:--}" + +echo "$RUN_PREFIX$logrun" | require="__directory/$servicedir/$name/log/main" __config_file $servicedir/$name/log/run \ + --onchange "svc -t '$servicedir/$name/log' 2>/dev/null" \ + --mode 755 \ + --source "-" diff --git a/cdist/conf/type/__daemontools_service/parameter/default/log-run b/cdist/conf/type/__daemontools_service/parameter/default/log-run new file mode 100644 index 00000000..80d57a74 --- /dev/null +++ b/cdist/conf/type/__daemontools_service/parameter/default/log-run @@ -0,0 +1 @@ +multilog t ./main diff --git a/cdist/conf/type/__daemontools_service/parameter/default/run b/cdist/conf/type/__daemontools_service/parameter/default/run new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__daemontools_service/parameter/default/run-file b/cdist/conf/type/__daemontools_service/parameter/default/run-file new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__daemontools_service/parameter/default/servicedir b/cdist/conf/type/__daemontools_service/parameter/default/servicedir new file mode 100644 index 00000000..b74e27f6 --- /dev/null +++ b/cdist/conf/type/__daemontools_service/parameter/default/servicedir @@ -0,0 +1 @@ +/service diff --git a/cdist/conf/type/__daemontools_service/parameter/optional b/cdist/conf/type/__daemontools_service/parameter/optional new file mode 100644 index 00000000..7e54985f --- /dev/null +++ b/cdist/conf/type/__daemontools_service/parameter/optional @@ -0,0 +1,4 @@ +log-run +run +run-file +servicedir From 29bebc4af4944348e4c332b1acb6397e26a36e84 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 31 May 2017 09:55:33 +0200 Subject: [PATCH 0444/1332] Shorten ssh control path. On macos the path is too long due to long default TMP dir. --- cdist/config.py | 17 ++++++++++++----- docs/changelog | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 6b57e7bf..c25c029b 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -27,6 +27,8 @@ import time import itertools import tempfile import socket +import atexit +import shutil import cdist import cdist.hostsource @@ -92,7 +94,6 @@ class Config(object): "failed: %s" % e)) args.manifest = initial_manifest_temp_path - import atexit atexit.register(lambda: os.remove(initial_manifest_temp_path)) # default remote cmd patterns @@ -176,8 +177,15 @@ class Config(object): " ".join(failed_hosts)) @classmethod - def _resolve_remote_cmds(cls, args, host_base_path): - control_path = os.path.join(host_base_path, "ssh-control-path") + def _resolve_ssh_control_path(cls): + base_path = tempfile.mkdtemp() + control_path = os.path.join(base_path, "s") + atexit.register(lambda: shutil.rmtree(base_path)) + return control_path + + @classmethod + def _resolve_remote_cmds(cls, args): + control_path = cls._resolve_ssh_control_path() # If we constructed patterns for remote commands then there is # placeholder for ssh ControlPath, format it and we have unique # ControlPath for each host. @@ -200,8 +208,7 @@ class Config(object): log = logging.getLogger(host) try: - remote_exec, remote_copy = cls._resolve_remote_cmds( - args, host_base_path) + remote_exec, remote_copy = cls._resolve_remote_cmds(args) log.debug("remote_exec for host \"{}\": {}".format( host, remote_exec)) log.debug("remote_copy for host \"{}\": {}".format( diff --git a/docs/changelog b/docs/changelog index 524257a7..be0ed2e3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Type __go_get: Install go packages using go get (Kamila Součková) * Explorer kernel_name: uname -s (Kamila Součková) * Type __sysctl: Add devuan support (Nico Schottelius) + * Core: Shorten ssh control path (Darko Poljak) 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) From 5ec8ac90d9f8e5dd2cafb003e86db9f804863c8a Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Wed, 31 May 2017 18:21:24 +0200 Subject: [PATCH 0445/1332] consul: add http check; add new version --- cdist/conf/type/__consul/files/versions/0.8.1/cksum | 1 + cdist/conf/type/__consul/files/versions/0.8.1/source | 1 + cdist/conf/type/__consul/manifest | 2 +- cdist/conf/type/__consul_agent/manifest | 12 ++++++++---- cdist/conf/type/__consul_service/manifest | 10 ++++++++++ cdist/conf/type/__consul_service/parameter/optional | 1 + 6 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 cdist/conf/type/__consul/files/versions/0.8.1/cksum create mode 100644 cdist/conf/type/__consul/files/versions/0.8.1/source diff --git a/cdist/conf/type/__consul/files/versions/0.8.1/cksum b/cdist/conf/type/__consul/files/versions/0.8.1/cksum new file mode 100644 index 00000000..9125cc8f --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.8.1/cksum @@ -0,0 +1 @@ +283033689 36101209 consul diff --git a/cdist/conf/type/__consul/files/versions/0.8.1/source b/cdist/conf/type/__consul/files/versions/0.8.1/source new file mode 100644 index 00000000..92386c7c --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/0.8.1/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/0.8.1/consul_0.8.1_linux_amd64.zip diff --git a/cdist/conf/type/__consul/manifest b/cdist/conf/type/__consul/manifest index b16c5749..7d0e73c5 100755 --- a/cdist/conf/type/__consul/manifest +++ b/cdist/conf/type/__consul/manifest @@ -23,7 +23,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - scientific|centos|redhat|ubuntu|debian|archlinux|gentoo) + scientific|centos|redhat|ubuntu|debian|devuan|archlinux|gentoo) # any linux should work : ;; diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index 07bf3b26..64efd366 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -23,7 +23,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - scientific|centos|debian|redhat|ubuntu) + scientific|centos|debian|devuan|redhat|ubuntu) # whitelist safeguard : ;; @@ -215,7 +215,11 @@ case "$os" in esac ;; - ubuntu) - init_upstart - ;; + devuan) + init_sysvinit debian + ;; + + ubuntu) + init_upstart + ;; esac diff --git a/cdist/conf/type/__consul_service/manifest b/cdist/conf/type/__consul_service/manifest index 9ba64141..4f52d542 100755 --- a/cdist/conf/type/__consul_service/manifest +++ b/cdist/conf/type/__consul_service/manifest @@ -32,6 +32,10 @@ if [ -f "$__object/parameter/check-script" -a ! -f "$__object/parameter/check-in echo "When using --check-script you must also define --check-interval" >&2 exit 1 fi +if [ -f "$__object/parameter/check-http" -a ! -f "$__object/parameter/check-interval" ]; then + echo "When using --check-http you must also define --check-interval" >&2 + exit 1 +fi # Generate json config file ( @@ -52,6 +56,12 @@ for param in $(ls "$__object/parameter/"); do printf ' "ttl": "%s"\n' "$(cat "$__object/parameter/check-ttl")" printf ' }\n' ;; + check-http) + printf ' ,"check": {\n' + printf ' "http": "%s"\n' "$(cat "$__object/parameter/check-http")" + printf ' ,"interval": "%s"\n' "$(cat "$__object/parameter/check-interval")" + printf ' }\n' + ;; tag) # create json array from newline delimited file tags="$(awk '{printf "\""$1"\","}' "$__object/parameter/tag")" diff --git a/cdist/conf/type/__consul_service/parameter/optional b/cdist/conf/type/__consul_service/parameter/optional index 496e31a3..2e3e8b63 100644 --- a/cdist/conf/type/__consul_service/parameter/optional +++ b/cdist/conf/type/__consul_service/parameter/optional @@ -1,3 +1,4 @@ +check-http check-interval check-script check-ttl From 06e1ddcf4712bd6ad6c759ccc43fdea2a0cb8bfe Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Wed, 31 May 2017 18:57:21 +0200 Subject: [PATCH 0446/1332] __consul_agent: mention http-check in man page --- cdist/conf/type/__consul_service/man.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdist/conf/type/__consul_service/man.rst b/cdist/conf/type/__consul_service/man.rst index bcfe4067..510be3d5 100644 --- a/cdist/conf/type/__consul_service/man.rst +++ b/cdist/conf/type/__consul_service/man.rst @@ -24,6 +24,9 @@ OPTIONAL PARAMETERS check-interval the interval in which the script given with --check-script should be run +check-http + the URL to check for HTTP 200-ish status every --check-interval + check-script the shell command to run every --check-interval From 0b37c79bf4cdca681472a9d4eca5f50aa339c430 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 1 Jun 2017 09:03:42 +0200 Subject: [PATCH 0447/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index be0ed2e3..db0284a7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: * Explorer kernel_name: uname -s (Kamila Součková) * Type __sysctl: Add devuan support (Nico Schottelius) * Core: Shorten ssh control path (Darko Poljak) + * Type __consul: Add new version and add http check (Kamila Součková) 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) From d30103e9d2ea55013517ebd25029a5ab7292c6b5 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Thu, 1 Jun 2017 17:43:43 +0200 Subject: [PATCH 0448/1332] __daemontools*: add/improve; + add man pages --- .../type/__daemontools/files/init.d-svscan | 63 +++++++++++++++++++ cdist/conf/type/__daemontools/man.rst | 42 +++++++++++++ cdist/conf/type/__daemontools/manifest | 20 ++++++ .../conf/type/__daemontools/parameter/boolean | 1 + .../parameter/default/from-package | 1 + .../parameter/default/install-init-script | 0 .../type/__daemontools/parameter/optional | 1 + cdist/conf/type/__daemontools/singleton | 0 .../type/__daemontools_service/explorer/svc | 1 + cdist/conf/type/__daemontools_service/man.rst | 63 +++++++++++++++++++ .../conf/type/__daemontools_service/manifest | 7 +++ 11 files changed, 199 insertions(+) create mode 100644 cdist/conf/type/__daemontools/files/init.d-svscan create mode 100644 cdist/conf/type/__daemontools/man.rst create mode 100644 cdist/conf/type/__daemontools/manifest create mode 100644 cdist/conf/type/__daemontools/parameter/boolean create mode 100644 cdist/conf/type/__daemontools/parameter/default/from-package create mode 100644 cdist/conf/type/__daemontools/parameter/default/install-init-script create mode 100644 cdist/conf/type/__daemontools/parameter/optional create mode 100644 cdist/conf/type/__daemontools/singleton create mode 100644 cdist/conf/type/__daemontools_service/explorer/svc create mode 100644 cdist/conf/type/__daemontools_service/man.rst diff --git a/cdist/conf/type/__daemontools/files/init.d-svscan b/cdist/conf/type/__daemontools/files/init.d-svscan new file mode 100644 index 00000000..127dfdb3 --- /dev/null +++ b/cdist/conf/type/__daemontools/files/init.d-svscan @@ -0,0 +1,63 @@ +#!/bin/bash +### BEGIN INIT INFO +# Provides: svscan +# Required-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: svscan +# Description: djb svscan +### END INIT INFO +# from https://gist.githubusercontent.com/pacojp/5766990/raw/2ed009ab19515afc9e58291b636d673c5ca864b3/init.d.svscan +# written by Adam McKenna +# edited by Kamila Součková + +export PATH=$PATH:/usr/local/bin + +l=/var/log/svscan + +if [ ! -d $l ]; then + mkdir $l + chown daemon $l +fi + +case "$1" in + start) + echo -n "Starting daemontools: " + if [ ! `pidof svscan` ]; then + echo -n "svscan " + env - PATH="$PATH" svscan /service 2>&1 | setuidgid daemon multilog t /var/log/svscan & + echo "." + else + echo "already running." + fi + ;; + stop) + echo -n "Stopping daemontools: " + if [ `pidof svscan` ]; then + echo -n "svscan" + while [ `pidof svscan` ]; do + kill `pidof svscan` + echo -n "." + done + fi + echo -n " services" + for i in `ls -d /service/*`; do + svc -dx $i + echo -n "." + done + echo -n " logging " + for i in `ls -d /service/*/log`; do + svc -dx $i + echo -n "." + done + echo "" + ;; + restart|force-reload) + $0 stop + $0 start + ;; + *) + echo 'Usage: /etc/init.d/svscan {start|stop|restart|force-reload}' + exit 1 +esac diff --git a/cdist/conf/type/__daemontools/man.rst b/cdist/conf/type/__daemontools/man.rst new file mode 100644 index 00000000..62dc5681 --- /dev/null +++ b/cdist/conf/type/__daemontools/man.rst @@ -0,0 +1,42 @@ +cdist-type__daemontools(7) +========================== + +NAME +---- +cdist-type__daemontools - Install daemontools + + +DESCRIPTION +----------- +Install djb daemontools and (optionally) an init script. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +from-package + Package to install. Must be compatible with the original daemontools. Example: daemontools-encore. Default: daemontools. + +BOOLEAN PARAMETERS +------------------ +install-init-script + Add an init script and set it to start on boot. Default yes. + +EXAMPLES +-------- + +.. code-block:: sh + + __daemontools --from-package daemontools-encore # if you prefer + +SEE ALSO +-------- +cdist-type__daemontools_service + +AUTHORS +------- +Kamila Součková diff --git a/cdist/conf/type/__daemontools/manifest b/cdist/conf/type/__daemontools/manifest new file mode 100644 index 00000000..550994a7 --- /dev/null +++ b/cdist/conf/type/__daemontools/manifest @@ -0,0 +1,20 @@ +#!/bin/sh + +pkg=$(cat "$__object/parameter/from-package") + +__package $pkg + +if [ -f "$__object/parameter/install-init-script" ]; then + init=$(cat "$__global/explorer/init") + case $init in + init) + __config_file /etc/init.d/svscan --mode 755 --source "$__type/files/init.d-svscan" + require="$require __config_file/etc/init.d/svscan" __start_on_boot svscan + require="$require __start_on_boot/svscan" __process svscan --start 'service svscan start' + ;; + *) + echo "Your init system ($init) is not supported by this type. Submit a patch at github.com/ungleich/cdist!" + exit 1 + ;; + esac +fi diff --git a/cdist/conf/type/__daemontools/parameter/boolean b/cdist/conf/type/__daemontools/parameter/boolean new file mode 100644 index 00000000..99a1cefd --- /dev/null +++ b/cdist/conf/type/__daemontools/parameter/boolean @@ -0,0 +1 @@ +install-init-script diff --git a/cdist/conf/type/__daemontools/parameter/default/from-package b/cdist/conf/type/__daemontools/parameter/default/from-package new file mode 100644 index 00000000..598dd40a --- /dev/null +++ b/cdist/conf/type/__daemontools/parameter/default/from-package @@ -0,0 +1 @@ +daemontools diff --git a/cdist/conf/type/__daemontools/parameter/default/install-init-script b/cdist/conf/type/__daemontools/parameter/default/install-init-script new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__daemontools/parameter/optional b/cdist/conf/type/__daemontools/parameter/optional new file mode 100644 index 00000000..8eca305b --- /dev/null +++ b/cdist/conf/type/__daemontools/parameter/optional @@ -0,0 +1 @@ +from-package diff --git a/cdist/conf/type/__daemontools/singleton b/cdist/conf/type/__daemontools/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__daemontools_service/explorer/svc b/cdist/conf/type/__daemontools_service/explorer/svc new file mode 100644 index 00000000..4a867485 --- /dev/null +++ b/cdist/conf/type/__daemontools_service/explorer/svc @@ -0,0 +1 @@ +command -v svc diff --git a/cdist/conf/type/__daemontools_service/man.rst b/cdist/conf/type/__daemontools_service/man.rst new file mode 100644 index 00000000..aa15a826 --- /dev/null +++ b/cdist/conf/type/__daemontools_service/man.rst @@ -0,0 +1,63 @@ +cdist-type__daemontools_service(7) +================================== + +NAME +---- +cdist-type__daemontools_service - Create a daemontools-compatible service dir. + + +DESCRIPTION +----------- +Create a directory structure compatible with daemontools-like service management. + +Note that svc must be present on the target system. + +The object ID will be used as the service name. + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +run + Command to run. exec-ing and stderr redirection will be added. One of run, run-file must be specified. + + Example: `my-program` + +run-file + File to save as /run. One of run, run-file must be specified. + + Example: +.. code-block:: sh + #!/bin/sh + exec 2>&1 + exec my_program + + +log-run + Command to run for log consumption. Default: `multilog t ./main` + +servicedir + Directory to install into. Default: `/service` + +BOOLEAN PARAMETERS +------------------ +None. + +EXAMPLES +-------- + +.. code-block:: sh + + require="__daemontools" __daemontools_service prometheus --run "setuidgid prometheus $GOBIN/prometheus $FLAGS" + + +SEE ALSO +-------- +cdist-type__daemontools + + +AUTHORS +------- +Kamila Součková diff --git a/cdist/conf/type/__daemontools_service/manifest b/cdist/conf/type/__daemontools_service/manifest index 34f45545..175066af 100644 --- a/cdist/conf/type/__daemontools_service/manifest +++ b/cdist/conf/type/__daemontools_service/manifest @@ -10,6 +10,13 @@ run=$(cat "$__object/parameter/run") runfile=$(cat "$__object/parameter/run-file") logrun=$(cat "$__object/parameter/log-run") +svc=$(cat "$__type/explorer/svc") + +if [ -z "$svc" ]; then + echo "svc not found! Install daemontools first: see __daemontools" + exit 1 +fi + badusage() { echo "__daemontools_service/$__object_id: exactly one of --run, --run-file must be set" >&2 exit 1 From 5ac324cd91c12c088c531f69661f076421959e40 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Thu, 1 Jun 2017 22:26:18 +0200 Subject: [PATCH 0449/1332] sacrifice to the evil manpage demons --- cdist/conf/type/__daemontools/man.rst | 9 ++++++++- cdist/conf/type/__daemontools_service/man.rst | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__daemontools/man.rst b/cdist/conf/type/__daemontools/man.rst index 62dc5681..2e012cb5 100644 --- a/cdist/conf/type/__daemontools/man.rst +++ b/cdist/conf/type/__daemontools/man.rst @@ -35,8 +35,15 @@ EXAMPLES SEE ALSO -------- -cdist-type__daemontools_service +:strong:`cdist-type__daemontools_service`\ (7) AUTHORS ------- Kamila Součková + +COPYING +------- +Copyright \(C) 2017 Kamila Součková. 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/__daemontools_service/man.rst b/cdist/conf/type/__daemontools_service/man.rst index aa15a826..0d75917e 100644 --- a/cdist/conf/type/__daemontools_service/man.rst +++ b/cdist/conf/type/__daemontools_service/man.rst @@ -55,9 +55,16 @@ EXAMPLES SEE ALSO -------- -cdist-type__daemontools +:strong:`cdist-type__daemontools`\ (7) AUTHORS ------- Kamila Součková + +COPYING +------- +Copyright \(C) 2017 Kamila Součková. 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. From c16277bb8fc36f207fdabc533ce01406ff609188 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Thu, 1 Jun 2017 22:55:58 +0200 Subject: [PATCH 0450/1332] =?UTF-8?q?manpage=20d=C3=A6mons=20won't=20stop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cdist/conf/type/__daemontools_service/man.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__daemontools_service/man.rst b/cdist/conf/type/__daemontools_service/man.rst index 0d75917e..66360361 100644 --- a/cdist/conf/type/__daemontools_service/man.rst +++ b/cdist/conf/type/__daemontools_service/man.rst @@ -29,6 +29,7 @@ run-file File to save as /run. One of run, run-file must be specified. Example: + .. code-block:: sh #!/bin/sh exec 2>&1 From 42bc5e28b90d4143c8f7318773bd601f8b54f3c7 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Thu, 1 Jun 2017 23:01:03 +0200 Subject: [PATCH 0451/1332] WHY can't I write a man page? --- cdist/conf/type/__daemontools_service/man.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__daemontools_service/man.rst b/cdist/conf/type/__daemontools_service/man.rst index 66360361..ec1d20ff 100644 --- a/cdist/conf/type/__daemontools_service/man.rst +++ b/cdist/conf/type/__daemontools_service/man.rst @@ -31,6 +31,7 @@ run-file Example: .. code-block:: sh + #!/bin/sh exec 2>&1 exec my_program From 8d5e20757778c1f7d27f2f188d5584aabda51a06 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 1 Jun 2017 23:08:25 +0200 Subject: [PATCH 0452/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index db0284a7..e691145c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Type __sysctl: Add devuan support (Nico Schottelius) * Core: Shorten ssh control path (Darko Poljak) * Type __consul: Add new version and add http check (Kamila Součková) + * New types: __daemontools and __daemontools_service (Kamila Součková) 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) From 2272539c16e594a3c4705b9aa4466b42f680d716 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Thu, 1 Jun 2017 23:52:23 +0200 Subject: [PATCH 0453/1332] is it Christmas today? So many new awesome types! --- .../type/__prometheus_alertmanager/man.rst | 66 ++++++++++++++++ .../type/__prometheus_alertmanager/manifest | 39 ++++++++++ .../parameter/default/storage-path | 1 + .../parameter/optional | 1 + .../parameter/required | 2 + .../type/__prometheus_alertmanager/singleton | 0 cdist/conf/type/__prometheus_server/man.rst | 78 +++++++++++++++++++ cdist/conf/type/__prometheus_server/manifest | 57 ++++++++++++++ .../__prometheus_server/parameter/boolean | 1 + .../parameter/default/retention-days | 1 + .../parameter/default/rule-files | 0 .../parameter/default/storage-path | 1 + .../parameter/default/target-heap-size | 1 + .../parameter/default/with-daemontools | 0 .../__prometheus_server/parameter/optional | 4 + .../__prometheus_server/parameter/required | 3 + cdist/conf/type/__prometheus_server/singleton | 0 17 files changed, 255 insertions(+) create mode 100644 cdist/conf/type/__prometheus_alertmanager/man.rst create mode 100644 cdist/conf/type/__prometheus_alertmanager/manifest create mode 100644 cdist/conf/type/__prometheus_alertmanager/parameter/default/storage-path create mode 100644 cdist/conf/type/__prometheus_alertmanager/parameter/optional create mode 100644 cdist/conf/type/__prometheus_alertmanager/parameter/required create mode 100644 cdist/conf/type/__prometheus_alertmanager/singleton create mode 100644 cdist/conf/type/__prometheus_server/man.rst create mode 100644 cdist/conf/type/__prometheus_server/manifest create mode 100644 cdist/conf/type/__prometheus_server/parameter/boolean create mode 100644 cdist/conf/type/__prometheus_server/parameter/default/retention-days create mode 100644 cdist/conf/type/__prometheus_server/parameter/default/rule-files create mode 100644 cdist/conf/type/__prometheus_server/parameter/default/storage-path create mode 100644 cdist/conf/type/__prometheus_server/parameter/default/target-heap-size create mode 100644 cdist/conf/type/__prometheus_server/parameter/default/with-daemontools create mode 100644 cdist/conf/type/__prometheus_server/parameter/optional create mode 100644 cdist/conf/type/__prometheus_server/parameter/required create mode 100644 cdist/conf/type/__prometheus_server/singleton diff --git a/cdist/conf/type/__prometheus_alertmanager/man.rst b/cdist/conf/type/__prometheus_alertmanager/man.rst new file mode 100644 index 00000000..f218254e --- /dev/null +++ b/cdist/conf/type/__prometheus_alertmanager/man.rst @@ -0,0 +1,66 @@ +cdist-type__prometheus_alertmanager(7) +====================================== + +NAME +---- +cdist-type__prometheus_alertmanager - install Alertmanager + + +DESCRIPTION +----------- +Install and configure Prometheus Alertmanager (https://prometheus.io/docs/alerting/alertmanager/). + + +REQUIRED PARAMETERS +------------------- +config + Alertmanager configuration file. It will be saved as /etc/alertmanager/alertmanager.yml on the target. +listen-address + Passed as web.listen-address. + + +OPTIONAL PARAMETERS +------------------- +storage-path + Where to put data. Default: /data/alertmanager. (Directory will be created if needed.) + + +BOOLEAN PARAMETERS +------------------ +with-daemontools + Create a daemontools service directory under /service/prometheus. Default: yes. + Note: If you do not use this, Alertmanager will not be launched, and will not reload config on change. + If you use this, daemontools (or something compatible) must be installed. + + +EXAMPLES +-------- + +.. code-block:: sh + + ALERTPORT=9093 + + __daemontools + __golang_from_vendor --version 1.8.1 # required for prometheus and many exporters + + require="__daemontools __golang_from_vendor" __prometheus_alertmanager \ + --config "$__manifest/files/alertmanager.yml" \ + --storage-path /data/alertmanager \ + --listen-address "[::]:$ALERTPORT" + + +SEE ALSO +-------- +:strong:`cdist-type__prometheus_server`\ (7), :strong:`cdist-type__daemontools`\ (7), +Prometheus alerting documentation: https://prometheus.io/docs/alerting/overview/ + +AUTHORS +------- +Kamila Součková + +COPYING +------- +Copyright \(C) 2017 Kamila Součková. 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/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest new file mode 100644 index 00000000..61ac2d20 --- /dev/null +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -0,0 +1,39 @@ +#!/bin/sh + +GOBIN=/opt/gocode/bin # where to find go binaries +CONF_DIR=/etc/prometheus +LOGLEVEL=info +CONF=$CONF_DIR/alertmanager.yml + +### Prometheus server ####################################################### + +config="$(cat "$__object/parameter/config")" +storage_path="$(cat "$__object/parameter/storage-path")" +listen_address="$(cat "$__object/parameter/listen-address")" + +ONCHANGE="" +if [ -f "$__object/parameter/with-daemontools" ]; then + __daemontools_service prometheus --run "setuidgid prometheus $GOBIN/prometheus $REAL_FLAGS" + ONCHANGE="svc -h /service/prometheus" +fi + +FLAGS="config.file '$CONF' +storage.path '$storage_path' +web.listen-address '$listen_address' +log.level $LOGLEVEL" + +REAL_FLAGS="$(echo "$FLAGS" | sed -nE 's/^([^#]+).*/ --\1 \\/p')" + +__go_get github.com/prometheus/alertmanager/cmd/... + +__user prometheus --system +__directory "$storage_path" --owner prometheus +__directory "$CONF_DIR" --owner prometheus + +__daemontools_service alertmanager --run "setuidgid prometheus $GOBIN/alertmanager $REAL_FLAGS" + +require="$require __directory/$storage_path" \ +__config_file $CONF \ + --source $config \ + --group prometheus --mode 640 \ + --onchange "$ONCHANGE" diff --git a/cdist/conf/type/__prometheus_alertmanager/parameter/default/storage-path b/cdist/conf/type/__prometheus_alertmanager/parameter/default/storage-path new file mode 100644 index 00000000..4f3e7559 --- /dev/null +++ b/cdist/conf/type/__prometheus_alertmanager/parameter/default/storage-path @@ -0,0 +1 @@ +/data/alertmanager diff --git a/cdist/conf/type/__prometheus_alertmanager/parameter/optional b/cdist/conf/type/__prometheus_alertmanager/parameter/optional new file mode 100644 index 00000000..f99d0d37 --- /dev/null +++ b/cdist/conf/type/__prometheus_alertmanager/parameter/optional @@ -0,0 +1 @@ +storage-path diff --git a/cdist/conf/type/__prometheus_alertmanager/parameter/required b/cdist/conf/type/__prometheus_alertmanager/parameter/required new file mode 100644 index 00000000..02cb49d0 --- /dev/null +++ b/cdist/conf/type/__prometheus_alertmanager/parameter/required @@ -0,0 +1,2 @@ +config +listen-address diff --git a/cdist/conf/type/__prometheus_alertmanager/singleton b/cdist/conf/type/__prometheus_alertmanager/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__prometheus_server/man.rst b/cdist/conf/type/__prometheus_server/man.rst new file mode 100644 index 00000000..c03a71d5 --- /dev/null +++ b/cdist/conf/type/__prometheus_server/man.rst @@ -0,0 +1,78 @@ +cdist-type__prometheus_server(7) +================================ + +NAME +---- +cdist-type__prometheus_server - install Prometheus + + +DESCRIPTION +----------- +Install and configure Prometheus (https://prometheus.io/). + + +REQUIRED PARAMETERS +------------------- +config + Prometheus configuration file. It will be saved as /etc/prometheus/prometheus.yml on the target. +listen-address + Passed as web.listen-address. +alertmanager-url + Passed as alertmanager.url + + +OPTIONAL PARAMETERS +------------------- +retention-days + How long to keep data. Default: 30 +rule-files + Path to rule files. They will be installed under /etc/prometheus/. You need to include `rule_files: [/etc/prometheus/]` in the config file if you use this. +storage-path + Where to put data. Default: /data/prometheus. (Directory will be created if needed.) +target-heap-size + Passed as storage.local.target-heap-size. Default: 1/2 of RAM. + + +BOOLEAN PARAMETERS +------------------ +with-daemontools + Create a daemontools service directory under /service/prometheus. Default: yes. + Note: If you do not use this, Prometheus will not be launched, and will not reload config on change. + If you use this, daemontools (or something compatible) must be installed. + + +EXAMPLES +-------- + +.. code-block:: sh + + PROMPORT=9090 + ALERTPORT=9093 + + __daemontools + __golang_from_vendor --version 1.8.1 # required for prometheus and many exporters + + require="__daemontools __golang_from_vendor" __prometheus_server \ + --config "$__manifest/files/prometheus.yml" \ + --retention-days 14 \ + --storage-path /data/prometheus \ + --listen-address "[::]:$PROMPORT" \ + --rule-files "$__manifest/files/*.rules" \ + --alertmanager-url "http://monitoring1.node.consul:$ALERTPORT,http://monitoring2.node.consul:$ALERTPORT" + + +SEE ALSO +-------- +:strong:`cdist-type__prometheus_alertmanager`\ (7), :strong:`cdist-type__daemontools`\ (7), +Prometheus documentation: https://prometheus.io/docs/introduction/overview/ + +AUTHORS +------- +Kamila Součková + +COPYING +------- +Copyright \(C) 2017 Kamila Součková. 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/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest new file mode 100644 index 00000000..dd81701d --- /dev/null +++ b/cdist/conf/type/__prometheus_server/manifest @@ -0,0 +1,57 @@ +#!/bin/sh + +GOBIN=/opt/gocode/bin # where to find go binaries +CONF_DIR=/etc/prometheus +CONF=$CONF_DIR/prometheus.yml +LOGLEVEL=info + +config="$(cat "$__object/parameter/config")" +retention_days="$(cat "$__object/parameter/retention-days")" +storage_path="$(cat "$__object/parameter/storage-path")" +listen_address="$(cat "$__object/parameter/listen-address")" +alertmanager_url="$(cat "$__object/parameter/alertmanager-url")" +target_heap_size="$(cat "$__object/parameter/target-heap-size")" +rule_files="$(cat "$__object/parameter/rule-files")" + +# explorer in kB => convert; by default we go with 1/2 RAM +[ "$target_heap_size" = "auto" ] && target_heap_size=$(($(cat $__global/explorer/memory)*1024/2)) + +ONCHANGE="" +if [ -f "$__object/parameter/with-daemontools" ]; then + __daemontools_service prometheus --run "setuidgid prometheus $GOBIN/prometheus $REAL_FLAGS" + ONCHANGE="&& svc -h /service/prometheus" +fi + +FLAGS="config.file '$CONF' +storage.local.path '$storage_path' +storage.local.target-heap-size $(($target_heap_size)) # in bytes; should be 2/3 of available memory because it may be hungry +storage.local.retention $(($retention_days*24))h # golang doesn't have days :D +web.listen-address '$listen_address' +alertmanager.url '$alertmanager_url' +log.level $LOGLEVEL" + +REAL_FLAGS="$(echo "$FLAGS" | sed -nE 's/^([^#]+).*/ --\1 \\/p')" + +__go_get github.com/prometheus/prometheus/cmd/... + +__user prometheus --system +__directory "$storage_path" --owner prometheus +__directory "$CONF_DIR" --owner prometheus + + + +require="$require __directory/$storage_path" \ +__config_file $CONF \ + --source $config \ + --group prometheus --mode 640 \ + --onchange "$GOBIN/promtool check-config $CONF $ONCHANGE" + +for file in $rule_files; do + dest=$CONF_DIR/$(basename $file) + require="$require __directory/$CONF_DIR" \ + __config_file "$dest" \ + --source "$file" \ + --owner prometheus \ + --onchange "$GOBIN/promtool check-rules '$dest' $ONCHANGE" +done + diff --git a/cdist/conf/type/__prometheus_server/parameter/boolean b/cdist/conf/type/__prometheus_server/parameter/boolean new file mode 100644 index 00000000..de4eefdd --- /dev/null +++ b/cdist/conf/type/__prometheus_server/parameter/boolean @@ -0,0 +1 @@ +with-daemontools diff --git a/cdist/conf/type/__prometheus_server/parameter/default/retention-days b/cdist/conf/type/__prometheus_server/parameter/default/retention-days new file mode 100644 index 00000000..64bb6b74 --- /dev/null +++ b/cdist/conf/type/__prometheus_server/parameter/default/retention-days @@ -0,0 +1 @@ +30 diff --git a/cdist/conf/type/__prometheus_server/parameter/default/rule-files b/cdist/conf/type/__prometheus_server/parameter/default/rule-files new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__prometheus_server/parameter/default/storage-path b/cdist/conf/type/__prometheus_server/parameter/default/storage-path new file mode 100644 index 00000000..fc05f8f3 --- /dev/null +++ b/cdist/conf/type/__prometheus_server/parameter/default/storage-path @@ -0,0 +1 @@ +/data/prometheus diff --git a/cdist/conf/type/__prometheus_server/parameter/default/target-heap-size b/cdist/conf/type/__prometheus_server/parameter/default/target-heap-size new file mode 100644 index 00000000..865faf10 --- /dev/null +++ b/cdist/conf/type/__prometheus_server/parameter/default/target-heap-size @@ -0,0 +1 @@ +auto diff --git a/cdist/conf/type/__prometheus_server/parameter/default/with-daemontools b/cdist/conf/type/__prometheus_server/parameter/default/with-daemontools new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__prometheus_server/parameter/optional b/cdist/conf/type/__prometheus_server/parameter/optional new file mode 100644 index 00000000..4d8d8f3e --- /dev/null +++ b/cdist/conf/type/__prometheus_server/parameter/optional @@ -0,0 +1,4 @@ +target-heap-size +retention-days +rule-files +storage-path diff --git a/cdist/conf/type/__prometheus_server/parameter/required b/cdist/conf/type/__prometheus_server/parameter/required new file mode 100644 index 00000000..49abf924 --- /dev/null +++ b/cdist/conf/type/__prometheus_server/parameter/required @@ -0,0 +1,3 @@ +alertmanager-url +config +listen-address diff --git a/cdist/conf/type/__prometheus_server/singleton b/cdist/conf/type/__prometheus_server/singleton new file mode 100644 index 00000000..e69de29b From f87cce28d1ca0219c958a3c3bf032c18a852efa9 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Fri, 2 Jun 2017 15:28:52 +0200 Subject: [PATCH 0454/1332] new type: __grafana_dashboard --- cdist/conf/type/__grafana_dashboard/man.rst | 43 +++++++++++++++++++ cdist/conf/type/__grafana_dashboard/manifest | 23 ++++++++++ cdist/conf/type/__grafana_dashboard/singleton | 0 3 files changed, 66 insertions(+) create mode 100644 cdist/conf/type/__grafana_dashboard/man.rst create mode 100644 cdist/conf/type/__grafana_dashboard/manifest create mode 100644 cdist/conf/type/__grafana_dashboard/singleton diff --git a/cdist/conf/type/__grafana_dashboard/man.rst b/cdist/conf/type/__grafana_dashboard/man.rst new file mode 100644 index 00000000..b3974028 --- /dev/null +++ b/cdist/conf/type/__grafana_dashboard/man.rst @@ -0,0 +1,43 @@ +cdist-type__grafana_dashboard(7) +================================ + +NAME +---- +cdist-type__grafana_dashboard - Install Grafana (https://grafana.com) + + +DESCRIPTION +----------- +This cdist type adds the Grafana repository, installs the grafana package, and sets the server to start on boot. + +This is a singleton type. + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + __grafana_dashboard + + +AUTHORS +------- +Kamila Součková + + +COPYING +------- +Copyright \(C) 2017 Kamila Součková. 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/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest new file mode 100644 index 00000000..c5bc78d2 --- /dev/null +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -0,0 +1,23 @@ +os=$(cat $__global/explorer/os) + +case $os in + debian|devuan) + __apt_key_uri grafana \ + --name 'Grafana Release Signing Key' \ + --uri https://packagecloud.io/gpg.key + + require="__apt_key_uri/grafana" __apt_source grafana \ + --uri https://packagecloud.io/grafana/stable/debian/ \ + --distribution jessie \ + --component main + + __package apt-transport-https + + require="__apt_source/grafana __package/apt-transport-https" __package grafana + require="__package/grafana" __start_on_boot grafana-server + ;; + *) + echo "Don't know how to install Grafana on $os. Send us a pull request!" + exit 1 + ;; +esac diff --git a/cdist/conf/type/__grafana_dashboard/singleton b/cdist/conf/type/__grafana_dashboard/singleton new file mode 100644 index 00000000..e69de29b From 4c9863cc542e5e77bc17a19814dd8048de86488b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 2 Jun 2017 17:39:43 +0200 Subject: [PATCH 0455/1332] Update changelog --- docs/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index e691145c..c33ad05a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,7 +8,8 @@ next: * Type __sysctl: Add devuan support (Nico Schottelius) * Core: Shorten ssh control path (Darko Poljak) * Type __consul: Add new version and add http check (Kamila Součková) - * New types: __daemontools and __daemontools_service (Kamila Součková) + * New types: __daemontools and __daemontools_service (Kamila Součková) + * New types: __prometheus_server and __prometheus_alertmanager (Kamila Součková) 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) From 91ff80fa6adce3b91790eff8bb51b2863a47dc7e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 3 Jun 2017 18:15:44 +0200 Subject: [PATCH 0456/1332] Add devuan support for __start_on_boot --- cdist/conf/type/__start_on_boot/gencode-remote | 2 +- docs/changelog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 45de5465..0ab67a1a 100644 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -93,7 +93,7 @@ case "$state_should" in else case "$os" in - debian|ubuntu) + debian|ubuntu|devuan) echo update-rc.d -f \"$name\" remove ;; diff --git a/docs/changelog b/docs/changelog index 524257a7..92123b70 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Type __go_get: Install go packages using go get (Kamila Součková) * Explorer kernel_name: uname -s (Kamila Součková) * Type __sysctl: Add devuan support (Nico Schottelius) + * Type __start_on_boot: Add devuan support (Nico Schottelius) 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) From 4c7327e81462d11d7ba53bf6c38a990f12549c84 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Fri, 9 Jun 2017 18:40:47 +0200 Subject: [PATCH 0457/1332] consider de(bi|vu)an version --- cdist/conf/type/__grafana_dashboard/manifest | 29 +++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest index c5bc78d2..b6e3020e 100644 --- a/cdist/conf/type/__grafana_dashboard/manifest +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -1,20 +1,29 @@ os=$(cat $__global/explorer/os) +os_version=$(cat $__global/explorer/os_version) case $os in debian|devuan) - __apt_key_uri grafana \ - --name 'Grafana Release Signing Key' \ - --uri https://packagecloud.io/gpg.key + case $os_version in + 8*|jessie) + __apt_key_uri grafana \ + --name 'Grafana Release Signing Key' \ + --uri https://packagecloud.io/gpg.key - require="__apt_key_uri/grafana" __apt_source grafana \ - --uri https://packagecloud.io/grafana/stable/debian/ \ - --distribution jessie \ - --component main + require="__apt_key_uri/grafana" __apt_source grafana \ + --uri https://packagecloud.io/grafana/stable/debian/ \ + --distribution jessie \ + --component main - __package apt-transport-https + __package apt-transport-https - require="__apt_source/grafana __package/apt-transport-https" __package grafana - require="__package/grafana" __start_on_boot grafana-server + require="__apt_source/grafana __package/apt-transport-https" __package grafana + require="__package/grafana" __start_on_boot grafana-server + ;; + *) + echo "Don't know how to install Grafana on $os $os_version. Send us a pull request!" + exit 1 + ;; + esac ;; *) echo "Don't know how to install Grafana on $os. Send us a pull request!" From d6ca07795991ffa444a0219a6edfd24b2430fea3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 11 Jun 2017 13:58:47 +0200 Subject: [PATCH 0458/1332] Fix cdist man page text. --- docs/src/man1/cdist.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index adabe052..e975a407 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -268,12 +268,12 @@ This limit is controlled with sshd :strong:`MaxSessions` configuration options. For more details refer to :strong:`sshd_config`\ (5). When requirements for the same object are defined in different manifests (see -example below) in init manifest and in some other type manifest and they differs -then dependency resolver cannot detect dependencies right. This happens because -cdist cannot prepare all objects first and then run objects because some -object can depend on the result of type explorer(s) and explorers are executed -during object run. cdist will detect such case and write warning message. -Example for such a case: +example below), for example, in init manifest and in some other type manifest +and those requirements differ then dependency resolver cannot detect +dependencies right. This happens because cdist cannot prepare all objects first +and run all objects afterwards. Some object can depend on the result of type +explorer(s) and explorers are executed during object run. cdist will detect +such case and write warning message. Example for such a case: .. code-block:: sh From d4ec3a709d2281f32e0b115aa324b7bbeafbe0dd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 11 Jun 2017 14:01:16 +0200 Subject: [PATCH 0459/1332] Update cdist man page copyright. --- docs/src/man1/cdist.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index e975a407..72cee4cc 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -298,5 +298,5 @@ such case and write warning message. Example for such a case: COPYING ------- -Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is +Copyright \(C) 2011-2017 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License v3 or later (GPLv3+). From 0ec361165dd558aa8aebfd18955f4c34c5b5afb6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 11 Jun 2017 14:02:47 +0200 Subject: [PATCH 0460/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index a0eacaf4..75147776 100644 --- a/docs/changelog +++ b/docs/changelog @@ -11,6 +11,7 @@ next: * Type __consul: Add new version and add http check (Kamila Součková) * New types: __daemontools and __daemontools_service (Kamila Součková) * New types: __prometheus_server and __prometheus_alertmanager (Kamila Součková) + * New type: __grafana_dashboard (Kamila Součková) 4.4.2: 2017-03-08 * Core: Fix suppression of manifests' outputs (Darko Poljak) From 9aeea937c4a293c67f916c6534df2042534ac5e2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 13 Jun 2017 18:04:41 +0200 Subject: [PATCH 0461/1332] Fix spelling. --- cdist/conf/type/__firewalld_rule/man.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__firewalld_rule/man.rst b/cdist/conf/type/__firewalld_rule/man.rst index 53ae52b8..5de5d15c 100644 --- a/cdist/conf/type/__firewalld_rule/man.rst +++ b/cdist/conf/type/__firewalld_rule/man.rst @@ -38,7 +38,7 @@ EXAMPLES .. code-block:: sh - # Allow acces from entrance.place4.ungleich.ch + # Allow access from entrance.place4.ungleich.ch __firewalld_rule entrance \ --protocol ipv4 \ --table filter \ From 8cd2136d8e285b2067b34e59b10071b7796bb6a3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 13 Jun 2017 18:07:11 +0200 Subject: [PATCH 0462/1332] Release 4.4.3 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 75147776..33d056e7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.4.3: 2017-06-13 * Type __golang_from_vendor: Install golang from https://golang.org/dl/ (Kamila Součková) * Type __go_get: Install go packages using go get (Kamila Součková) * Explorer kernel_name: uname -s (Kamila Součková) From e32f2110ab412460088a1a5bdc09895e4743cb3d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 13 Jun 2017 22:54:40 +0200 Subject: [PATCH 0463/1332] Document object prepare and object run parallelization. --- cdist/argparse.py | 5 +++-- docs/changelog | 3 +++ docs/src/cdist-parallelization.rst | 5 +++-- docs/src/man1/cdist.rst | 5 +++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 3791e779..045c12bc 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -127,8 +127,9 @@ def get_parsers(): parser['config_main'].add_argument( '-j', '--jobs', nargs='?', type=check_positive_int, - help=('Specify the maximum number of parallel jobs, currently ' - 'only global explorers are supported'), + help=('Specify the maximum number of parallel jobs. Global' + 'explorers, object prepare and object run are supported' + '(currently in beta'), action='store', dest='jobs', const=multiprocessing.cpu_count()) parser['config_main'].add_argument( diff --git a/docs/changelog b/docs/changelog index 33d056e7..1631b997 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Support -j parallelization for object prepare and object run (Darko Poljak) + 4.4.3: 2017-06-13 * Type __golang_from_vendor: Install golang from https://golang.org/dl/ (Kamila Součková) * Type __go_get: Install go packages using go get (Kamila Součková) diff --git a/docs/src/cdist-parallelization.rst b/docs/src/cdist-parallelization.rst index ce9f5bca..ed3afae9 100644 --- a/docs/src/cdist-parallelization.rst +++ b/docs/src/cdist-parallelization.rst @@ -11,8 +11,9 @@ with :strong:`-p/--parallel` option. The other way is to operate in parallel within one host where you specify the number of jobs. This is enabled with :strong:`-j/--jobs` option where you can specify the number of parallel jobs. By default, -:strong:`multiprocessing.cpu_count()` is used. For this mode only global -explorers are currently supported and this option is still in :strong:`beta`. +:strong:`multiprocessing.cpu_count()` is used. For this mode global explorers, +object preparation and object run are supported and this option is still in +:strong:`beta`. You can, of course, use those two options together. This means that each host will be processed by its own process. Within each process cdist will operate diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 72cee4cc..a46e1e02 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -99,8 +99,9 @@ Configure/install one or more hosts. .. option:: -j [JOBS], --jobs [JOBS] - Specify the maximum number of parallel jobs; currently only - global explorers are supported (currently in beta) + Specify the maximum number of parallel jobs. Global + explorers, object prepare and object run are supported + (currently in beta). .. option:: -n, --dry-run From 5d148a58d2ed93c88c3700bc87d98b3cd766bc65 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Thu, 15 Jun 2017 11:13:39 +0200 Subject: [PATCH 0464/1332] fix missing dependencies in __prometheus_*, __go_get --- cdist/conf/type/__daemontools/man.rst | 2 +- .../parameter/default/install-init-script | 0 .../type/__daemontools_service/explorer/svc | 2 +- cdist/conf/type/__go_get/manifest | 1 + .../type/__prometheus_alertmanager/man.rst | 9 +++++---- .../type/__prometheus_alertmanager/manifest | 12 +++--------- cdist/conf/type/__prometheus_server/man.rst | 9 +++++---- cdist/conf/type/__prometheus_server/manifest | 19 +++++++------------ .../__prometheus_server/parameter/boolean | 1 - .../parameter/default/with-daemontools | 0 10 files changed, 23 insertions(+), 32 deletions(-) delete mode 100644 cdist/conf/type/__daemontools/parameter/default/install-init-script delete mode 100644 cdist/conf/type/__prometheus_server/parameter/boolean delete mode 100644 cdist/conf/type/__prometheus_server/parameter/default/with-daemontools diff --git a/cdist/conf/type/__daemontools/man.rst b/cdist/conf/type/__daemontools/man.rst index 2e012cb5..a8e81e54 100644 --- a/cdist/conf/type/__daemontools/man.rst +++ b/cdist/conf/type/__daemontools/man.rst @@ -24,7 +24,7 @@ from-package BOOLEAN PARAMETERS ------------------ install-init-script - Add an init script and set it to start on boot. Default yes. + Add an init script and set it to start on boot. EXAMPLES -------- diff --git a/cdist/conf/type/__daemontools/parameter/default/install-init-script b/cdist/conf/type/__daemontools/parameter/default/install-init-script deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/conf/type/__daemontools_service/explorer/svc b/cdist/conf/type/__daemontools_service/explorer/svc index 4a867485..d33fcea4 100644 --- a/cdist/conf/type/__daemontools_service/explorer/svc +++ b/cdist/conf/type/__daemontools_service/explorer/svc @@ -1 +1 @@ -command -v svc +command -v svc || true diff --git a/cdist/conf/type/__go_get/manifest b/cdist/conf/type/__go_get/manifest index cfeb6396..04e6a09a 100644 --- a/cdist/conf/type/__go_get/manifest +++ b/cdist/conf/type/__go_get/manifest @@ -15,3 +15,4 @@ case $os in ;; esac +__package git diff --git a/cdist/conf/type/__prometheus_alertmanager/man.rst b/cdist/conf/type/__prometheus_alertmanager/man.rst index f218254e..ba99e7c8 100644 --- a/cdist/conf/type/__prometheus_alertmanager/man.rst +++ b/cdist/conf/type/__prometheus_alertmanager/man.rst @@ -10,6 +10,9 @@ DESCRIPTION ----------- Install and configure Prometheus Alertmanager (https://prometheus.io/docs/alerting/alertmanager/). +This type create a daemontools-compatible service directory under /service/prometheus. +Daemontools (or something compatible) must be installed (in particular, the command `svc` must be executable). + REQUIRED PARAMETERS ------------------- @@ -27,10 +30,7 @@ storage-path BOOLEAN PARAMETERS ------------------ -with-daemontools - Create a daemontools service directory under /service/prometheus. Default: yes. - Note: If you do not use this, Alertmanager will not be launched, and will not reload config on change. - If you use this, daemontools (or something compatible) must be installed. +None EXAMPLES @@ -44,6 +44,7 @@ EXAMPLES __golang_from_vendor --version 1.8.1 # required for prometheus and many exporters require="__daemontools __golang_from_vendor" __prometheus_alertmanager \ + --with-daemontools \ --config "$__manifest/files/alertmanager.yml" \ --storage-path /data/alertmanager \ --listen-address "[::]:$ALERTPORT" diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index 61ac2d20..d885f2ed 100644 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -11,12 +11,6 @@ config="$(cat "$__object/parameter/config")" storage_path="$(cat "$__object/parameter/storage-path")" listen_address="$(cat "$__object/parameter/listen-address")" -ONCHANGE="" -if [ -f "$__object/parameter/with-daemontools" ]; then - __daemontools_service prometheus --run "setuidgid prometheus $GOBIN/prometheus $REAL_FLAGS" - ONCHANGE="svc -h /service/prometheus" -fi - FLAGS="config.file '$CONF' storage.path '$storage_path' web.listen-address '$listen_address' @@ -27,12 +21,12 @@ REAL_FLAGS="$(echo "$FLAGS" | sed -nE 's/^([^#]+).*/ --\1 \\/p')" __go_get github.com/prometheus/alertmanager/cmd/... __user prometheus --system -__directory "$storage_path" --owner prometheus -__directory "$CONF_DIR" --owner prometheus +require="__user/prometheus" __directory "$storage_path" --owner prometheus +require="__user/prometheus" __directory "$CONF_DIR" --owner prometheus __daemontools_service alertmanager --run "setuidgid prometheus $GOBIN/alertmanager $REAL_FLAGS" -require="$require __directory/$storage_path" \ +require="$require __directory/$storage_path __user/prometheus" \ __config_file $CONF \ --source $config \ --group prometheus --mode 640 \ diff --git a/cdist/conf/type/__prometheus_server/man.rst b/cdist/conf/type/__prometheus_server/man.rst index c03a71d5..fadebd3f 100644 --- a/cdist/conf/type/__prometheus_server/man.rst +++ b/cdist/conf/type/__prometheus_server/man.rst @@ -10,6 +10,9 @@ DESCRIPTION ----------- Install and configure Prometheus (https://prometheus.io/). +This type creates a daemontools-compatible service directory under /service/prometheus. +Daemontools (or something compatible) must be installed (in particular, the command `svc` must be executable). + REQUIRED PARAMETERS ------------------- @@ -35,10 +38,7 @@ target-heap-size BOOLEAN PARAMETERS ------------------ -with-daemontools - Create a daemontools service directory under /service/prometheus. Default: yes. - Note: If you do not use this, Prometheus will not be launched, and will not reload config on change. - If you use this, daemontools (or something compatible) must be installed. +None EXAMPLES @@ -53,6 +53,7 @@ EXAMPLES __golang_from_vendor --version 1.8.1 # required for prometheus and many exporters require="__daemontools __golang_from_vendor" __prometheus_server \ + --with-daemontools \ --config "$__manifest/files/prometheus.yml" \ --retention-days 14 \ --storage-path /data/prometheus \ diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index dd81701d..3c5f16e3 100644 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -16,11 +16,6 @@ rule_files="$(cat "$__object/parameter/rule-files")" # explorer in kB => convert; by default we go with 1/2 RAM [ "$target_heap_size" = "auto" ] && target_heap_size=$(($(cat $__global/explorer/memory)*1024/2)) -ONCHANGE="" -if [ -f "$__object/parameter/with-daemontools" ]; then - __daemontools_service prometheus --run "setuidgid prometheus $GOBIN/prometheus $REAL_FLAGS" - ONCHANGE="&& svc -h /service/prometheus" -fi FLAGS="config.file '$CONF' storage.local.path '$storage_path' @@ -35,23 +30,23 @@ REAL_FLAGS="$(echo "$FLAGS" | sed -nE 's/^([^#]+).*/ --\1 \\/p')" __go_get github.com/prometheus/prometheus/cmd/... __user prometheus --system -__directory "$storage_path" --owner prometheus -__directory "$CONF_DIR" --owner prometheus +require="__user/prometheus" __directory "$storage_path" --owner prometheus +require="__user/prometheus" __directory "$CONF_DIR" --owner prometheus +__daemontools_service prometheus --run "setuidgid prometheus $GOBIN/prometheus $REAL_FLAGS" - -require="$require __directory/$storage_path" \ +require="$require __directory/$storage_path __user/prometheus" \ __config_file $CONF \ --source $config \ --group prometheus --mode 640 \ - --onchange "$GOBIN/promtool check-config $CONF $ONCHANGE" + --onchange "$GOBIN/promtool check-config $CONF && svc -h /service/prometheus" for file in $rule_files; do dest=$CONF_DIR/$(basename $file) - require="$require __directory/$CONF_DIR" \ + require="$require __directory/$CONF_DIR __user/prometheus" \ __config_file "$dest" \ --source "$file" \ --owner prometheus \ - --onchange "$GOBIN/promtool check-rules '$dest' $ONCHANGE" + --onchange "$GOBIN/promtool check-rules '$dest' && svc -h /service/prometheus" done diff --git a/cdist/conf/type/__prometheus_server/parameter/boolean b/cdist/conf/type/__prometheus_server/parameter/boolean deleted file mode 100644 index de4eefdd..00000000 --- a/cdist/conf/type/__prometheus_server/parameter/boolean +++ /dev/null @@ -1 +0,0 @@ -with-daemontools diff --git a/cdist/conf/type/__prometheus_server/parameter/default/with-daemontools b/cdist/conf/type/__prometheus_server/parameter/default/with-daemontools deleted file mode 100644 index e69de29b..00000000 From e7fa238b2a95da17fc0c4e64f68cf2dcc050f756 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 16 Jun 2017 05:30:40 +0200 Subject: [PATCH 0465/1332] Fix mkfs.vfat support (no -q) --- cdist/conf/type/__install_mkfs/gencode-remote | 56 +++++++++---------- docs/changelog | 1 + 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/cdist/conf/type/__install_mkfs/gencode-remote b/cdist/conf/type/__install_mkfs/gencode-remote index 2fe680e5..da643cce 100755 --- a/cdist/conf/type/__install_mkfs/gencode-remote +++ b/cdist/conf/type/__install_mkfs/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) +# 2017 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -22,32 +23,31 @@ device="$(cat "$__object/parameter/device")" type="$(cat "$__object/parameter/type")" case "$type" in - swap) - echo "mkswap $device" - ;; - xfs) - command="mkfs.xfs -f -q" - if [ -f "$__object/parameter/options" ]; then - options="$(cat "$__object/parameter/options")" - command="$command $options" - fi - command="$command $device" - if [ -f "$__object/parameter/blocks" ]; then - blocks="$(cat "$__object/parameter/blocks")" - command="$command $blocks" - fi - echo "$command" - ;; - *) - command="mkfs -t $type -q" - if [ -f "$__object/parameter/options" ]; then - options="$(cat "$__object/parameter/options")" - command="$command $options" - fi - command="$command $device" - if [ -f "$__object/parameter/blocks" ]; then - blocks="$(cat "$__object/parameter/blocks")" - command="$command $blocks" - fi - echo "$command" + swap) + echo "mkswap $device" + exit 0 + ;; + xfs) + command="mkfs.xfs -f -q" + ;; + + vfat) + command="mkfs.vfat" + ;; + + *) + command="mkfs -t $type -q" + ;; esac + +if [ -f "$__object/parameter/options" ]; then + options="$(cat "$__object/parameter/options")" + command="$command $options" +fi + +command="$command $device" +if [ -f "$__object/parameter/blocks" ]; then + blocks="$(cat "$__object/parameter/blocks")" + command="$command $blocks" +fi +echo "$command" diff --git a/docs/changelog b/docs/changelog index 1631b997..15beba6b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Core: Support -j parallelization for object prepare and object run (Darko Poljak) + * Type __install_mkfs: mkfs.vfat does not support -q (Nico Schottelius) 4.4.3: 2017-06-13 * Type __golang_from_vendor: Install golang from https://golang.org/dl/ (Kamila Součková) From 6d8763f72143999fb14bfba0c4b8192b820daa1d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 16 Jun 2017 10:08:04 +0200 Subject: [PATCH 0466/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 15beba6b..cf204911 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Core: Support -j parallelization for object prepare and object run (Darko Poljak) * Type __install_mkfs: mkfs.vfat does not support -q (Nico Schottelius) + * Types __go_get, __daemontools*, __prometheus*: Fix missing dependencies, fix arguments(Kamila Součková) 4.4.3: 2017-06-13 * Type __golang_from_vendor: Install golang from https://golang.org/dl/ (Kamila Součková) From 689cac5be5af2818513f1ef323aeb1cc6916cdaa Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 16 Jun 2017 12:50:10 +0200 Subject: [PATCH 0467/1332] Release 4.4.4 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index cf204911..4a17e583 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.4.4: 2017-06-16 * Core: Support -j parallelization for object prepare and object run (Darko Poljak) * Type __install_mkfs: mkfs.vfat does not support -q (Nico Schottelius) * Types __go_get, __daemontools*, __prometheus*: Fix missing dependencies, fix arguments(Kamila Součková) From 00a7f4af93fcfb57164d92017a847857374ebee4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 23 Jun 2017 20:03:28 +0200 Subject: [PATCH 0468/1332] Separate functions for target host name and fqdn. --- cdist/util/ipaddr.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cdist/util/ipaddr.py b/cdist/util/ipaddr.py index 71477682..a747aeb5 100644 --- a/cdist/util/ipaddr.py +++ b/cdist/util/ipaddr.py @@ -24,6 +24,12 @@ import logging def resolve_target_addresses(host): + host_name = resolve_target_host_name(host) + host_fqdn = resolve_target_fqdn(host) + return (host, host_name, host_fqdn) + + +def resolve_target_host_name(host): log = logging.getLogger(host) try: # getaddrinfo returns a list of 5-tuples: @@ -43,7 +49,11 @@ def resolve_target_addresses(host): ", $host_name will be empty. Error is: {}".format(host, e)) # in case of error provide empty value host_name = '' + return host_name + +def resolve_target_fqdn(host): + log = logging.getLogger(host) try: host_fqdn = socket.getfqdn(host) log.debug("derived host_fqdn for host \"{}\": {}".format( @@ -53,8 +63,7 @@ def resolve_target_addresses(host): ", $host_fqdn will be empty. Error is: {}".format(host, e)) # in case of error provide empty value host_fqdn = '' - - return (host, host_name, host_fqdn) + return host_fqdn # check whether addr is IPv6 From c1141453fea8d032458c816f13804d1e821b8117 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 20 Jan 2014 12:09:55 +0100 Subject: [PATCH 0469/1332] fix quoting Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_reset_disk/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__install_reset_disk/gencode-remote b/cdist/conf/type/__install_reset_disk/gencode-remote index e8e9cf8c..42ed00c6 100755 --- a/cdist/conf/type/__install_reset_disk/gencode-remote +++ b/cdist/conf/type/__install_reset_disk/gencode-remote @@ -33,7 +33,7 @@ fi # stop mdadm raids if any if [ -r /proc/mdstat ]; then - md_name="\$(awk "/$disk_name/ {print \$1}" /proc/mdstat)" + md_name="\$(awk '/$disk_name/ {print \$1}' /proc/mdstat)" if [ -n "\$md_name" ]; then if command -v mdadm >/dev/null; then mdadm --stop "/dev/\$md_name" From 49dfcf4885f37606af48453edb8abbc76dc80315 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 20 Jan 2014 12:13:15 +0100 Subject: [PATCH 0470/1332] first remove lvm, then mdadm Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_reset_disk/gencode-remote | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__install_reset_disk/gencode-remote b/cdist/conf/type/__install_reset_disk/gencode-remote index 42ed00c6..a16ded5a 100755 --- a/cdist/conf/type/__install_reset_disk/gencode-remote +++ b/cdist/conf/type/__install_reset_disk/gencode-remote @@ -31,6 +31,12 @@ if find /sys/class/block/$disk_name*/holders/ -mindepth 1 | grep -q holders/dm; fi fi +if command -v pvremove >/dev/null; then + pvremove --force --force --yes "$disk" || true +else + echo "WARNING: pvremove command not found" >&2 +fi + # stop mdadm raids if any if [ -r /proc/mdstat ]; then md_name="\$(awk '/$disk_name/ {print \$1}' /proc/mdstat)" @@ -43,12 +49,6 @@ if [ -r /proc/mdstat ]; then fi fi fi - -if command -v pvremove >/dev/null; then - pvremove --force --force --yes "$disk" || true -else - echo "WARNING: pvremove command not found" >&2 -fi if command -v mdadm >/dev/null; then mdadm --zero-superblock --force "$disk" || true else From 2bd48f1c8d77ef2bb43478cca03972509bb45618 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 20 Jan 2014 13:45:23 +0100 Subject: [PATCH 0471/1332] make nuking mdadm/lvm actually work Signed-off-by: Steven Armstrong --- .../type/__install_reset_disk/gencode-remote | 64 ++++++++++--------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/cdist/conf/type/__install_reset_disk/gencode-remote b/cdist/conf/type/__install_reset_disk/gencode-remote index a16ded5a..234715ac 100755 --- a/cdist/conf/type/__install_reset_disk/gencode-remote +++ b/cdist/conf/type/__install_reset_disk/gencode-remote @@ -22,38 +22,44 @@ disk="/$__object_id" disk_name="${disk##*/}" cat << DONE -# stop lvm's if any -if find /sys/class/block/$disk_name*/holders/ -mindepth 1 | grep -q holders/dm; then - if command -v vgchange >/dev/null; then - vgchange -a n + +debug() { + echo "[DEBUG] \$@" >&2 +} + +find_md_device_names() { + local disk_name="\$1" + for slave in \$(find /sys/devices/virtual/block/*/slaves/ -name "\${disk_name}*"); do + debug "slave: \$slave" + for holder in \$slave/holders/*; do + debug "holder: \$holder" + if [ -d "\$holder/md" ]; then + debug "mdadm found at \$holder" + holder_name="\${holder##*/}" + echo "\$holder_name" + fi + done + done +} + +# disable any enabled volume group +if command -v vgchange >/dev/null; then + vgchange -a n +else + echo "WARNING: vgchange command not found" >&2 +fi + +# disable any running mdadm arrays related to $disk +for md_name in \$(find_md_device_names "$disk_name" | sort | uniq); do + echo "md_name: \$md_name" + if command -v mdadm >/dev/null; then + mdadm --stop "/dev/\$md_name" else - echo "WARNING: vgchange command not found" >&2 + echo "WARNING: mdadm command not found" >&2 + echo "WARNING: could not stop active mdadm raid for disk $disk" >&2 fi -fi +done -if command -v pvremove >/dev/null; then - pvremove --force --force --yes "$disk" || true -else - echo "WARNING: pvremove command not found" >&2 -fi - -# stop mdadm raids if any -if [ -r /proc/mdstat ]; then - md_name="\$(awk '/$disk_name/ {print \$1}' /proc/mdstat)" - if [ -n "\$md_name" ]; then - if command -v mdadm >/dev/null; then - mdadm --stop "/dev/\$md_name" - else - echo "WARNING: mdadm command not found" >&2 - echo "WARNING: could not stop active mdadm raid for disk $disk" >&2 - fi - fi -fi -if command -v mdadm >/dev/null; then - mdadm --zero-superblock --force "$disk" || true -else - echo "WARNING: mdadm command not found" >&2 -fi # clean disks from any legacy signatures if command -v wipefs >/dev/null; then wipefs -a "$disk" || true From 5417471dffe60932bfba50b930aac5fcc711e592 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Feb 2014 10:34:22 +0100 Subject: [PATCH 0472/1332] add support for centos Signed-off-by: Steven Armstrong --- .../explorer/target_os | 100 ++++++++++++++++++ .../__install_bootloader_grub/gencode-remote | 88 +++++++++------ .../parameter/default/chroot | 1 + 3 files changed, 156 insertions(+), 33 deletions(-) create mode 100755 cdist/conf/type/__install_bootloader_grub/explorer/target_os create mode 100644 cdist/conf/type/__install_bootloader_grub/parameter/default/chroot diff --git a/cdist/conf/type/__install_bootloader_grub/explorer/target_os b/cdist/conf/type/__install_bootloader_grub/explorer/target_os new file mode 100755 index 00000000..f235710a --- /dev/null +++ b/cdist/conf/type/__install_bootloader_grub/explorer/target_os @@ -0,0 +1,100 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# +# +# All os variables are lower case. Keep this file in alphabetical +# order by os variable except in cases where order otherwise matters, +# in which case keep the primary os and its derivatives together in +# a block (see Debian and Redhat examples below). +# + +chroot="$(cat "$__object/parameter/chroot")" + +if grep -q ^Amazon "$chroot/etc/system-release" 2>/dev/null; then + echo amazon + exit 0 +fi + +if [ -f "$chroot/etc/arch-release" ]; then + echo archlinux + exit 0 +fi + +if [ -f "$chroot/etc/cdist-preos" ]; then + echo cdist-preos + exit 0 +fi + +### Debian and derivatives +if grep -q ^DISTRIB_ID=Ubuntu "$chroot/etc/lsb-release" 2>/dev/null; then + echo ubuntu + exit 0 +fi + +if [ -f "$chroot/etc/debian_version" ]; then + echo debian + exit 0 +fi +### + +if [ -f "$chroot/etc/gentoo-release" ]; then + echo gentoo + exit 0 +fi + +if [ -f "$chroot/etc/openwrt_version" ]; then + echo openwrt + exit 0 +fi + +if [ -f "$chroot/etc/owl-release" ]; then + echo owl + exit 0 +fi + +### Redhat and derivatives +if grep -q ^CentOS "$chroot/etc/redhat-release" 2>/dev/null; then + echo centos + exit 0 +fi + +if grep -q ^Fedora "$chroot/etc/redhat-release" 2>/dev/null; then + echo fedora + exit 0 +fi + +if [ -f "$chroot/etc/redhat-release" ]; then + echo redhat + exit 0 +fi +### + +if [ -f "$chroot/etc/SuSE-release" ]; then + echo suse + exit 0 +fi + +if [ -f "$chroot/etc/slackware-version" ]; then + echo slackware + exit 0 +fi + +echo "Unknown OS" >&2 +exit 1 diff --git a/cdist/conf/type/__install_bootloader_grub/gencode-remote b/cdist/conf/type/__install_bootloader_grub/gencode-remote index ed57331a..24a132ea 100755 --- a/cdist/conf/type/__install_bootloader_grub/gencode-remote +++ b/cdist/conf/type/__install_bootloader_grub/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -18,52 +18,74 @@ # along with cdist. If not, see . # -device="$(cat "$__object/parameter/device")" +device="$(cat "$__object/parameter/device" 2>/dev/null || echo "/$__object_id")" chroot="$(cat "$__object/parameter/chroot")" +target_os=$(cat "$__object/explorer/target_os") -cat << DONE -os=\$( -if grep -q ^DISTRIB_ID=Ubuntu ${chroot}/etc/lsb-release 2>/dev/null; then - echo ubuntu - exit 0 -fi - -if [ -f ${chroot}/etc/arch-release ]; then - echo archlinux - exit 0 -fi - -if [ -f ${chroot}/etc/debian_version ]; then - echo debian - exit 0 -fi -) - -# Ensure /tmp exists -[ -d "${chroot}/tmp" ] || mkdir -m 1777 "${chroot}/tmp" -# Generate script to run in chroot -script=\$(mktemp "${chroot}/tmp/__install_bootloader_grub.XXXXXXXXXX") +mkdir "$__object/files" +install_script="$__object/files/install_script" # Link file descriptor #6 with stdout exec 6>&1 -# Link stdout with \$script -exec > \$script +# Link stdout with $install_script +exec > $install_script -echo "#!/bin/sh -l" -echo "grub-install $device" -case \$os in +# Generate script to install bootloader on distro +printf '#!/bin/sh -l\n' +printf 'grub-install "%s"\n' "$device" + +case "$target_os" in + ubuntu|debian) + printf 'update-grub\n' + ;; archlinux) # bugfix/workarround: rebuild initramfs # FIXME: doesn't belong here - echo "mkinitcpio -p linux" - echo "grub-mkconfig -o /boot/grub/grub.cfg" + printf 'mkinitcpio -p linux\n' + printf 'grub-mkconfig -o /boot/grub/grub.cfg\n' + ;; + centos) + cat << centos_DONE +( +printf '# Generated by cdist ${__type##*/}' +printf 'default=0' +printf 'timeout=3' +for kernel in \$(find /boot -mindepth 1 -maxdepth 2 -name "vmlinuz-*"); do + kernel_version="\${kernel#*-}" + initramfs="\$(echo "\$kernel" | sed 's|/boot/vmlinuz-|/boot/initramfs-|').img" + root_device="\$(awk '\$2 == "/" {print \$1}' /etc/fstab)" + cat << centos_entry_DONE +title \$(cat /etc/redhat-release) (\$kernel_version) + # root is assumed to be on the first partition + root (hd0,0) + kernel \$kernel ro root=\$root_device norhgb noquiet + initrd \$initramfs +centos_entry_DONE +done +) > /boot/grub/grub.conf +cd /boot/grub +ln -sf grub.conf menu.lst +centos_DONE + ;; + *) + echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "If you can, please contribute an implementation for it." >&2 + exit 1 ;; - ubuntu|debian) echo "update-grub" ;; esac - # Restore stdout and close file descriptor #6. exec 1>&6 6>&- + +cat << DONE +# Ensure /tmp exists +[ -d "${chroot}/tmp" ] || mkdir -m 1777 "${chroot}/tmp" +# Generate script to run in chroot +script=\$(mktemp "${chroot}/tmp/${__type##*/}.XXXXXXXXXX") +cat > \$script << script_DONE +$(cat "$install_script") +script_DONE + # Make script executable chmod +x "\$script" diff --git a/cdist/conf/type/__install_bootloader_grub/parameter/default/chroot b/cdist/conf/type/__install_bootloader_grub/parameter/default/chroot new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/cdist/conf/type/__install_bootloader_grub/parameter/default/chroot @@ -0,0 +1 @@ +/target From f97e6c42c79f8d6a2059f5fc845ce9f9658fc952 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 11 Feb 2014 22:29:09 +0100 Subject: [PATCH 0473/1332] no point generating grub.conf at this time, there is no kernel installed yet Signed-off-by: Steven Armstrong --- .../__install_bootloader_grub/gencode-remote | 22 +--------------- .../type/__install_bootloader_grub/manifest | 25 ------------------- 2 files changed, 1 insertion(+), 46 deletions(-) delete mode 100755 cdist/conf/type/__install_bootloader_grub/manifest diff --git a/cdist/conf/type/__install_bootloader_grub/gencode-remote b/cdist/conf/type/__install_bootloader_grub/gencode-remote index 24a132ea..ccc38912 100755 --- a/cdist/conf/type/__install_bootloader_grub/gencode-remote +++ b/cdist/conf/type/__install_bootloader_grub/gencode-remote @@ -45,27 +45,7 @@ case "$target_os" in printf 'grub-mkconfig -o /boot/grub/grub.cfg\n' ;; centos) - cat << centos_DONE -( -printf '# Generated by cdist ${__type##*/}' -printf 'default=0' -printf 'timeout=3' -for kernel in \$(find /boot -mindepth 1 -maxdepth 2 -name "vmlinuz-*"); do - kernel_version="\${kernel#*-}" - initramfs="\$(echo "\$kernel" | sed 's|/boot/vmlinuz-|/boot/initramfs-|').img" - root_device="\$(awk '\$2 == "/" {print \$1}' /etc/fstab)" - cat << centos_entry_DONE -title \$(cat /etc/redhat-release) (\$kernel_version) - # root is assumed to be on the first partition - root (hd0,0) - kernel \$kernel ro root=\$root_device norhgb noquiet - initrd \$initramfs -centos_entry_DONE -done -) > /boot/grub/grub.conf -cd /boot/grub -ln -sf grub.conf menu.lst -centos_DONE + : ;; *) echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 diff --git a/cdist/conf/type/__install_bootloader_grub/manifest b/cdist/conf/type/__install_bootloader_grub/manifest deleted file mode 100755 index 4c7c4955..00000000 --- a/cdist/conf/type/__install_bootloader_grub/manifest +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# 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 . -# - -# set defaults -device="$(cat "$__object/parameter/device" 2>/dev/null \ - || echo "/$__object_id" | tee "$__object/parameter/device")" -chroot="$(cat "$__object/parameter/chroot" 2>/dev/null \ - || echo "/target" | tee "$__object/parameter/chroot")" From bb62787c7c0ca695c14693aa0cfba4e8b365c4a3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 10 Jul 2015 16:28:15 +0200 Subject: [PATCH 0474/1332] deal with that stinkin cdist marker thinggy Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_generate_fstab/gencode-local | 2 +- cdist/conf/type/__install_partition_msdos_apply/gencode-remote | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_generate_fstab/gencode-local b/cdist/conf/type/__install_generate_fstab/gencode-local index d10e5b92..4c9a87b9 100755 --- a/cdist/conf/type/__install_generate_fstab/gencode-local +++ b/cdist/conf/type/__install_generate_fstab/gencode-local @@ -25,7 +25,7 @@ mkdir "$__object/files" # get current UUID's from target_host $__remote_exec $__target_host blkid > "$__object/files/blkid" -for object in $(find "$__global/object/__install_mount" -path "*.cdist"); do +for object in $(find "$__global/object/__install_mount" -path "*.cdist-*"); do device="$(cat "$object/parameter/device")" dir="$(cat "$object/parameter/dir")" prefix="$(cat "$object/parameter/prefix")" diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index a1547296..00cff3d3 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -57,7 +57,7 @@ size_to_mb() { get_objects() { objects_file=$(mktemp) - for object in $(find "$__global/object/__install_partition_msdos" -path "*.cdist"); do + for object in $(find "$__global/object/__install_partition_msdos" -path "*.cdist-*"); do object_device="$(cat "$object/parameter/device")" object_minor="$(cat "$object/parameter/minor")" echo "$object_device $object_minor $object" >> $objects_file From 9ad203c7448d4fdfef8b2d39eb63a16893d9c881 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 10 Jul 2015 16:36:02 +0200 Subject: [PATCH 0475/1332] deal with that stinkin cdist marker thinggy Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_generate_fstab/gencode-local | 2 +- cdist/conf/type/__install_partition_msdos_apply/gencode-remote | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_generate_fstab/gencode-local b/cdist/conf/type/__install_generate_fstab/gencode-local index 4c9a87b9..5dfc0249 100755 --- a/cdist/conf/type/__install_generate_fstab/gencode-local +++ b/cdist/conf/type/__install_generate_fstab/gencode-local @@ -25,7 +25,7 @@ mkdir "$__object/files" # get current UUID's from target_host $__remote_exec $__target_host blkid > "$__object/files/blkid" -for object in $(find "$__global/object/__install_mount" -path "*.cdist-*"); do +for object in $(find "$__global/object/__install_mount" -type d -name "$__cdist_object_marker"); do device="$(cat "$object/parameter/device")" dir="$(cat "$object/parameter/dir")" prefix="$(cat "$object/parameter/prefix")" diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index 00cff3d3..e9ec588b 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -57,7 +57,7 @@ size_to_mb() { get_objects() { objects_file=$(mktemp) - for object in $(find "$__global/object/__install_partition_msdos" -path "*.cdist-*"); do + for object in $(find "$__global/object/__install_partition_msdos" -type d -name "$__cdist_object_marker"); do object_device="$(cat "$object/parameter/device")" object_minor="$(cat "$object/parameter/minor")" echo "$object_device $object_minor $object" >> $objects_file From d05f11b0b8636fe4eb1e658dbb4380553ca48808 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 10 Jul 2015 16:39:27 +0200 Subject: [PATCH 0476/1332] deal with that stinkin cdist marker thinggy Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_mount/gencode-remote | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_mount/gencode-remote b/cdist/conf/type/__install_mount/gencode-remote index 3a35c139..ea5d260b 100755 --- a/cdist/conf/type/__install_mount/gencode-remote +++ b/cdist/conf/type/__install_mount/gencode-remote @@ -20,7 +20,7 @@ get_type_from_mkfs() { _device="$1" - for mkfs_object in $(find "$__global/object/__install_mkfs" -path "*.cdist"); do + for mkfs_object in $(find "$__global/object/__install_mkfs" -type d -name "$__cdist_object_marker"); do mkfs_device="$(cat "$mkfs_object/parameter/device")" if [ "$_device" = "$mkfs_device" ]; then cat "$mkfs_object/parameter/type" @@ -42,7 +42,10 @@ else # store for later use by others echo "$type" > "$__object/parameter/type" fi -[ -n "$type" ] || die "Can't determine type for $__object" +[ -n "$type" ] || { + echo "Can't determine type for $__object" >&2 + exit 1 +} if [ "$type" = "swap" ]; then echo "swapon \"$device\"" else From fd6258c90e1c3b1090279c862eee24e0374f077a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 27 Oct 2015 15:54:30 +0100 Subject: [PATCH 0477/1332] unsure apt index is up2date Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/gencode-local | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 674dec25..6f9bb3c7 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -26,25 +26,9 @@ cdist_args="-v" [ "$__debug" = "yes" ] && cdist_args="$cdist_args -d" cat << DONE -#echo "__apt_noautostart --state present" \ -# | cdist $cdist_args \ -# config \ -# --initial-manifest - \ -# --remote-exec="$remote_exec $chroot" \ -# --remote-copy="$remote_copy $chroot" \ -# $__target_host - cdist $cdist_args \ config \ --remote-exec="$remote_exec $chroot" \ --remote-copy="$remote_copy $chroot" \ $__target_host - -#echo "__apt_noautostart --state absent" \ -# | cdist $cdist_args \ -# config \ -# --initial-manifest - \ -# --remote-exec="$remote_exec $chroot" \ -# --remote-copy="$remote_copy $chroot" \ -# $__target_host DONE From c6e4888c842ef8ce5f18640cfdb2fac2675bff09 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 27 Oct 2015 15:54:50 +0100 Subject: [PATCH 0478/1332] support for centos7 Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_bootloader_grub/gencode-remote | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__install_bootloader_grub/gencode-remote b/cdist/conf/type/__install_bootloader_grub/gencode-remote index ccc38912..0ca94b90 100755 --- a/cdist/conf/type/__install_bootloader_grub/gencode-remote +++ b/cdist/conf/type/__install_bootloader_grub/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011-2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2015 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -32,20 +32,22 @@ exec > $install_script # Generate script to install bootloader on distro printf '#!/bin/sh -l\n' -printf 'grub-install "%s"\n' "$device" case "$target_os" in ubuntu|debian) + printf 'grub-install "%s"\n' "$device" printf 'update-grub\n' ;; archlinux) # bugfix/workarround: rebuild initramfs # FIXME: doesn't belong here + printf 'grub-install "%s"\n' "$device" printf 'mkinitcpio -p linux\n' printf 'grub-mkconfig -o /boot/grub/grub.cfg\n' ;; centos) - : + printf 'grub2-install "%s"\n' "$device" + printf 'grub2-mkconfig --output=/boot/grub2/grub.cfg\n' ;; *) echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 From 1d42e4afcba38b1da14de40b6230e6901d62d863 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 4 Apr 2016 21:58:43 +0200 Subject: [PATCH 0479/1332] bind mount /etc/resolv.conf instead of overwriting/removing Signed-off-by: Steven Armstrong --- cdist/conf/type/__chroot_mount/gencode-remote | 5 ++--- cdist/conf/type/__chroot_umount/gencode-remote | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__chroot_mount/gencode-remote b/cdist/conf/type/__chroot_mount/gencode-remote index 6d855f41..14da81ee 100755 --- a/cdist/conf/type/__chroot_mount/gencode-remote +++ b/cdist/conf/type/__chroot_mount/gencode-remote @@ -42,7 +42,6 @@ mountpoint -q "${chroot}/dev/pts" \ mountpoint -q "${chroot}/tmp" \ || mount -t tmpfs -o mode=1777,strictatime,nodev,nosuid tmpfs "${chroot}/tmp" -if [ ! -f "${chroot}/etc/resolv.conf" ]; then - cp /etc/resolv.conf "${chroot}/etc/" -fi +mountpoint -q "${chroot}/etc/resolv.conf" \ + || mount --bind -o ro /etc/resolv.conf "${chroot}/etc/resolv.conf" DONE diff --git a/cdist/conf/type/__chroot_umount/gencode-remote b/cdist/conf/type/__chroot_umount/gencode-remote index caf2c40c..ad06a0a2 100755 --- a/cdist/conf/type/__chroot_umount/gencode-remote +++ b/cdist/conf/type/__chroot_umount/gencode-remote @@ -26,7 +26,9 @@ umount -l "${chroot}/dev/pts" umount -l "${chroot}/dev" umount -l "${chroot}/sys" umount -l "${chroot}/proc" -rm -f "${chroot}/etc/resolv.conf" +if mountpoint -q "${chroot}/etc/resolv.conf"; then + umount "${chroot}/etc/resolv.conf" +fi if [ -d "${chroot}/etc/resolvconf/resolv.conf.d" ]; then # ensure /etc/resolvconf/resolv.conf.d/tail is not linked to \ # e.g. /etc/resolvconf/resolv.conf.d/original From 73cad9dee2c7c361d2dcacf5daa94b6bf7c74d42 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 4 Apr 2016 23:31:38 +0200 Subject: [PATCH 0480/1332] backcompat Signed-off-by: Steven Armstrong --- cdist/conf/type/__chroot_mount/gencode-remote | 10 ++++++++-- cdist/conf/type/__chroot_umount/gencode-remote | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__chroot_mount/gencode-remote b/cdist/conf/type/__chroot_mount/gencode-remote index 14da81ee..7ec41f28 100755 --- a/cdist/conf/type/__chroot_mount/gencode-remote +++ b/cdist/conf/type/__chroot_mount/gencode-remote @@ -42,6 +42,12 @@ mountpoint -q "${chroot}/dev/pts" \ mountpoint -q "${chroot}/tmp" \ || mount -t tmpfs -o mode=1777,strictatime,nodev,nosuid tmpfs "${chroot}/tmp" -mountpoint -q "${chroot}/etc/resolv.conf" \ - || mount --bind -o ro /etc/resolv.conf "${chroot}/etc/resolv.conf" +if [ -f "${chroot}/etc/resolv.conf" ]; then + # if file exists, bind mount over it + mountpoint -q "${chroot}/etc/resolv.conf" \ + || mount --bind -o ro /etc/resolv.conf "${chroot}/etc/resolv.conf" +else + # otherwise copy + cp /etc/resolv.conf "${chroot}/etc/resolv.conf" +fi DONE diff --git a/cdist/conf/type/__chroot_umount/gencode-remote b/cdist/conf/type/__chroot_umount/gencode-remote index ad06a0a2..cbcdeff2 100755 --- a/cdist/conf/type/__chroot_umount/gencode-remote +++ b/cdist/conf/type/__chroot_umount/gencode-remote @@ -28,6 +28,8 @@ umount -l "${chroot}/sys" umount -l "${chroot}/proc" if mountpoint -q "${chroot}/etc/resolv.conf"; then umount "${chroot}/etc/resolv.conf" +else + rm -rf "${chroot}/etc/resolv.conf" fi if [ -d "${chroot}/etc/resolvconf/resolv.conf.d" ]; then # ensure /etc/resolvconf/resolv.conf.d/tail is not linked to \ From aea9747918daa1b597d88b78ff2f47e93c43f6e1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 26 Apr 2016 22:39:36 +0200 Subject: [PATCH 0481/1332] mount/umounting a chroot should not mess with resolv.conf at all Signed-off-by: Steven Armstrong --- cdist/conf/type/__chroot_mount/gencode-remote | 9 --------- cdist/conf/type/__chroot_umount/gencode-remote | 5 ----- 2 files changed, 14 deletions(-) diff --git a/cdist/conf/type/__chroot_mount/gencode-remote b/cdist/conf/type/__chroot_mount/gencode-remote index 7ec41f28..a3b94b33 100755 --- a/cdist/conf/type/__chroot_mount/gencode-remote +++ b/cdist/conf/type/__chroot_mount/gencode-remote @@ -41,13 +41,4 @@ mountpoint -q "${chroot}/dev/pts" \ [ -d "${chroot}/tmp" ] || mkdir -m 1777 "${chroot}/tmp" mountpoint -q "${chroot}/tmp" \ || mount -t tmpfs -o mode=1777,strictatime,nodev,nosuid tmpfs "${chroot}/tmp" - -if [ -f "${chroot}/etc/resolv.conf" ]; then - # if file exists, bind mount over it - mountpoint -q "${chroot}/etc/resolv.conf" \ - || mount --bind -o ro /etc/resolv.conf "${chroot}/etc/resolv.conf" -else - # otherwise copy - cp /etc/resolv.conf "${chroot}/etc/resolv.conf" -fi DONE diff --git a/cdist/conf/type/__chroot_umount/gencode-remote b/cdist/conf/type/__chroot_umount/gencode-remote index cbcdeff2..bb854efe 100755 --- a/cdist/conf/type/__chroot_umount/gencode-remote +++ b/cdist/conf/type/__chroot_umount/gencode-remote @@ -26,11 +26,6 @@ umount -l "${chroot}/dev/pts" umount -l "${chroot}/dev" umount -l "${chroot}/sys" umount -l "${chroot}/proc" -if mountpoint -q "${chroot}/etc/resolv.conf"; then - umount "${chroot}/etc/resolv.conf" -else - rm -rf "${chroot}/etc/resolv.conf" -fi if [ -d "${chroot}/etc/resolvconf/resolv.conf.d" ]; then # ensure /etc/resolvconf/resolv.conf.d/tail is not linked to \ # e.g. /etc/resolvconf/resolv.conf.d/original From 4547d2efa1fd735b4c36be0c06df54c1794972d0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 25 May 2016 12:39:11 +0200 Subject: [PATCH 0482/1332] properly escape single quotes Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/files/remote/exec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__install_config/files/remote/exec b/cdist/conf/type/__install_config/files/remote/exec index 58e6b162..fc217e3e 100755 --- a/cdist/conf/type/__install_config/files/remote/exec +++ b/cdist/conf/type/__install_config/files/remote/exec @@ -35,7 +35,10 @@ target_host="$__target_host" shift ssh="ssh -o User=root -q $target_host" -code="$ssh chroot $chroot sh -c '$@'" + +# escape ' with '"'"' +code="$(echo "$@" | sed -e "s/'/'\"'\"'/g")" +code="$ssh chroot $chroot sh -c '$code'" log "target_host: $target_host" log "chroot: $chroot" From ce82e32c5962af7ad473fa83d63f29c39e7d1feb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Jun 2016 16:02:29 +0200 Subject: [PATCH 0483/1332] handle resolv.conf Signed-off-by: Steven Armstrong --- .../conf/type/__install_config/gencode-local | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 6f9bb3c7..4f1dcc23 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2016 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -25,6 +25,16 @@ remote_copy="$__type/files/remote/copy" cdist_args="-v" [ "$__debug" = "yes" ] && cdist_args="$cdist_args -d" + +cat << DONE +$__remote_exec $__target_host << EOSSH +if [ ! -f "${chroot}/etc/resolv.conf" ]; then + touch "${chroot}/etc/resolv.conf" +fi +mount --bind -o ro /etc/resolv.conf "${chroot}/etc/resolv.conf" +EOSSH +DONE + cat << DONE cdist $cdist_args \ config \ @@ -32,3 +42,16 @@ cdist $cdist_args \ --remote-copy="$remote_copy $chroot" \ $__target_host DONE + +cat << DONE +$__remote_exec $__target_host << EOSSH +if mountpoint -q "${chroot}/etc/resolv.conf"; + umount "${chroot}/etc/resolv.conf" +fi +if [ -f "${chroot}/etc/resolv.conf" -a ! -s "${chroot}/etc/resolv.conf" ]; then + # file exists but is empty which means we created it or it's useless anyway + rm "${chroot}/etc/resolv.conf" +fi + +EOSSH +DONE From 8305477e01d0e07a9ab166c2b95cee19ca68b11d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 22 Jun 2016 23:54:14 +0200 Subject: [PATCH 0484/1332] fix typo Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/gencode-local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 4f1dcc23..cbf916da 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -45,7 +45,7 @@ DONE cat << DONE $__remote_exec $__target_host << EOSSH -if mountpoint -q "${chroot}/etc/resolv.conf"; +if mountpoint -q "${chroot}/etc/resolv.conf"; then umount "${chroot}/etc/resolv.conf" fi if [ -f "${chroot}/etc/resolv.conf" -a ! -s "${chroot}/etc/resolv.conf" ]; then From 2ce00f3357df1188c39556e90371497b1ad6a8a7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 23 Sep 2016 15:33:17 +0200 Subject: [PATCH 0485/1332] fix syntax error Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/gencode-local | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index cbf916da..980eb996 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -27,6 +27,7 @@ cdist_args="-v" cat << DONE + $__remote_exec $__target_host << EOSSH if [ ! -f "${chroot}/etc/resolv.conf" ]; then touch "${chroot}/etc/resolv.conf" From 9ee0de7c8bbcef8daa2f167d953ea2cf958bca77 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 7 Dec 2016 23:41:02 +0100 Subject: [PATCH 0486/1332] make uefi boot work Signed-off-by: Steven Armstrong --- cdist/conf/type/__chroot_mount/gencode-local | 35 +++++++++++++++++++ cdist/conf/type/__chroot_mount/man.rst | 10 ++++-- .../type/__chroot_mount/parameter/boolean | 1 + cdist/conf/type/__chroot_umount/gencode-local | 35 +++++++++++++++++++ cdist/conf/type/__chroot_umount/man.rst | 8 ++++- .../type/__chroot_umount/parameter/boolean | 1 + .../type/__install_chroot_mount/parameter | 1 + .../type/__install_chroot_umount/parameter | 1 + .../conf/type/__install_config/gencode-local | 23 ------------ .../type/__install_partition_msdos/man.rst | 4 ++- .../type/__install_partition_msdos/manifest | 13 ++++--- .../parameter/optional | 2 ++ .../gencode-remote | 2 ++ 13 files changed, 105 insertions(+), 31 deletions(-) create mode 100755 cdist/conf/type/__chroot_mount/gencode-local create mode 100644 cdist/conf/type/__chroot_mount/parameter/boolean create mode 100755 cdist/conf/type/__chroot_umount/gencode-local create mode 100644 cdist/conf/type/__chroot_umount/parameter/boolean create mode 120000 cdist/conf/type/__install_chroot_mount/parameter create mode 120000 cdist/conf/type/__install_chroot_umount/parameter diff --git a/cdist/conf/type/__chroot_mount/gencode-local b/cdist/conf/type/__chroot_mount/gencode-local new file mode 100755 index 00000000..a2e1f423 --- /dev/null +++ b/cdist/conf/type/__chroot_mount/gencode-local @@ -0,0 +1,35 @@ +#!/bin/sh +# +# 2016 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# + +chroot="/$__object_id" + +if [ -f "$__object/parameter/manage-resolv-conf" ]; then + resolv_conf="${chroot}/etc/resolv.conf" + original_resolv_conf="${resolv_conf}${__cdist_object_marker}" + cat << DONE +$__remote_exec $__target_host << EOSSH +if [ -f "${resolv_conf}" ]; then + mv "${resolv_conf}" "${original_resolv_conf}" +fi +# copy hosts resolv.conf into chroot +cp /etc/resolv.conf "${resolv_conf}" +EOSSH +DONE +fi diff --git a/cdist/conf/type/__chroot_mount/man.rst b/cdist/conf/type/__chroot_mount/man.rst index 0d7cdce3..a44b70ba 100644 --- a/cdist/conf/type/__chroot_mount/man.rst +++ b/cdist/conf/type/__chroot_mount/man.rst @@ -1,5 +1,5 @@ cdist-type__chroot_mount(7) -=================================== +=========================== NAME ---- @@ -21,6 +21,12 @@ OPTIONAL PARAMETERS None +BOOLEAN PARAMETERS +------------------ +manage-resolv-conf + manage /etc/resolv.conf inside the chroot + + EXAMPLES -------- @@ -36,7 +42,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. You can redistribute it +Copyright \(C) 2012-2017 Steven Armstrong. 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/__chroot_mount/parameter/boolean b/cdist/conf/type/__chroot_mount/parameter/boolean new file mode 100644 index 00000000..27928f2c --- /dev/null +++ b/cdist/conf/type/__chroot_mount/parameter/boolean @@ -0,0 +1 @@ +manage-resolv-conf diff --git a/cdist/conf/type/__chroot_umount/gencode-local b/cdist/conf/type/__chroot_umount/gencode-local new file mode 100755 index 00000000..97f126a5 --- /dev/null +++ b/cdist/conf/type/__chroot_umount/gencode-local @@ -0,0 +1,35 @@ +#!/bin/sh +# +# 2016 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# + +chroot="/$__object_id" + +if [ -f "$__object/parameter/manage-resolv-conf" ]; then + resolv_conf="${chroot}/etc/resolv.conf" + original_resolv_conf="${resolv_conf}${__cdist_object_marker}" +cat << DONE +$__remote_exec $__target_host << EOSSH +if [ -f "${original_resolv_conf}" ]; then + # restore original /etc/resolv.conf that we moved out of the way + # in __chroot_mount/gencode-local + mv -f "${original_resolv_conf}" "${resolv_conf}" +fi +EOSSH +DONE +fi diff --git a/cdist/conf/type/__chroot_umount/man.rst b/cdist/conf/type/__chroot_umount/man.rst index ff116da5..349cc2e0 100644 --- a/cdist/conf/type/__chroot_umount/man.rst +++ b/cdist/conf/type/__chroot_umount/man.rst @@ -21,6 +21,12 @@ OPTIONAL PARAMETERS None +BOOLEAN PARAMETERS +------------------ +manage-resolv-conf + manage /etc/resolv.conf inside the chroot + + EXAMPLES -------- @@ -41,7 +47,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2012 Steven Armstrong. You can redistribute it +Copyright \(C) 2012-2017 Steven Armstrong. 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/__chroot_umount/parameter/boolean b/cdist/conf/type/__chroot_umount/parameter/boolean new file mode 100644 index 00000000..27928f2c --- /dev/null +++ b/cdist/conf/type/__chroot_umount/parameter/boolean @@ -0,0 +1 @@ +manage-resolv-conf diff --git a/cdist/conf/type/__install_chroot_mount/parameter b/cdist/conf/type/__install_chroot_mount/parameter new file mode 120000 index 00000000..5b5c9e20 --- /dev/null +++ b/cdist/conf/type/__install_chroot_mount/parameter @@ -0,0 +1 @@ +../__chroot_mount/parameter \ No newline at end of file diff --git a/cdist/conf/type/__install_chroot_umount/parameter b/cdist/conf/type/__install_chroot_umount/parameter new file mode 120000 index 00000000..4148bcd0 --- /dev/null +++ b/cdist/conf/type/__install_chroot_umount/parameter @@ -0,0 +1 @@ +../__chroot_umount/parameter \ No newline at end of file diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 980eb996..30434d1b 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -25,17 +25,6 @@ remote_copy="$__type/files/remote/copy" cdist_args="-v" [ "$__debug" = "yes" ] && cdist_args="$cdist_args -d" - -cat << DONE - -$__remote_exec $__target_host << EOSSH -if [ ! -f "${chroot}/etc/resolv.conf" ]; then - touch "${chroot}/etc/resolv.conf" -fi -mount --bind -o ro /etc/resolv.conf "${chroot}/etc/resolv.conf" -EOSSH -DONE - cat << DONE cdist $cdist_args \ config \ @@ -44,15 +33,3 @@ cdist $cdist_args \ $__target_host DONE -cat << DONE -$__remote_exec $__target_host << EOSSH -if mountpoint -q "${chroot}/etc/resolv.conf"; then - umount "${chroot}/etc/resolv.conf" -fi -if [ -f "${chroot}/etc/resolv.conf" -a ! -s "${chroot}/etc/resolv.conf" ]; then - # file exists but is empty which means we created it or it's useless anyway - rm "${chroot}/etc/resolv.conf" -fi - -EOSSH -DONE diff --git a/cdist/conf/type/__install_partition_msdos/man.rst b/cdist/conf/type/__install_partition_msdos/man.rst index 5ebb9218..aa194110 100644 --- a/cdist/conf/type/__install_partition_msdos/man.rst +++ b/cdist/conf/type/__install_partition_msdos/man.rst @@ -49,6 +49,8 @@ EXAMPLES __install_partition_msdos /dev/sda6 --type 83 --size 50% # rest of the extended partition, linux __install_partition_msdos /dev/sda7 --type 83 --size + + # nvm device partition 2 + __install_partition_msdos /dev/nvme0n1p2 --device /dev/nvme0n1 --minor 2 --type 83 --size 128M --bootable true AUTHORS @@ -58,7 +60,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011 Steven Armstrong. You can redistribute it +Copyright \(C) 2011-2017 Steven Armstrong. 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/__install_partition_msdos/manifest b/cdist/conf/type/__install_partition_msdos/manifest index e55d3f24..636fbd6a 100755 --- a/cdist/conf/type/__install_partition_msdos/manifest +++ b/cdist/conf/type/__install_partition_msdos/manifest @@ -25,10 +25,15 @@ else partition="/$__object_id" echo "$partition" > "$__object/parameter/partition" fi -device="$(echo "$partition" | sed 's/[0-9]//g')" -echo "$device" > "$__object/parameter/device" -minor="$(echo "$partition" | sed 's/[^0-9]//g')" -echo "$minor" > "$__object/parameter/minor" + +if [ ! -f "$__object/parameter/device" ]; then + device="$(echo "$partition" | sed 's/[0-9]//g')" + echo "$device" > "$__object/parameter/device" +fi +if [ ! -f "$__object/parameter/minor" ]; then + minor="$(echo "$partition" | sed 's/[^0-9]//g')" + echo "$minor" > "$__object/parameter/minor" +fi if [ ! -f "$__object/parameter/bootable" ]; then echo "false" > "$__object/parameter/bootable" diff --git a/cdist/conf/type/__install_partition_msdos/parameter/optional b/cdist/conf/type/__install_partition_msdos/parameter/optional index b2b0a4c2..3b3f2083 100644 --- a/cdist/conf/type/__install_partition_msdos/parameter/optional +++ b/cdist/conf/type/__install_partition_msdos/parameter/optional @@ -1,3 +1,5 @@ +device +minor partition bootable size diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index e9ec588b..60f2fd1e 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -18,6 +18,8 @@ # along with cdist. If not, see . # +#set -x + die() { echo "[__install_partition_msdos_apply] $@" >&2 exit 1 From 42e197a5bae4f3eb8f876528dbf683d8fdd923d9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 9 Dec 2016 14:20:23 +0100 Subject: [PATCH 0487/1332] use the force when creating swap Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_mkfs/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__install_mkfs/gencode-remote b/cdist/conf/type/__install_mkfs/gencode-remote index da643cce..63a4b96d 100755 --- a/cdist/conf/type/__install_mkfs/gencode-remote +++ b/cdist/conf/type/__install_mkfs/gencode-remote @@ -24,7 +24,7 @@ type="$(cat "$__object/parameter/type")" case "$type" in swap) - echo "mkswap $device" + echo "mkswap -f $device" exit 0 ;; xfs) From f9d371c6e3740c1e0244443771453be888b32a07 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 14 Dec 2016 08:12:02 +0100 Subject: [PATCH 0488/1332] use sysrq to reboot Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_reboot/gencode-remote | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__install_reboot/gencode-remote b/cdist/conf/type/__install_reboot/gencode-remote index 4358347d..c4307de8 100755 --- a/cdist/conf/type/__install_reboot/gencode-remote +++ b/cdist/conf/type/__install_reboot/gencode-remote @@ -20,4 +20,13 @@ options="$(cat "$__object/parameter/options")" -echo "reboot $options" +#echo "reboot $options" +cat << DONE +echo 1 > /proc/sys/kernel/sysrq +echo s > /proc/sysrq-trigger + +# close file descriptors to detach from ssh +sh -c 'sleep 3; echo b > /proc/sysrq-trigger' > /dev/null 2>&1 Date: Thu, 15 Dec 2016 14:08:08 +0100 Subject: [PATCH 0489/1332] add __install_directory type Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_directory/explorer | 1 + cdist/conf/type/__install_directory/gencode-remote | 1 + cdist/conf/type/__install_directory/install | 0 cdist/conf/type/__install_directory/man.rst | 1 + cdist/conf/type/__install_directory/parameter | 1 + 5 files changed, 4 insertions(+) create mode 120000 cdist/conf/type/__install_directory/explorer create mode 120000 cdist/conf/type/__install_directory/gencode-remote create mode 100644 cdist/conf/type/__install_directory/install create mode 120000 cdist/conf/type/__install_directory/man.rst create mode 120000 cdist/conf/type/__install_directory/parameter diff --git a/cdist/conf/type/__install_directory/explorer b/cdist/conf/type/__install_directory/explorer new file mode 120000 index 00000000..ba2591e1 --- /dev/null +++ b/cdist/conf/type/__install_directory/explorer @@ -0,0 +1 @@ +../__directory/explorer \ No newline at end of file diff --git a/cdist/conf/type/__install_directory/gencode-remote b/cdist/conf/type/__install_directory/gencode-remote new file mode 120000 index 00000000..c86d61c9 --- /dev/null +++ b/cdist/conf/type/__install_directory/gencode-remote @@ -0,0 +1 @@ +../__directory/gencode-remote \ No newline at end of file diff --git a/cdist/conf/type/__install_directory/install b/cdist/conf/type/__install_directory/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_directory/man.rst b/cdist/conf/type/__install_directory/man.rst new file mode 120000 index 00000000..1ad7fa84 --- /dev/null +++ b/cdist/conf/type/__install_directory/man.rst @@ -0,0 +1 @@ +../__directory/man.rst \ No newline at end of file diff --git a/cdist/conf/type/__install_directory/parameter b/cdist/conf/type/__install_directory/parameter new file mode 120000 index 00000000..e23d9672 --- /dev/null +++ b/cdist/conf/type/__install_directory/parameter @@ -0,0 +1 @@ +../__directory/parameter \ No newline at end of file From a495a20d9577d9111b8764a71bdaf5f6b47d0553 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 20 Dec 2016 11:08:24 +0100 Subject: [PATCH 0490/1332] uefi support Signed-off-by: Steven Armstrong --- .../__install_bootloader_grub/gencode-remote | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__install_bootloader_grub/gencode-remote b/cdist/conf/type/__install_bootloader_grub/gencode-remote index 0ca94b90..0db6dee6 100755 --- a/cdist/conf/type/__install_bootloader_grub/gencode-remote +++ b/cdist/conf/type/__install_bootloader_grub/gencode-remote @@ -35,22 +35,41 @@ printf '#!/bin/sh -l\n' case "$target_os" in ubuntu|debian) - printf 'grub-install "%s"\n' "$device" - printf 'update-grub\n' + if [ -s "$__global/explorer/efi" ]; then + # FIXME: untested. maybe also just run update-grub for EFI system? + printf 'grub-mkconfig --output=/boot/efi/EFI/%s/grub.cfg\n' "$target_os" + printf 'mkdir -p /boot/efi/EFI/BOOT\n' + printf 'cp /boot/efi/EFI/%s/grubx64.efi /boot/efi/EFI/BOOT/bootx64.efi' "$target_os" + else + printf 'grub-install "%s"\n' "$device" + printf 'update-grub\n' + fi ;; archlinux) - # bugfix/workarround: rebuild initramfs - # FIXME: doesn't belong here - printf 'grub-install "%s"\n' "$device" - printf 'mkinitcpio -p linux\n' - printf 'grub-mkconfig -o /boot/grub/grub.cfg\n' + if [ -s "$__global/explorer/efi" ]; then + echo "EFI boot loader installation is on your operating system ($target_os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + else + printf 'grub-install "%s"\n' "$device" + # bugfix/workarround: rebuild initramfs + # FIXME: doesn't belong here + printf 'mkinitcpio -p linux\n' + printf 'grub-mkconfig -o /boot/grub/grub.cfg\n' + fi ;; centos) - printf 'grub2-install "%s"\n' "$device" - printf 'grub2-mkconfig --output=/boot/grub2/grub.cfg\n' + if [ -s "$__global/explorer/efi" ]; then + printf 'grub2-mkconfig --output=/boot/efi/EFI/%s/grub.cfg\n' "$target_os" + printf 'mkdir -p /boot/efi/EFI/BOOT\n' + printf 'cp /boot/efi/EFI/%s/grubx64.efi /boot/efi/EFI/BOOT/bootx64.efi' "$target_os" + else + printf 'grub2-install "%s"\n' "$device" + printf 'grub2-mkconfig --output=/boot/grub2/grub.cfg\n' + fi ;; *) - echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Your operating system ($target_os) is currently not supported by this type (${__type##*/})." >&2 echo "If you can, please contribute an implementation for it." >&2 exit 1 ;; @@ -74,4 +93,5 @@ chmod +x "\$script" # Run script in chroot relative_script="\${script#$chroot}" chroot "$chroot" "\$relative_script" +rm -rf \$script DONE From 058e4d757bf43266b9d6001c367518a01e962b1c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 18 Jan 2017 21:14:17 +0100 Subject: [PATCH 0491/1332] disabel debug log Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/files/remote/copy | 2 +- cdist/conf/type/__install_config/files/remote/exec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_config/files/remote/copy b/cdist/conf/type/__install_config/files/remote/copy index 5b6f555c..df6a3f06 100755 --- a/cdist/conf/type/__install_config/files/remote/copy +++ b/cdist/conf/type/__install_config/files/remote/copy @@ -25,7 +25,7 @@ # log() { - echo "$@" | logger -t "__install_config copy" + #echo "$@" | logger -t "__install_config copy" : } diff --git a/cdist/conf/type/__install_config/files/remote/exec b/cdist/conf/type/__install_config/files/remote/exec index fc217e3e..17375693 100755 --- a/cdist/conf/type/__install_config/files/remote/exec +++ b/cdist/conf/type/__install_config/files/remote/exec @@ -25,7 +25,7 @@ # log() { - echo "$@" | logger -t "__install_config exec" + #echo "$@" | logger -t "__install_config exec" : } From 86a61bbcff9e8ff14fa3d38249ba97347afa4f4d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 24 Jan 2017 00:08:55 +0100 Subject: [PATCH 0492/1332] need to pass a known suffix from outside Signed-off-by: Steven Armstrong --- cdist/conf/type/__chroot_mount/gencode-local | 3 +- cdist/conf/type/__chroot_mount/man.rst | 13 +++++-- .../parameter/{boolean => optional} | 0 cdist/conf/type/__chroot_umount/gencode-local | 3 +- cdist/conf/type/__chroot_umount/man.rst | 13 +++++-- cdist/conf/type/__chroot_umount/manifest | 36 +++++++++++++++++++ .../parameter/{boolean => optional} | 0 7 files changed, 60 insertions(+), 8 deletions(-) rename cdist/conf/type/__chroot_mount/parameter/{boolean => optional} (100%) create mode 100755 cdist/conf/type/__chroot_umount/manifest rename cdist/conf/type/__chroot_umount/parameter/{boolean => optional} (100%) diff --git a/cdist/conf/type/__chroot_mount/gencode-local b/cdist/conf/type/__chroot_mount/gencode-local index a2e1f423..2c3b51b8 100755 --- a/cdist/conf/type/__chroot_mount/gencode-local +++ b/cdist/conf/type/__chroot_mount/gencode-local @@ -21,8 +21,9 @@ chroot="/$__object_id" if [ -f "$__object/parameter/manage-resolv-conf" ]; then + suffix="$(cat "$__object/parameter/manage-resolv-conf")" resolv_conf="${chroot}/etc/resolv.conf" - original_resolv_conf="${resolv_conf}${__cdist_object_marker}" + original_resolv_conf="${resolv_conf}.${suffix}" cat << DONE $__remote_exec $__target_host << EOSSH if [ -f "${resolv_conf}" ]; then diff --git a/cdist/conf/type/__chroot_mount/man.rst b/cdist/conf/type/__chroot_mount/man.rst index a44b70ba..41fd496b 100644 --- a/cdist/conf/type/__chroot_mount/man.rst +++ b/cdist/conf/type/__chroot_mount/man.rst @@ -18,13 +18,17 @@ None OPTIONAL PARAMETERS ------------------- -None +manage-resolv-conf + manage /etc/resolv.conf inside the chroot. + Use the value of this parameter as the suffix to save a copy + of the current /etc/resolv.conf to /etc/resolv.conf.$suffix. + This is used by the __chroot_umount type to restore the initial + file content when unmounting the chroot. BOOLEAN PARAMETERS ------------------ -manage-resolv-conf - manage /etc/resolv.conf inside the chroot +None. EXAMPLES @@ -34,6 +38,9 @@ EXAMPLES __chroot_mount /path/to/chroot + __chroot_mount /path/to/chroot \ + --manage-resolv-conf "some-known-string" + AUTHORS ------- diff --git a/cdist/conf/type/__chroot_mount/parameter/boolean b/cdist/conf/type/__chroot_mount/parameter/optional similarity index 100% rename from cdist/conf/type/__chroot_mount/parameter/boolean rename to cdist/conf/type/__chroot_mount/parameter/optional diff --git a/cdist/conf/type/__chroot_umount/gencode-local b/cdist/conf/type/__chroot_umount/gencode-local index 97f126a5..a6793534 100755 --- a/cdist/conf/type/__chroot_umount/gencode-local +++ b/cdist/conf/type/__chroot_umount/gencode-local @@ -21,8 +21,9 @@ chroot="/$__object_id" if [ -f "$__object/parameter/manage-resolv-conf" ]; then + suffix="$(cat "$__object/parameter/manage-resolv-conf")" resolv_conf="${chroot}/etc/resolv.conf" - original_resolv_conf="${resolv_conf}${__cdist_object_marker}" + original_resolv_conf="${resolv_conf}.${suffix}" cat << DONE $__remote_exec $__target_host << EOSSH if [ -f "${original_resolv_conf}" ]; then diff --git a/cdist/conf/type/__chroot_umount/man.rst b/cdist/conf/type/__chroot_umount/man.rst index 349cc2e0..2a15f362 100644 --- a/cdist/conf/type/__chroot_umount/man.rst +++ b/cdist/conf/type/__chroot_umount/man.rst @@ -18,13 +18,17 @@ None OPTIONAL PARAMETERS ------------------- -None +manage-resolv-conf + manage /etc/resolv.conf inside the chroot. + Use the value of this parameter as the suffix to find the backup file + that was saved by the __chroot_mount. + This is used by the to restore the initial file content when unmounting + the chroot. BOOLEAN PARAMETERS ------------------ -manage-resolv-conf - manage /etc/resolv.conf inside the chroot +None. EXAMPLES @@ -34,6 +38,9 @@ EXAMPLES __chroot_umount /path/to/chroot + __chroot_umount /path/to/chroot \ + --manage-resolv-conf "some-known-string" + SEE ALSO -------- diff --git a/cdist/conf/type/__chroot_umount/manifest b/cdist/conf/type/__chroot_umount/manifest new file mode 100755 index 00000000..a6793534 --- /dev/null +++ b/cdist/conf/type/__chroot_umount/manifest @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2016 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# + +chroot="/$__object_id" + +if [ -f "$__object/parameter/manage-resolv-conf" ]; then + suffix="$(cat "$__object/parameter/manage-resolv-conf")" + resolv_conf="${chroot}/etc/resolv.conf" + original_resolv_conf="${resolv_conf}.${suffix}" +cat << DONE +$__remote_exec $__target_host << EOSSH +if [ -f "${original_resolv_conf}" ]; then + # restore original /etc/resolv.conf that we moved out of the way + # in __chroot_mount/gencode-local + mv -f "${original_resolv_conf}" "${resolv_conf}" +fi +EOSSH +DONE +fi diff --git a/cdist/conf/type/__chroot_umount/parameter/boolean b/cdist/conf/type/__chroot_umount/parameter/optional similarity index 100% rename from cdist/conf/type/__chroot_umount/parameter/boolean rename to cdist/conf/type/__chroot_umount/parameter/optional From efd935150093be4a7e94bd13361fd038f4436644 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 1 Feb 2017 06:53:13 +0100 Subject: [PATCH 0493/1332] document new parameters: device, minor Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_partition_msdos/man.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cdist/conf/type/__install_partition_msdos/man.rst b/cdist/conf/type/__install_partition_msdos/man.rst index aa194110..c408a614 100644 --- a/cdist/conf/type/__install_partition_msdos/man.rst +++ b/cdist/conf/type/__install_partition_msdos/man.rst @@ -19,6 +19,12 @@ type OPTIONAL PARAMETERS ------------------- +device + the device we're working on. Defaults to the string prefix of --partition + +minor + the partition number we're working on. Defaults to the numeric suffix of --partition + partition defaults to object_id From e74d2be2d47ddfd9468d75721177cb29c6591651 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 1 Feb 2017 07:16:19 +0100 Subject: [PATCH 0494/1332] add support for bind mounting Signed-off-by: Steven Armstrong --- .../conf/type/__install_mount/gencode-remote | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__install_mount/gencode-remote b/cdist/conf/type/__install_mount/gencode-remote index ea5d260b..35f08e57 100755 --- a/cdist/conf/type/__install_mount/gencode-remote +++ b/cdist/conf/type/__install_mount/gencode-remote @@ -47,16 +47,19 @@ fi exit 1 } if [ "$type" = "swap" ]; then - echo "swapon \"$device\"" + printf 'swapon "%s"\n' "$device" else - if [ -f "$__object/parameter/options" ]; then - options="$(cat "$__object/parameter/options")" - else - options="" - fi - [ -n "$options" ] && options="-o $options" mount_point="${prefix}${dir}" - - echo "[ -d \"$mount_point\" ] || mkdir -p \"$mount_point\"" - echo "mount -t \"$type\" $options \"$device\" \"$mount_point\"" + printf '[ -d "%s" ] || mkdir -p "%s"\n' "$mount_point" "$mount_point" + printf 'mount' + if [ "$type" = "bind" ]; then + printf ' --bind' + else + printf ' -t "%s"' "$type" + fi + if [ -f "$__object/parameter/options" ]; then + printf ' -o %s' "$(cat "$__object/parameter/options")" + fi + printf ' "%s"' "$device" + printf ' "%s"\n' "$mount_point" fi From 1627b58cfc0623ff1193ab94ae61138a8cb7effa Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 1 Feb 2017 07:42:06 +0100 Subject: [PATCH 0495/1332] for bind mount also have to prefix device Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_mount/gencode-remote | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__install_mount/gencode-remote b/cdist/conf/type/__install_mount/gencode-remote index 35f08e57..b2498d41 100755 --- a/cdist/conf/type/__install_mount/gencode-remote +++ b/cdist/conf/type/__install_mount/gencode-remote @@ -54,6 +54,7 @@ else printf 'mount' if [ "$type" = "bind" ]; then printf ' --bind' + device="${prefix}${device}" else printf ' -t "%s"' "$type" fi From c740c968903b93695aee84bc7e7a6de0785789d6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 2 Feb 2017 22:52:39 +0100 Subject: [PATCH 0496/1332] set log level for cdist config based on env vars Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/gencode-local | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 30434d1b..a1caea69 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -22,8 +22,9 @@ chroot="$(cat "$__object/parameter/chroot")" remote_exec="$__type/files/remote/exec" remote_copy="$__type/files/remote/copy" -cdist_args="-v" -[ "$__debug" = "yes" ] && cdist_args="$cdist_args -d" +cdist_args="" +[ "$__verbose" = "yes" ] && cdist_args="-vv" +[ "$__debug" = "yes" ] && cdist_args="-d" cat << DONE cdist $cdist_args \ From b8fcd30a37d6a18e3d1d7e199e6e289f8cff69bf Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 2 Feb 2017 23:46:57 +0100 Subject: [PATCH 0497/1332] support for bind mounts Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_generate_fstab/gencode-local | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cdist/conf/type/__install_generate_fstab/gencode-local b/cdist/conf/type/__install_generate_fstab/gencode-local index 5dfc0249..1fec9334 100755 --- a/cdist/conf/type/__install_generate_fstab/gencode-local +++ b/cdist/conf/type/__install_generate_fstab/gencode-local @@ -44,6 +44,11 @@ for object in $(find "$__global/object/__install_mount" -type d -name "$__cdist_ tmpfs) pass=0 ;; + bind) + pass=0 + type=none + options="bind,$options" + ;; *) pass=1 ;; From 574f36f59398d005929a9f84f1a87d297a0157af Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 15 Jun 2017 22:42:46 +0200 Subject: [PATCH 0498/1332] fix order of arguments Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/gencode-local | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index a1caea69..3767253e 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011-2016 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -27,8 +27,8 @@ cdist_args="" [ "$__debug" = "yes" ] && cdist_args="-d" cat << DONE -cdist $cdist_args \ - config \ +cdist config \ + $cdist_args \ --remote-exec="$remote_exec $chroot" \ --remote-copy="$remote_copy $chroot" \ $__target_host From 93ccf925cde03d8d47223fe74130f7b1d29edebc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 20 Jan 2017 15:34:17 +0100 Subject: [PATCH 0499/1332] need a way to set remote.base_path from the command line Signed-off-by: Steven Armstrong --- cdist/argparse.py | 4 ++++ cdist/config.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 045c12bc..bdda5933 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -173,6 +173,10 @@ def get_parsers(): '-s', '--sequential', help='operate on multiple hosts sequentially (default)', action='store_false', dest='parallel') + parser['config_args'].add_argument( + '-r', '--remote-out-dir', + help='Directory to save cdist output in on the target host', + dest="remote_out_path") parser['config'] = parser['sub'].add_parser( 'config', parents=[parser['loglevel'], parser['beta'], parser['config_main'], diff --git a/cdist/config.py b/cdist/config.py index 03a2e6ee..271aea38 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -228,7 +228,8 @@ class Config(object): remote = cdist.exec.remote.Remote( target_host=target_host, remote_exec=remote_exec, - remote_copy=remote_copy) + remote_copy=remote_copy, + base_path=args.remote_out_path) c = cls(local, remote, dry_run=args.dry_run, jobs=args.jobs) c.run() From 9cee230ef59967840412019560509e6c0c873632 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 27 Jun 2017 17:47:30 +0200 Subject: [PATCH 0500/1332] alphabetical order ftw Signed-off-by: Steven Armstrong --- cdist/argparse.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index bdda5933..5873b8ef 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -169,14 +169,14 @@ def get_parsers(): '-p', '--parallel', help='operate on multiple hosts in parallel', action='store_true', dest='parallel') - parser['config_args'].add_argument( - '-s', '--sequential', - help='operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') parser['config_args'].add_argument( '-r', '--remote-out-dir', help='Directory to save cdist output in on the target host', dest="remote_out_path") + parser['config_args'].add_argument( + '-s', '--sequential', + help='operate on multiple hosts sequentially (default)', + action='store_false', dest='parallel') parser['config'] = parser['sub'].add_parser( 'config', parents=[parser['loglevel'], parser['beta'], parser['config_main'], From f968d90475388a18e9e0ef37a714390411fdbaa1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 27 Jun 2017 17:49:58 +0200 Subject: [PATCH 0501/1332] docs++ Signed-off-by: Steven Armstrong --- docs/src/man1/cdist.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index a46e1e02..ea3ded12 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -115,6 +115,10 @@ Configure/install one or more hosts. Operate on multiple hosts in parallel +.. option:: -r, --remote-out-dir + + Directory to save cdist output in on the target host + .. option:: -s, --sequential Operate on multiple hosts sequentially (default) From e894d67ddffecb0e539eeb924292be70f729300e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 27 Jun 2017 18:22:45 +0200 Subject: [PATCH 0502/1332] Update changelog. --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index 4a17e583..fff80f8e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,10 @@ Changelog --------- +next: + * Types: Fix install types (Steven Armstrong) + * Core: Add -r command line option for setting remote base path (Steven Armstrong) + 4.4.4: 2017-06-16 * Core: Support -j parallelization for object prepare and object run (Darko Poljak) * Type __install_mkfs: mkfs.vfat does not support -q (Nico Schottelius) From 9312bcb6b0749f2ab4740e972455f59de541201a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Jun 2017 12:52:10 +0200 Subject: [PATCH 0503/1332] chmod +x *manifest *gencode-* --- cdist/conf/type/__apt_mark/gencode-remote | 0 cdist/conf/type/__cron/gencode-remote | 0 cdist/conf/type/__cron/manifest | 0 cdist/conf/type/__daemontools/manifest | 0 cdist/conf/type/__daemontools_service/manifest | 0 cdist/conf/type/__docker_compose/gencode-remote | 0 cdist/conf/type/__docker_compose/manifest | 0 cdist/conf/type/__dog_vdi/gencode-remote | 0 cdist/conf/type/__dog_vdi/manifest | 0 cdist/conf/type/__filesystem/gencode-remote | 0 cdist/conf/type/__firewalld_rule/gencode-remote | 0 cdist/conf/type/__firewalld_rule/manifest | 0 cdist/conf/type/__firewalld_start/gencode-remote | 0 cdist/conf/type/__firewalld_start/manifest | 0 cdist/conf/type/__git/gencode-remote | 0 cdist/conf/type/__git/manifest | 0 cdist/conf/type/__go_get/gencode-remote | 0 cdist/conf/type/__go_get/manifest | 0 cdist/conf/type/__golang_from_vendor/gencode-remote | 0 cdist/conf/type/__golang_from_vendor/manifest | 0 cdist/conf/type/__grafana_dashboard/manifest | 0 cdist/conf/type/__iptables_apply/gencode-remote | 0 cdist/conf/type/__iptables_apply/manifest | 0 cdist/conf/type/__iptables_rule/manifest | 0 cdist/conf/type/__keyboard/manifest | 0 cdist/conf/type/__locale/gencode-remote | 0 cdist/conf/type/__locale/manifest | 0 cdist/conf/type/__locale_system/manifest | 0 cdist/conf/type/__package_dpkg/manifest | 0 cdist/conf/type/__package_emerge/gencode-remote | 0 cdist/conf/type/__package_emerge_dependencies/gencode-remote | 0 cdist/conf/type/__package_luarocks/manifest | 0 cdist/conf/type/__package_pip/gencode-remote | 0 cdist/conf/type/__package_zypper/gencode-remote | 0 cdist/conf/type/__pacman_conf/manifest | 0 cdist/conf/type/__pacman_conf_integrate/manifest | 0 cdist/conf/type/__pf_ruleset/gencode-local | 0 cdist/conf/type/__pf_ruleset/gencode-remote | 0 cdist/conf/type/__prometheus_alertmanager/manifest | 0 cdist/conf/type/__prometheus_server/manifest | 0 cdist/conf/type/__qemu_img/gencode-remote | 0 cdist/conf/type/__qemu_img/manifest | 0 cdist/conf/type/__rbenv/manifest | 0 cdist/conf/type/__rsync/gencode-local | 0 cdist/conf/type/__rsync/gencode-remote | 0 cdist/conf/type/__rsync/manifest | 0 cdist/conf/type/__start_on_boot/gencode-remote | 0 cdist/conf/type/__zypper_repo/gencode-remote | 0 cdist/conf/type/__zypper_service/gencode-remote | 0 cdist/conf/type/__zypper_service/manifest | 0 50 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 cdist/conf/type/__apt_mark/gencode-remote mode change 100644 => 100755 cdist/conf/type/__cron/gencode-remote mode change 100644 => 100755 cdist/conf/type/__cron/manifest mode change 100644 => 100755 cdist/conf/type/__daemontools/manifest mode change 100644 => 100755 cdist/conf/type/__daemontools_service/manifest mode change 100644 => 100755 cdist/conf/type/__docker_compose/gencode-remote mode change 100644 => 100755 cdist/conf/type/__docker_compose/manifest mode change 100644 => 100755 cdist/conf/type/__dog_vdi/gencode-remote mode change 100644 => 100755 cdist/conf/type/__dog_vdi/manifest mode change 100644 => 100755 cdist/conf/type/__filesystem/gencode-remote mode change 100644 => 100755 cdist/conf/type/__firewalld_rule/gencode-remote mode change 100644 => 100755 cdist/conf/type/__firewalld_rule/manifest mode change 100644 => 100755 cdist/conf/type/__firewalld_start/gencode-remote mode change 100644 => 100755 cdist/conf/type/__firewalld_start/manifest mode change 100644 => 100755 cdist/conf/type/__git/gencode-remote mode change 100644 => 100755 cdist/conf/type/__git/manifest mode change 100644 => 100755 cdist/conf/type/__go_get/gencode-remote mode change 100644 => 100755 cdist/conf/type/__go_get/manifest mode change 100644 => 100755 cdist/conf/type/__golang_from_vendor/gencode-remote mode change 100644 => 100755 cdist/conf/type/__golang_from_vendor/manifest mode change 100644 => 100755 cdist/conf/type/__grafana_dashboard/manifest mode change 100644 => 100755 cdist/conf/type/__iptables_apply/gencode-remote mode change 100644 => 100755 cdist/conf/type/__iptables_apply/manifest mode change 100644 => 100755 cdist/conf/type/__iptables_rule/manifest mode change 100644 => 100755 cdist/conf/type/__keyboard/manifest mode change 100644 => 100755 cdist/conf/type/__locale/gencode-remote mode change 100644 => 100755 cdist/conf/type/__locale/manifest mode change 100644 => 100755 cdist/conf/type/__locale_system/manifest mode change 100644 => 100755 cdist/conf/type/__package_dpkg/manifest mode change 100644 => 100755 cdist/conf/type/__package_emerge/gencode-remote mode change 100644 => 100755 cdist/conf/type/__package_emerge_dependencies/gencode-remote mode change 100644 => 100755 cdist/conf/type/__package_luarocks/manifest mode change 100644 => 100755 cdist/conf/type/__package_pip/gencode-remote mode change 100644 => 100755 cdist/conf/type/__package_zypper/gencode-remote mode change 100644 => 100755 cdist/conf/type/__pacman_conf/manifest mode change 100644 => 100755 cdist/conf/type/__pacman_conf_integrate/manifest mode change 100644 => 100755 cdist/conf/type/__pf_ruleset/gencode-local mode change 100644 => 100755 cdist/conf/type/__pf_ruleset/gencode-remote mode change 100644 => 100755 cdist/conf/type/__prometheus_alertmanager/manifest mode change 100644 => 100755 cdist/conf/type/__prometheus_server/manifest mode change 100644 => 100755 cdist/conf/type/__qemu_img/gencode-remote mode change 100644 => 100755 cdist/conf/type/__qemu_img/manifest mode change 100644 => 100755 cdist/conf/type/__rbenv/manifest mode change 100644 => 100755 cdist/conf/type/__rsync/gencode-local mode change 100644 => 100755 cdist/conf/type/__rsync/gencode-remote mode change 100644 => 100755 cdist/conf/type/__rsync/manifest mode change 100644 => 100755 cdist/conf/type/__start_on_boot/gencode-remote mode change 100644 => 100755 cdist/conf/type/__zypper_repo/gencode-remote mode change 100644 => 100755 cdist/conf/type/__zypper_service/gencode-remote mode change 100644 => 100755 cdist/conf/type/__zypper_service/manifest diff --git a/cdist/conf/type/__apt_mark/gencode-remote b/cdist/conf/type/__apt_mark/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__cron/manifest b/cdist/conf/type/__cron/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__daemontools/manifest b/cdist/conf/type/__daemontools/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__daemontools_service/manifest b/cdist/conf/type/__daemontools_service/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__docker_compose/manifest b/cdist/conf/type/__docker_compose/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__dog_vdi/gencode-remote b/cdist/conf/type/__dog_vdi/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__dog_vdi/manifest b/cdist/conf/type/__dog_vdi/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__filesystem/gencode-remote b/cdist/conf/type/__filesystem/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__firewalld_rule/gencode-remote b/cdist/conf/type/__firewalld_rule/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__firewalld_rule/manifest b/cdist/conf/type/__firewalld_rule/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__firewalld_start/gencode-remote b/cdist/conf/type/__firewalld_start/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__firewalld_start/manifest b/cdist/conf/type/__firewalld_start/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__git/manifest b/cdist/conf/type/__git/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__go_get/gencode-remote b/cdist/conf/type/__go_get/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__go_get/manifest b/cdist/conf/type/__go_get/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__golang_from_vendor/gencode-remote b/cdist/conf/type/__golang_from_vendor/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__golang_from_vendor/manifest b/cdist/conf/type/__golang_from_vendor/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__iptables_apply/gencode-remote b/cdist/conf/type/__iptables_apply/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__iptables_apply/manifest b/cdist/conf/type/__iptables_apply/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__iptables_rule/manifest b/cdist/conf/type/__iptables_rule/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__keyboard/manifest b/cdist/conf/type/__keyboard/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__locale/gencode-remote b/cdist/conf/type/__locale/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__locale_system/manifest b/cdist/conf/type/__locale_system/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__package_dpkg/manifest b/cdist/conf/type/__package_dpkg/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__package_emerge_dependencies/gencode-remote b/cdist/conf/type/__package_emerge_dependencies/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__package_luarocks/manifest b/cdist/conf/type/__package_luarocks/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__package_pip/gencode-remote b/cdist/conf/type/__package_pip/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__pacman_conf_integrate/manifest b/cdist/conf/type/__pacman_conf_integrate/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__pf_ruleset/gencode-local b/cdist/conf/type/__pf_ruleset/gencode-local old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__pf_ruleset/gencode-remote b/cdist/conf/type/__pf_ruleset/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__qemu_img/manifest b/cdist/conf/type/__qemu_img/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__rbenv/manifest b/cdist/conf/type/__rbenv/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__rsync/gencode-local b/cdist/conf/type/__rsync/gencode-local old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__rsync/gencode-remote b/cdist/conf/type/__rsync/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__rsync/manifest b/cdist/conf/type/__rsync/manifest old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__zypper_service/manifest b/cdist/conf/type/__zypper_service/manifest old mode 100644 new mode 100755 From fc97381c6e8704c1ae4086072cc5b30507010db6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Jun 2017 12:54:10 +0200 Subject: [PATCH 0504/1332] Add missing shebang. --- cdist/conf/type/__go_get/gencode-remote | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__go_get/gencode-remote b/cdist/conf/type/__go_get/gencode-remote index 5f1d3aae..fcf8746f 100755 --- a/cdist/conf/type/__go_get/gencode-remote +++ b/cdist/conf/type/__go_get/gencode-remote @@ -1,3 +1,5 @@ +#!/bin/sh + package=$__object_id cat< Date: Wed, 28 Jun 2017 13:19:32 +0200 Subject: [PATCH 0505/1332] Change shebang to #!/bin/sh -e --- cdist/conf/type/__apt_key/gencode-remote | 2 +- cdist/conf/type/__apt_key_uri/gencode-remote | 2 +- cdist/conf/type/__apt_key_uri/manifest | 2 +- cdist/conf/type/__apt_mark/gencode-remote | 2 +- cdist/conf/type/__apt_norecommends/manifest | 2 +- cdist/conf/type/__apt_ppa/gencode-remote | 2 +- cdist/conf/type/__apt_ppa/manifest | 2 +- cdist/conf/type/__apt_source/manifest | 2 +- cdist/conf/type/__apt_update_index/gencode-remote | 2 +- cdist/conf/type/__block/gencode-remote | 2 +- cdist/conf/type/__block/manifest | 2 +- cdist/conf/type/__ccollect_source/gencode-remote | 2 +- cdist/conf/type/__ccollect_source/manifest | 2 +- cdist/conf/type/__cdist/manifest | 2 +- cdist/conf/type/__cdistmarker/gencode-remote | 2 +- cdist/conf/type/__chroot_mount/gencode-local | 2 +- cdist/conf/type/__chroot_mount/gencode-remote | 2 +- cdist/conf/type/__chroot_umount/gencode-local | 2 +- cdist/conf/type/__chroot_umount/gencode-remote | 2 +- cdist/conf/type/__chroot_umount/manifest | 2 +- cdist/conf/type/__config_file/gencode-remote | 2 +- cdist/conf/type/__config_file/manifest | 2 +- cdist/conf/type/__consul/manifest | 2 +- cdist/conf/type/__consul_agent/gencode-remote | 2 +- cdist/conf/type/__consul_agent/manifest | 2 +- cdist/conf/type/__consul_check/manifest | 2 +- cdist/conf/type/__consul_reload/gencode-remote | 2 +- cdist/conf/type/__consul_service/manifest | 2 +- cdist/conf/type/__consul_template/manifest | 2 +- cdist/conf/type/__consul_template_template/manifest | 2 +- cdist/conf/type/__consul_watch_checks/manifest | 2 +- cdist/conf/type/__consul_watch_event/manifest | 2 +- cdist/conf/type/__consul_watch_key/manifest | 2 +- cdist/conf/type/__consul_watch_keyprefix/manifest | 2 +- cdist/conf/type/__consul_watch_nodes/manifest | 2 +- cdist/conf/type/__consul_watch_service/manifest | 2 +- cdist/conf/type/__consul_watch_services/manifest | 2 +- cdist/conf/type/__cron/gencode-remote | 2 +- cdist/conf/type/__cron/manifest | 2 +- cdist/conf/type/__daemontools/manifest | 2 +- cdist/conf/type/__daemontools_service/manifest | 2 +- cdist/conf/type/__debconf_set_selections/gencode-remote | 2 +- cdist/conf/type/__directory/gencode-remote | 2 +- cdist/conf/type/__docker/manifest | 2 +- cdist/conf/type/__docker_compose/gencode-remote | 2 +- cdist/conf/type/__docker_compose/manifest | 2 +- cdist/conf/type/__dog_vdi/gencode-remote | 2 +- cdist/conf/type/__dog_vdi/manifest | 2 +- cdist/conf/type/__dot_file/manifest | 2 +- cdist/conf/type/__file/gencode-local | 2 +- cdist/conf/type/__file/gencode-remote | 2 +- cdist/conf/type/__filesystem/gencode-remote | 2 +- cdist/conf/type/__firewalld_rule/gencode-remote | 2 +- cdist/conf/type/__firewalld_rule/manifest | 2 +- cdist/conf/type/__firewalld_start/gencode-remote | 2 +- cdist/conf/type/__firewalld_start/manifest | 2 +- cdist/conf/type/__git/gencode-remote | 2 +- cdist/conf/type/__git/manifest | 2 +- cdist/conf/type/__go_get/gencode-remote | 2 +- cdist/conf/type/__go_get/manifest | 2 +- cdist/conf/type/__golang_from_vendor/gencode-remote | 2 +- cdist/conf/type/__group/gencode-remote | 2 +- cdist/conf/type/__hostname/gencode-remote | 2 +- cdist/conf/type/__hostname/manifest | 2 +- cdist/conf/type/__hosts/manifest | 2 +- cdist/conf/type/__install_bootloader_grub/gencode-remote | 2 +- cdist/conf/type/__install_config/gencode-local | 2 +- cdist/conf/type/__install_config/manifest | 2 +- cdist/conf/type/__install_fstab/manifest | 2 +- cdist/conf/type/__install_generate_fstab/gencode-local | 2 +- cdist/conf/type/__install_mkfs/gencode-remote | 2 +- cdist/conf/type/__install_mkfs/manifest | 2 +- cdist/conf/type/__install_mount/gencode-remote | 2 +- cdist/conf/type/__install_mount/manifest | 2 +- cdist/conf/type/__install_partition_msdos/manifest | 2 +- cdist/conf/type/__install_partition_msdos_apply/gencode-remote | 2 +- cdist/conf/type/__install_reboot/gencode-remote | 2 +- cdist/conf/type/__install_reboot/manifest | 2 +- cdist/conf/type/__install_reset_disk/gencode-remote | 2 +- cdist/conf/type/__install_stage/gencode-remote | 2 +- cdist/conf/type/__install_umount/gencode-remote | 2 +- cdist/conf/type/__install_umount/manifest | 2 +- cdist/conf/type/__iptables_apply/gencode-remote | 2 +- cdist/conf/type/__iptables_apply/manifest | 2 +- cdist/conf/type/__iptables_rule/manifest | 2 +- cdist/conf/type/__issue/manifest | 2 +- cdist/conf/type/__jail/manifest | 2 +- cdist/conf/type/__jail_freebsd10/gencode-local | 2 +- cdist/conf/type/__jail_freebsd10/gencode-remote | 2 +- cdist/conf/type/__jail_freebsd9/gencode-local | 2 +- cdist/conf/type/__jail_freebsd9/gencode-remote | 2 +- cdist/conf/type/__key_value/gencode-remote | 2 +- cdist/conf/type/__key_value/manifest | 2 +- cdist/conf/type/__keyboard/manifest | 2 +- cdist/conf/type/__line/gencode-remote | 2 +- cdist/conf/type/__link/gencode-remote | 2 +- cdist/conf/type/__locale/gencode-remote | 2 +- cdist/conf/type/__locale/manifest | 2 +- cdist/conf/type/__locale_system/manifest | 2 +- cdist/conf/type/__motd/gencode-remote | 2 +- cdist/conf/type/__motd/manifest | 2 +- cdist/conf/type/__mount/gencode-remote | 2 +- cdist/conf/type/__mount/manifest | 2 +- cdist/conf/type/__mysql_database/gencode-remote | 2 +- cdist/conf/type/__package/manifest | 2 +- cdist/conf/type/__package_apt/gencode-remote | 2 +- cdist/conf/type/__package_dpkg/gencode-remote | 2 +- cdist/conf/type/__package_dpkg/manifest | 2 +- cdist/conf/type/__package_emerge/gencode-remote | 2 +- cdist/conf/type/__package_emerge_dependencies/gencode-remote | 2 +- cdist/conf/type/__package_luarocks/gencode-remote | 2 +- cdist/conf/type/__package_luarocks/manifest | 2 +- cdist/conf/type/__package_opkg/gencode-remote | 2 +- cdist/conf/type/__package_pacman/gencode-remote | 2 +- cdist/conf/type/__package_pip/gencode-remote | 2 +- cdist/conf/type/__package_pkg_freebsd/gencode-remote | 2 +- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 2 +- cdist/conf/type/__package_pkgng_freebsd/gencode-remote | 2 +- cdist/conf/type/__package_rubygem/gencode-remote | 2 +- cdist/conf/type/__package_update_index/gencode-remote | 2 +- cdist/conf/type/__package_upgrade_all/gencode-remote | 2 +- cdist/conf/type/__package_yum/gencode-remote | 2 +- cdist/conf/type/__package_zypper/gencode-remote | 2 +- cdist/conf/type/__pacman_conf/manifest | 2 +- cdist/conf/type/__pacman_conf_integrate/manifest | 2 +- cdist/conf/type/__pf_apply/gencode-remote | 2 +- cdist/conf/type/__pf_ruleset/gencode-local | 2 +- cdist/conf/type/__pf_ruleset/gencode-remote | 2 +- cdist/conf/type/__postfix/manifest | 2 +- cdist/conf/type/__postfix_master/gencode-remote | 2 +- cdist/conf/type/__postfix_master/manifest | 2 +- cdist/conf/type/__postfix_postconf/gencode-remote | 2 +- cdist/conf/type/__postfix_postconf/manifest | 2 +- cdist/conf/type/__postfix_postmap/gencode-remote | 2 +- cdist/conf/type/__postfix_postmap/manifest | 2 +- cdist/conf/type/__postfix_reload/gencode-remote | 2 +- cdist/conf/type/__postfix_reload/manifest | 2 +- cdist/conf/type/__postgres_database/gencode-remote | 2 +- cdist/conf/type/__postgres_extension/gencode-remote | 2 +- cdist/conf/type/__postgres_role/gencode-remote | 2 +- cdist/conf/type/__process/gencode-remote | 2 +- cdist/conf/type/__prometheus_alertmanager/manifest | 2 +- cdist/conf/type/__prometheus_server/manifest | 2 +- cdist/conf/type/__pyvenv/gencode-remote | 2 +- cdist/conf/type/__pyvenv/manifest | 2 +- cdist/conf/type/__qemu_img/gencode-remote | 2 +- cdist/conf/type/__qemu_img/manifest | 2 +- cdist/conf/type/__rbenv/manifest | 2 +- cdist/conf/type/__rsync/gencode-local | 2 +- cdist/conf/type/__rsync/gencode-remote | 2 +- cdist/conf/type/__rsync/manifest | 2 +- cdist/conf/type/__rvm/gencode-remote | 2 +- cdist/conf/type/__rvm/manifest | 2 +- cdist/conf/type/__rvm_gemset/gencode-remote | 2 +- cdist/conf/type/__rvm_ruby/gencode-remote | 2 +- cdist/conf/type/__rvm_ruby/manifest | 2 +- cdist/conf/type/__ssh_authorized_key/gencode-remote | 2 +- cdist/conf/type/__ssh_authorized_keys/manifest | 2 +- cdist/conf/type/__ssh_dot_ssh/manifest | 2 +- cdist/conf/type/__staged_file/gencode-local | 2 +- cdist/conf/type/__staged_file/manifest | 2 +- cdist/conf/type/__start_on_boot/gencode-remote | 2 +- cdist/conf/type/__sysctl/gencode-remote | 2 +- cdist/conf/type/__sysctl/manifest | 2 +- cdist/conf/type/__timezone/gencode-remote | 2 +- cdist/conf/type/__timezone/manifest | 2 +- cdist/conf/type/__update_alternatives/gencode-remote | 2 +- cdist/conf/type/__user/gencode-remote | 2 +- cdist/conf/type/__user_groups/gencode-remote | 2 +- cdist/conf/type/__yum_repo/manifest | 2 +- cdist/conf/type/__zypper_repo/gencode-remote | 2 +- cdist/conf/type/__zypper_service/gencode-remote | 2 +- cdist/conf/type/__zypper_service/manifest | 2 +- 173 files changed, 173 insertions(+), 173 deletions(-) diff --git a/cdist/conf/type/__apt_key/gencode-remote b/cdist/conf/type/__apt_key/gencode-remote index c6ead91c..9c4fa00c 100755 --- a/cdist/conf/type/__apt_key/gencode-remote +++ b/cdist/conf/type/__apt_key/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__apt_key_uri/gencode-remote b/cdist/conf/type/__apt_key_uri/gencode-remote index 078b8695..229b6564 100755 --- a/cdist/conf/type/__apt_key_uri/gencode-remote +++ b/cdist/conf/type/__apt_key_uri/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__apt_key_uri/manifest b/cdist/conf/type/__apt_key_uri/manifest index 8dddde56..bf7b267d 100755 --- a/cdist/conf/type/__apt_key_uri/manifest +++ b/cdist/conf/type/__apt_key_uri/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__apt_mark/gencode-remote b/cdist/conf/type/__apt_mark/gencode-remote index c1ac58b3..bc995444 100755 --- a/cdist/conf/type/__apt_mark/gencode-remote +++ b/cdist/conf/type/__apt_mark/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Ander Punnar (cdist at kvlt.ee) # diff --git a/cdist/conf/type/__apt_norecommends/manifest b/cdist/conf/type/__apt_norecommends/manifest index 9e633308..e737df89 100755 --- a/cdist/conf/type/__apt_norecommends/manifest +++ b/cdist/conf/type/__apt_norecommends/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__apt_ppa/gencode-remote b/cdist/conf/type/__apt_ppa/gencode-remote index 300a0e1e..f60cb7ac 100755 --- a/cdist/conf/type/__apt_ppa/gencode-remote +++ b/cdist/conf/type/__apt_ppa/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__apt_ppa/manifest b/cdist/conf/type/__apt_ppa/manifest index a67c7613..e1af21bd 100755 --- a/cdist/conf/type/__apt_ppa/manifest +++ b/cdist/conf/type/__apt_ppa/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2016 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__apt_source/manifest b/cdist/conf/type/__apt_source/manifest index 59c7c567..7957bf8c 100755 --- a/cdist/conf/type/__apt_source/manifest +++ b/cdist/conf/type/__apt_source/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__apt_update_index/gencode-remote b/cdist/conf/type/__apt_update_index/gencode-remote index 61ce11a9..70b59710 100755 --- a/cdist/conf/type/__apt_update_index/gencode-remote +++ b/cdist/conf/type/__apt_update_index/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__block/gencode-remote b/cdist/conf/type/__block/gencode-remote index 2e2147e5..f269c785 100755 --- a/cdist/conf/type/__block/gencode-remote +++ b/cdist/conf/type/__block/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__block/manifest b/cdist/conf/type/__block/manifest index bf96181c..8fea3e83 100755 --- a/cdist/conf/type/__block/manifest +++ b/cdist/conf/type/__block/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__ccollect_source/gencode-remote b/cdist/conf/type/__ccollect_source/gencode-remote index c41b5179..56003fef 100755 --- a/cdist/conf/type/__ccollect_source/gencode-remote +++ b/cdist/conf/type/__ccollect_source/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__ccollect_source/manifest b/cdist/conf/type/__ccollect_source/manifest index b95b75c3..22326d7b 100755 --- a/cdist/conf/type/__ccollect_source/manifest +++ b/cdist/conf/type/__ccollect_source/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__cdist/manifest b/cdist/conf/type/__cdist/manifest index 7c0ae60e..a97cf288 100755 --- a/cdist/conf/type/__cdist/manifest +++ b/cdist/conf/type/__cdist/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__cdistmarker/gencode-remote b/cdist/conf/type/__cdistmarker/gencode-remote index 5e889e52..e71955c4 100755 --- a/cdist/conf/type/__cdistmarker/gencode-remote +++ b/cdist/conf/type/__cdistmarker/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # Copyright (C) 2011 Daniel Maher (phrawzty+cdist at gmail.com) # diff --git a/cdist/conf/type/__chroot_mount/gencode-local b/cdist/conf/type/__chroot_mount/gencode-local index 2c3b51b8..b131346c 100755 --- a/cdist/conf/type/__chroot_mount/gencode-local +++ b/cdist/conf/type/__chroot_mount/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__chroot_mount/gencode-remote b/cdist/conf/type/__chroot_mount/gencode-remote index a3b94b33..4fbb3ffc 100755 --- a/cdist/conf/type/__chroot_mount/gencode-remote +++ b/cdist/conf/type/__chroot_mount/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__chroot_umount/gencode-local b/cdist/conf/type/__chroot_umount/gencode-local index a6793534..b3cb69c6 100755 --- a/cdist/conf/type/__chroot_umount/gencode-local +++ b/cdist/conf/type/__chroot_umount/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__chroot_umount/gencode-remote b/cdist/conf/type/__chroot_umount/gencode-remote index bb854efe..ff669e1b 100755 --- a/cdist/conf/type/__chroot_umount/gencode-remote +++ b/cdist/conf/type/__chroot_umount/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__chroot_umount/manifest b/cdist/conf/type/__chroot_umount/manifest index a6793534..b3cb69c6 100755 --- a/cdist/conf/type/__chroot_umount/manifest +++ b/cdist/conf/type/__chroot_umount/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__config_file/gencode-remote b/cdist/conf/type/__config_file/gencode-remote index e9b38c35..8a580e22 100755 --- a/cdist/conf/type/__config_file/gencode-remote +++ b/cdist/conf/type/__config_file/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__config_file/manifest b/cdist/conf/type/__config_file/manifest index 29add8b7..3155f79b 100755 --- a/cdist/conf/type/__config_file/manifest +++ b/cdist/conf/type/__config_file/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul/manifest b/cdist/conf/type/__consul/manifest index 7d0e73c5..cd79e5d9 100755 --- a/cdist/conf/type/__consul/manifest +++ b/cdist/conf/type/__consul/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # 2016 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__consul_agent/gencode-remote b/cdist/conf/type/__consul_agent/gencode-remote index 04662967..997aa831 100755 --- a/cdist/conf/type/__consul_agent/gencode-remote +++ b/cdist/conf/type/__consul_agent/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index 64efd366..820018c9 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # 2015 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__consul_check/manifest b/cdist/conf/type/__consul_check/manifest index 658e2598..8149b130 100755 --- a/cdist/conf/type/__consul_check/manifest +++ b/cdist/conf/type/__consul_check/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015-2016 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_reload/gencode-remote b/cdist/conf/type/__consul_reload/gencode-remote index 9369db73..839fd0c3 100755 --- a/cdist/conf/type/__consul_reload/gencode-remote +++ b/cdist/conf/type/__consul_reload/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_service/manifest b/cdist/conf/type/__consul_service/manifest index 4f52d542..d7a1b6e3 100755 --- a/cdist/conf/type/__consul_service/manifest +++ b/cdist/conf/type/__consul_service/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_template/manifest b/cdist/conf/type/__consul_template/manifest index fd249185..2236e5bd 100755 --- a/cdist/conf/type/__consul_template/manifest +++ b/cdist/conf/type/__consul_template/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_template_template/manifest b/cdist/conf/type/__consul_template_template/manifest index b832075d..5fe657d0 100755 --- a/cdist/conf/type/__consul_template_template/manifest +++ b/cdist/conf/type/__consul_template_template/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_watch_checks/manifest b/cdist/conf/type/__consul_watch_checks/manifest index c05ae9eb..ebb49e2e 100755 --- a/cdist/conf/type/__consul_watch_checks/manifest +++ b/cdist/conf/type/__consul_watch_checks/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_watch_event/manifest b/cdist/conf/type/__consul_watch_event/manifest index 4e36a10d..099054a5 100755 --- a/cdist/conf/type/__consul_watch_event/manifest +++ b/cdist/conf/type/__consul_watch_event/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_watch_key/manifest b/cdist/conf/type/__consul_watch_key/manifest index 4e36a10d..099054a5 100755 --- a/cdist/conf/type/__consul_watch_key/manifest +++ b/cdist/conf/type/__consul_watch_key/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_watch_keyprefix/manifest b/cdist/conf/type/__consul_watch_keyprefix/manifest index 4e36a10d..099054a5 100755 --- a/cdist/conf/type/__consul_watch_keyprefix/manifest +++ b/cdist/conf/type/__consul_watch_keyprefix/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_watch_nodes/manifest b/cdist/conf/type/__consul_watch_nodes/manifest index 4e36a10d..099054a5 100755 --- a/cdist/conf/type/__consul_watch_nodes/manifest +++ b/cdist/conf/type/__consul_watch_nodes/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_watch_service/manifest b/cdist/conf/type/__consul_watch_service/manifest index 6011e288..2825c716 100755 --- a/cdist/conf/type/__consul_watch_service/manifest +++ b/cdist/conf/type/__consul_watch_service/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__consul_watch_services/manifest b/cdist/conf/type/__consul_watch_services/manifest index 4e36a10d..099054a5 100755 --- a/cdist/conf/type/__consul_watch_services/manifest +++ b/cdist/conf/type/__consul_watch_services/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index 3c3ed6b3..f58896af 100755 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2013 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__cron/manifest b/cdist/conf/type/__cron/manifest index 9992df25..53973e07 100755 --- a/cdist/conf/type/__cron/manifest +++ b/cdist/conf/type/__cron/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Thomas Oettli (otho at sfs.biz) # diff --git a/cdist/conf/type/__daemontools/manifest b/cdist/conf/type/__daemontools/manifest index 550994a7..0763d7be 100755 --- a/cdist/conf/type/__daemontools/manifest +++ b/cdist/conf/type/__daemontools/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e pkg=$(cat "$__object/parameter/from-package") diff --git a/cdist/conf/type/__daemontools_service/manifest b/cdist/conf/type/__daemontools_service/manifest index 175066af..9e8e0bee 100755 --- a/cdist/conf/type/__daemontools_service/manifest +++ b/cdist/conf/type/__daemontools_service/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e RUN_PREFIX="#!/bin/sh exec 2>&1 diff --git a/cdist/conf/type/__debconf_set_selections/gencode-remote b/cdist/conf/type/__debconf_set_selections/gencode-remote index bb719c46..e99aef40 100755 --- a/cdist/conf/type/__debconf_set_selections/gencode-remote +++ b/cdist/conf/type/__debconf_set_selections/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2014 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index aba618ac..cced4624 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Steven Armstrong (steven-cdist armstrong.cc) diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index 1f473afb..1b1b1fb7 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote index bd1ad452..2b8267a9 100755 --- a/cdist/conf/type/__docker_compose/gencode-remote +++ b/cdist/conf/type/__docker_compose/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Dominique Roux (dominique.roux at ungleich.ch) # diff --git a/cdist/conf/type/__docker_compose/manifest b/cdist/conf/type/__docker_compose/manifest index 559375ef..c17f0f33 100755 --- a/cdist/conf/type/__docker_compose/manifest +++ b/cdist/conf/type/__docker_compose/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Dominique Roux (dominique.roux at ungleich.ch) # diff --git a/cdist/conf/type/__dog_vdi/gencode-remote b/cdist/conf/type/__dog_vdi/gencode-remote index 56e4108a..9d49506c 100755 --- a/cdist/conf/type/__dog_vdi/gencode-remote +++ b/cdist/conf/type/__dog_vdi/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__dog_vdi/manifest b/cdist/conf/type/__dog_vdi/manifest index be327a3a..869bdede 100755 --- a/cdist/conf/type/__dog_vdi/manifest +++ b/cdist/conf/type/__dog_vdi/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__dot_file/manifest b/cdist/conf/type/__dot_file/manifest index 4bc9f179..5e4957e5 100755 --- a/cdist/conf/type/__dot_file/manifest +++ b/cdist/conf/type/__dot_file/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # Copyright (C) 2016 Bogatov Dmitry # diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 4caa6df6..c79fc16a 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Steven Armstrong (steven-cdist armstrong.cc) diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index dcf3857b..fe1e2212 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Steven Armstrong (steven-cdist armstrong.cc) diff --git a/cdist/conf/type/__filesystem/gencode-remote b/cdist/conf/type/__filesystem/gencode-remote index 3ca1c498..0bcdc13c 100755 --- a/cdist/conf/type/__filesystem/gencode-remote +++ b/cdist/conf/type/__filesystem/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 - 2016 Daniel Heule (hda at sfs.biz) # diff --git a/cdist/conf/type/__firewalld_rule/gencode-remote b/cdist/conf/type/__firewalld_rule/gencode-remote index 8f1ba28a..4c824d39 100755 --- a/cdist/conf/type/__firewalld_rule/gencode-remote +++ b/cdist/conf/type/__firewalld_rule/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__firewalld_rule/manifest b/cdist/conf/type/__firewalld_rule/manifest index 5baf6da3..71156329 100755 --- a/cdist/conf/type/__firewalld_rule/manifest +++ b/cdist/conf/type/__firewalld_rule/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 David Hürlimann (david at ungleich.ch) # diff --git a/cdist/conf/type/__firewalld_start/gencode-remote b/cdist/conf/type/__firewalld_start/gencode-remote index 7a3b6298..3e767f68 100755 --- a/cdist/conf/type/__firewalld_start/gencode-remote +++ b/cdist/conf/type/__firewalld_start/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Darko Poljak(darko.poljak at ungleich.ch) # diff --git a/cdist/conf/type/__firewalld_start/manifest b/cdist/conf/type/__firewalld_start/manifest index 2c6a0219..98caaad9 100755 --- a/cdist/conf/type/__firewalld_start/manifest +++ b/cdist/conf/type/__firewalld_start/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Darko Poljak (darko.poljak at ungleich.ch) # diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote index c4fc1ef2..d0d0d4ed 100755 --- a/cdist/conf/type/__git/gencode-remote +++ b/cdist/conf/type/__git/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__git/manifest b/cdist/conf/type/__git/manifest index b2b0feb0..6fb870f4 100755 --- a/cdist/conf/type/__git/manifest +++ b/cdist/conf/type/__git/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__go_get/gencode-remote b/cdist/conf/type/__go_get/gencode-remote index fcf8746f..4c47a70e 100755 --- a/cdist/conf/type/__go_get/gencode-remote +++ b/cdist/conf/type/__go_get/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e package=$__object_id diff --git a/cdist/conf/type/__go_get/manifest b/cdist/conf/type/__go_get/manifest index 04e6a09a..a5cc4c80 100755 --- a/cdist/conf/type/__go_get/manifest +++ b/cdist/conf/type/__go_get/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e go_executable=$(cat "$__object/explorer/go-executable") [ -z "$go_executable" ] && echo "__go_get: Cannot find go executable; make sure it is installed and in PATH" >&2 && exit 1 diff --git a/cdist/conf/type/__golang_from_vendor/gencode-remote b/cdist/conf/type/__golang_from_vendor/gencode-remote index e372bf61..1654978b 100755 --- a/cdist/conf/type/__golang_from_vendor/gencode-remote +++ b/cdist/conf/type/__golang_from_vendor/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e version=$(cat "$__object/parameter/version") diff --git a/cdist/conf/type/__group/gencode-remote b/cdist/conf/type/__group/gencode-remote index 2aaa83f3..5847cb66 100755 --- a/cdist/conf/type/__group/gencode-remote +++ b/cdist/conf/type/__group/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2015 Steven Armstrong (steven-cdist at armstrong.cc) # 2011 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 4eb08723..bf09ba0c 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) # 2014 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 823d2f7e..21c2adc6 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # 2014 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__hosts/manifest b/cdist/conf/type/__hosts/manifest index 6fa21608..c536b83b 100755 --- a/cdist/conf/type/__hosts/manifest +++ b/cdist/conf/type/__hosts/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # Copyright (C) 2015 Bogatov Dmitry # # This program is free software: you can redistribute it and/or modify diff --git a/cdist/conf/type/__install_bootloader_grub/gencode-remote b/cdist/conf/type/__install_bootloader_grub/gencode-remote index 0db6dee6..6e6e5e85 100755 --- a/cdist/conf/type/__install_bootloader_grub/gencode-remote +++ b/cdist/conf/type/__install_bootloader_grub/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 3767253e..6682ce0a 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_config/manifest b/cdist/conf/type/__install_config/manifest index f26297b4..b920d8ab 100755 --- a/cdist/conf/type/__install_config/manifest +++ b/cdist/conf/type/__install_config/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_fstab/manifest b/cdist/conf/type/__install_fstab/manifest index 74af53c0..c5d24f3c 100755 --- a/cdist/conf/type/__install_fstab/manifest +++ b/cdist/conf/type/__install_fstab/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_generate_fstab/gencode-local b/cdist/conf/type/__install_generate_fstab/gencode-local index 1fec9334..5cc7d877 100755 --- a/cdist/conf/type/__install_generate_fstab/gencode-local +++ b/cdist/conf/type/__install_generate_fstab/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_mkfs/gencode-remote b/cdist/conf/type/__install_mkfs/gencode-remote index 63a4b96d..8fc2c98e 100755 --- a/cdist/conf/type/__install_mkfs/gencode-remote +++ b/cdist/conf/type/__install_mkfs/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # 2017 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__install_mkfs/manifest b/cdist/conf/type/__install_mkfs/manifest index e9d275a4..eb65757f 100755 --- a/cdist/conf/type/__install_mkfs/manifest +++ b/cdist/conf/type/__install_mkfs/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_mount/gencode-remote b/cdist/conf/type/__install_mount/gencode-remote index b2498d41..ce96279a 100755 --- a/cdist/conf/type/__install_mount/gencode-remote +++ b/cdist/conf/type/__install_mount/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_mount/manifest b/cdist/conf/type/__install_mount/manifest index 5afae7fc..72fc26e2 100755 --- a/cdist/conf/type/__install_mount/manifest +++ b/cdist/conf/type/__install_mount/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_partition_msdos/manifest b/cdist/conf/type/__install_partition_msdos/manifest index 636fbd6a..b32605fa 100755 --- a/cdist/conf/type/__install_partition_msdos/manifest +++ b/cdist/conf/type/__install_partition_msdos/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index 60f2fd1e..090a5d86 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_reboot/gencode-remote b/cdist/conf/type/__install_reboot/gencode-remote index c4307de8..00c04523 100755 --- a/cdist/conf/type/__install_reboot/gencode-remote +++ b/cdist/conf/type/__install_reboot/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_reboot/manifest b/cdist/conf/type/__install_reboot/manifest index fab80a1e..02689d82 100755 --- a/cdist/conf/type/__install_reboot/manifest +++ b/cdist/conf/type/__install_reboot/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_reset_disk/gencode-remote b/cdist/conf/type/__install_reset_disk/gencode-remote index 234715ac..947dd472 100755 --- a/cdist/conf/type/__install_reset_disk/gencode-remote +++ b/cdist/conf/type/__install_reset_disk/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_stage/gencode-remote b/cdist/conf/type/__install_stage/gencode-remote index 3b83ea61..3eb90477 100755 --- a/cdist/conf/type/__install_stage/gencode-remote +++ b/cdist/conf/type/__install_stage/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_umount/gencode-remote b/cdist/conf/type/__install_umount/gencode-remote index c275fe5d..8dcfb253 100755 --- a/cdist/conf/type/__install_umount/gencode-remote +++ b/cdist/conf/type/__install_umount/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__install_umount/manifest b/cdist/conf/type/__install_umount/manifest index c547e167..42cd19bf 100755 --- a/cdist/conf/type/__install_umount/manifest +++ b/cdist/conf/type/__install_umount/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__iptables_apply/gencode-remote b/cdist/conf/type/__iptables_apply/gencode-remote index c15d4d7f..a80cb936 100755 --- a/cdist/conf/type/__iptables_apply/gencode-remote +++ b/cdist/conf/type/__iptables_apply/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e if grep -q "^__file/etc/iptables.d/" "$__messages_in"; then echo /etc/init.d/iptables restart diff --git a/cdist/conf/type/__iptables_apply/manifest b/cdist/conf/type/__iptables_apply/manifest index 3bb2d976..0061d3de 100755 --- a/cdist/conf/type/__iptables_apply/manifest +++ b/cdist/conf/type/__iptables_apply/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__iptables_rule/manifest b/cdist/conf/type/__iptables_rule/manifest index 13cec523..ed78787f 100755 --- a/cdist/conf/type/__iptables_rule/manifest +++ b/cdist/conf/type/__iptables_rule/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__issue/manifest b/cdist/conf/type/__issue/manifest index d2720f2d..06eb120a 100755 --- a/cdist/conf/type/__issue/manifest +++ b/cdist/conf/type/__issue/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index 6df52c59..c3d9dfbe 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Jake Guffey (jake.guffey at eprotex.com) # diff --git a/cdist/conf/type/__jail_freebsd10/gencode-local b/cdist/conf/type/__jail_freebsd10/gencode-local index 8c1687a9..b2016f86 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-local +++ b/cdist/conf/type/__jail_freebsd10/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Jake Guffey (jake.guffey at eprotex.com) # diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index ae68616d..76241e0e 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012,2014,2016 Jake Guffey (jake.guffey at jointheirstm.org) # diff --git a/cdist/conf/type/__jail_freebsd9/gencode-local b/cdist/conf/type/__jail_freebsd9/gencode-local index 67420a6f..1ab7ff1a 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-local +++ b/cdist/conf/type/__jail_freebsd9/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Jake Guffey (jake.guffey at eprotex.com) # diff --git a/cdist/conf/type/__jail_freebsd9/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote index 6a4c64de..63b48e5c 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012,2014,2016 Jake Guffey (jake.guffey at jointheirstm.org) # diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index e6815cb6..7a60f94b 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2012-2014 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__key_value/manifest b/cdist/conf/type/__key_value/manifest index 56f4c874..c7801c89 100755 --- a/cdist/conf/type/__key_value/manifest +++ b/cdist/conf/type/__key_value/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2012 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__keyboard/manifest b/cdist/conf/type/__keyboard/manifest index 3bfddf0b..80cd4819 100755 --- a/cdist/conf/type/__keyboard/manifest +++ b/cdist/conf/type/__keyboard/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # Carlos Ortigoza (carlos.ortigoza at ungleich.ch) # diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index f73444e3..b9f118b1 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Steven Armstrong (steven-cdist at armstrong.cc) diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index 9e7831c7..4467fb8e 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # 2013-2014 Steven Armstrong (steven-cdist at armstrong.cc) diff --git a/cdist/conf/type/__locale/gencode-remote b/cdist/conf/type/__locale/gencode-remote index 538ce2cd..04e48712 100755 --- a/cdist/conf/type/__locale/gencode-remote +++ b/cdist/conf/type/__locale/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest index d360e9f3..cacd0b42 100755 --- a/cdist/conf/type/__locale/manifest +++ b/cdist/conf/type/__locale/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013-2015 Nico Schottelius (nico-cdist at schottelius.org) # 2015 David Hürlimann (david at ungleich.ch) diff --git a/cdist/conf/type/__locale_system/manifest b/cdist/conf/type/__locale_system/manifest index 02cf48df..80f7401b 100755 --- a/cdist/conf/type/__locale_system/manifest +++ b/cdist/conf/type/__locale_system/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2016 Steven Armstrong (steven-cdist at armstrong.cc) # 2016 Carlos Ortigoza (carlos.ortigoza at ungleich.ch) diff --git a/cdist/conf/type/__motd/gencode-remote b/cdist/conf/type/__motd/gencode-remote index 41fe3482..bc842cc8 100755 --- a/cdist/conf/type/__motd/gencode-remote +++ b/cdist/conf/type/__motd/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__motd/manifest b/cdist/conf/type/__motd/manifest index 4848a4c3..0e2e8097 100755 --- a/cdist/conf/type/__motd/manifest +++ b/cdist/conf/type/__motd/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__mount/gencode-remote b/cdist/conf/type/__mount/gencode-remote index 2626f3de..66d85f88 100755 --- a/cdist/conf/type/__mount/gencode-remote +++ b/cdist/conf/type/__mount/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__mount/manifest b/cdist/conf/type/__mount/manifest index 472b6e2e..73937899 100755 --- a/cdist/conf/type/__mount/manifest +++ b/cdist/conf/type/__mount/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__mysql_database/gencode-remote b/cdist/conf/type/__mysql_database/gencode-remote index b1c2e6a1..23e51b05 100755 --- a/cdist/conf/type/__mysql_database/gencode-remote +++ b/cdist/conf/type/__mysql_database/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Benedikt Koeppel (code@benediktkoeppel.ch) # diff --git a/cdist/conf/type/__package/manifest b/cdist/conf/type/__package/manifest index 525691bb..fe7abedc 100755 --- a/cdist/conf/type/__package/manifest +++ b/cdist/conf/type/__package/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index ef313070..e3e31c2b 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__package_dpkg/gencode-remote b/cdist/conf/type/__package_dpkg/gencode-remote index d4186e66..90921ae3 100755 --- a/cdist/conf/type/__package_dpkg/gencode-remote +++ b/cdist/conf/type/__package_dpkg/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Tomas Pospisek (tpo_deb sourcepole.ch) # diff --git a/cdist/conf/type/__package_dpkg/manifest b/cdist/conf/type/__package_dpkg/manifest index ff477c2d..9f0c1a97 100755 --- a/cdist/conf/type/__package_dpkg/manifest +++ b/cdist/conf/type/__package_dpkg/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Tomas Pospisek (tpo_deb sourcepole.ch) # diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote index 1199fc72..6abe2d61 100755 --- a/cdist/conf/type/__package_emerge/gencode-remote +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Thomas Oettli (otho at sfs.biz) # diff --git a/cdist/conf/type/__package_emerge_dependencies/gencode-remote b/cdist/conf/type/__package_emerge_dependencies/gencode-remote index 0c84e53d..face898a 100755 --- a/cdist/conf/type/__package_emerge_dependencies/gencode-remote +++ b/cdist/conf/type/__package_emerge_dependencies/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e gentoolkit_installed="$(cat "$__object/explorer/gentoolkit_installed")" flaggie_installed="$(cat "$__object/explorer/flaggie_installed")" diff --git a/cdist/conf/type/__package_luarocks/gencode-remote b/cdist/conf/type/__package_luarocks/gencode-remote index 1046a936..cae06b22 100755 --- a/cdist/conf/type/__package_luarocks/gencode-remote +++ b/cdist/conf/type/__package_luarocks/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 SwellPath, Inc. # Christian G. Warden diff --git a/cdist/conf/type/__package_luarocks/manifest b/cdist/conf/type/__package_luarocks/manifest index 8e626714..7d8262ca 100755 --- a/cdist/conf/type/__package_luarocks/manifest +++ b/cdist/conf/type/__package_luarocks/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 SwellPath, Inc. # Christian G. Warden diff --git a/cdist/conf/type/__package_opkg/gencode-remote b/cdist/conf/type/__package_opkg/gencode-remote index 2df31202..09fe69a4 100755 --- a/cdist/conf/type/__package_opkg/gencode-remote +++ b/cdist/conf/type/__package_opkg/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011,2013 Nico Schottelius (nico-cdist at schottelius.org) # 2012 Giel van Schijndel (giel plus cdist at mortis dot eu) diff --git a/cdist/conf/type/__package_pacman/gencode-remote b/cdist/conf/type/__package_pacman/gencode-remote index da1ac7c2..69a5d62a 100755 --- a/cdist/conf/type/__package_pacman/gencode-remote +++ b/cdist/conf/type/__package_pacman/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__package_pip/gencode-remote b/cdist/conf/type/__package_pip/gencode-remote index ccfdb92b..933406f2 100755 --- a/cdist/conf/type/__package_pip/gencode-remote +++ b/cdist/conf/type/__package_pip/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Nico Schottelius (nico-cdist at schottelius.org) # 2016 Darko Poljak (darko.poljak at gmail.com) diff --git a/cdist/conf/type/__package_pkg_freebsd/gencode-remote b/cdist/conf/type/__package_pkg_freebsd/gencode-remote index 5866a0a8..b51c3153 100755 --- a/cdist/conf/type/__package_pkg_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_freebsd/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Jake Guffey (jake.guffey at eprotex.com) # diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 5ba5f7ef..a10e2e86 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Andi Brönnimann (andi-cdist at v-net.ch) # 2012 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote index 3c3e41e9..aa00de6a 100755 --- a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Jake Guffey (jake.guffey at eprotex.com) # diff --git a/cdist/conf/type/__package_rubygem/gencode-remote b/cdist/conf/type/__package_rubygem/gencode-remote index dc755ad3..6d793ac0 100755 --- a/cdist/conf/type/__package_rubygem/gencode-remote +++ b/cdist/conf/type/__package_rubygem/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Chase Allen James # diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index bf6a532d..20beed5b 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Ricardo Catalinas Jiménez (jimenezrick at gmail.com) # diff --git a/cdist/conf/type/__package_upgrade_all/gencode-remote b/cdist/conf/type/__package_upgrade_all/gencode-remote index 3e25f45f..bcad8a43 100755 --- a/cdist/conf/type/__package_upgrade_all/gencode-remote +++ b/cdist/conf/type/__package_upgrade_all/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Ricardo Catalinas Jiménez (jimenezrick at gmail.com) # diff --git a/cdist/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote index 08c5c2b5..e9b48ee8 100755 --- a/cdist/conf/type/__package_yum/gencode-remote +++ b/cdist/conf/type/__package_yum/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2014 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote index d9f16f8d..d9372b6d 100755 --- a/cdist/conf/type/__package_zypper/gencode-remote +++ b/cdist/conf/type/__package_zypper/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Daniel Heule (hda at sfs.biz) diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest index b9679577..1561d613 100755 --- a/cdist/conf/type/__pacman_conf/manifest +++ b/cdist/conf/type/__pacman_conf/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Dominique Roux (dominique.roux4 at gmail.com) # diff --git a/cdist/conf/type/__pacman_conf_integrate/manifest b/cdist/conf/type/__pacman_conf_integrate/manifest index 1d02f3b3..b26bca50 100755 --- a/cdist/conf/type/__pacman_conf_integrate/manifest +++ b/cdist/conf/type/__pacman_conf_integrate/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Dominique Roux (dominique.roux4 at gmail.com # diff --git a/cdist/conf/type/__pf_apply/gencode-remote b/cdist/conf/type/__pf_apply/gencode-remote index f7c889b4..c8f7a25a 100755 --- a/cdist/conf/type/__pf_apply/gencode-remote +++ b/cdist/conf/type/__pf_apply/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Jake Guffey (jake.guffey at eprotex.com) # diff --git a/cdist/conf/type/__pf_ruleset/gencode-local b/cdist/conf/type/__pf_ruleset/gencode-local index 2db2ae06..b4bded98 100755 --- a/cdist/conf/type/__pf_ruleset/gencode-local +++ b/cdist/conf/type/__pf_ruleset/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Jake Guffey (jake.guffey at eprotex.com) # diff --git a/cdist/conf/type/__pf_ruleset/gencode-remote b/cdist/conf/type/__pf_ruleset/gencode-remote index 6e9030ea..12760fdf 100755 --- a/cdist/conf/type/__pf_ruleset/gencode-remote +++ b/cdist/conf/type/__pf_ruleset/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Jake Guffey (jake.guffey at eprotex.com) # diff --git a/cdist/conf/type/__postfix/manifest b/cdist/conf/type/__postfix/manifest index b425e072..1aea53a1 100755 --- a/cdist/conf/type/__postfix/manifest +++ b/cdist/conf/type/__postfix/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postfix_master/gencode-remote b/cdist/conf/type/__postfix_master/gencode-remote index 51edc668..7c109a69 100755 --- a/cdist/conf/type/__postfix_master/gencode-remote +++ b/cdist/conf/type/__postfix_master/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postfix_master/manifest b/cdist/conf/type/__postfix_master/manifest index af71b88e..4991a13d 100755 --- a/cdist/conf/type/__postfix_master/manifest +++ b/cdist/conf/type/__postfix_master/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postfix_postconf/gencode-remote b/cdist/conf/type/__postfix_postconf/gencode-remote index f886499b..6df0da7f 100755 --- a/cdist/conf/type/__postfix_postconf/gencode-remote +++ b/cdist/conf/type/__postfix_postconf/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postfix_postconf/manifest b/cdist/conf/type/__postfix_postconf/manifest index dbce5364..a82e13d7 100755 --- a/cdist/conf/type/__postfix_postconf/manifest +++ b/cdist/conf/type/__postfix_postconf/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postfix_postmap/gencode-remote b/cdist/conf/type/__postfix_postmap/gencode-remote index 1b370001..edb7711f 100755 --- a/cdist/conf/type/__postfix_postmap/gencode-remote +++ b/cdist/conf/type/__postfix_postmap/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postfix_postmap/manifest b/cdist/conf/type/__postfix_postmap/manifest index dbce5364..a82e13d7 100755 --- a/cdist/conf/type/__postfix_postmap/manifest +++ b/cdist/conf/type/__postfix_postmap/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postfix_reload/gencode-remote b/cdist/conf/type/__postfix_reload/gencode-remote index 0efd6022..7720dc49 100755 --- a/cdist/conf/type/__postfix_reload/gencode-remote +++ b/cdist/conf/type/__postfix_reload/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postfix_reload/manifest b/cdist/conf/type/__postfix_reload/manifest index dbce5364..a82e13d7 100755 --- a/cdist/conf/type/__postfix_reload/manifest +++ b/cdist/conf/type/__postfix_reload/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postgres_database/gencode-remote b/cdist/conf/type/__postgres_database/gencode-remote index c097efce..92301fb8 100755 --- a/cdist/conf/type/__postgres_database/gencode-remote +++ b/cdist/conf/type/__postgres_database/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__postgres_extension/gencode-remote b/cdist/conf/type/__postgres_extension/gencode-remote index 3408df86..f7895103 100755 --- a/cdist/conf/type/__postgres_extension/gencode-remote +++ b/cdist/conf/type/__postgres_extension/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2013 Tomas Pospisek (tpo_deb at sourcepole.ch) diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index 0230e48e..14240992 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote index 639940d9..1a606f5d 100755 --- a/cdist/conf/type/__process/gencode-remote +++ b/cdist/conf/type/__process/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Steven Armstrong (steven-cdist at armstrong.cc) diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index d885f2ed..555ab1a1 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e GOBIN=/opt/gocode/bin # where to find go binaries CONF_DIR=/etc/prometheus diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index 3c5f16e3..dee81bc2 100755 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e GOBIN=/opt/gocode/bin # where to find go binaries CONF_DIR=/etc/prometheus diff --git a/cdist/conf/type/__pyvenv/gencode-remote b/cdist/conf/type/__pyvenv/gencode-remote index 907e0ff6..a4f078c5 100755 --- a/cdist/conf/type/__pyvenv/gencode-remote +++ b/cdist/conf/type/__pyvenv/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Darko Poljak (darko.poljak at gmail.com) # diff --git a/cdist/conf/type/__pyvenv/manifest b/cdist/conf/type/__pyvenv/manifest index 3e41ad04..5d6a12e8 100755 --- a/cdist/conf/type/__pyvenv/manifest +++ b/cdist/conf/type/__pyvenv/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Darko Poljak (darko.poljak at gmail.com) # diff --git a/cdist/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote index bffedd26..9127e5ef 100755 --- a/cdist/conf/type/__qemu_img/gencode-remote +++ b/cdist/conf/type/__qemu_img/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # ################################################################################ # State: absent is handled by manifest - we need only to do stuff if image is diff --git a/cdist/conf/type/__qemu_img/manifest b/cdist/conf/type/__qemu_img/manifest index e0ff6e03..e7417389 100755 --- a/cdist/conf/type/__qemu_img/manifest +++ b/cdist/conf/type/__qemu_img/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # ################################################################################ # Default settings diff --git a/cdist/conf/type/__rbenv/manifest b/cdist/conf/type/__rbenv/manifest index 767abdba..e5c3d2f8 100755 --- a/cdist/conf/type/__rbenv/manifest +++ b/cdist/conf/type/__rbenv/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__rsync/gencode-local b/cdist/conf/type/__rsync/gencode-local index 8d268d7e..155f3a3a 100755 --- a/cdist/conf/type/__rsync/gencode-local +++ b/cdist/conf/type/__rsync/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Dominique Roux (dominique.roux4 at gmail.com) # diff --git a/cdist/conf/type/__rsync/gencode-remote b/cdist/conf/type/__rsync/gencode-remote index a1135ea6..074246af 100755 --- a/cdist/conf/type/__rsync/gencode-remote +++ b/cdist/conf/type/__rsync/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Dominique Roux (dominique.roux4 at gmail.com) # diff --git a/cdist/conf/type/__rsync/manifest b/cdist/conf/type/__rsync/manifest index 0e4cc1f4..9bd44c6d 100755 --- a/cdist/conf/type/__rsync/manifest +++ b/cdist/conf/type/__rsync/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Dominique Roux (dominique.roux4 at gmail.com) # diff --git a/cdist/conf/type/__rvm/gencode-remote b/cdist/conf/type/__rvm/gencode-remote index dbc6ba60..494c8fd8 100755 --- a/cdist/conf/type/__rvm/gencode-remote +++ b/cdist/conf/type/__rvm/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Evax Software # 2012 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__rvm/manifest b/cdist/conf/type/__rvm/manifest index 482c0d17..0230156b 100755 --- a/cdist/conf/type/__rvm/manifest +++ b/cdist/conf/type/__rvm/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Evax Software # diff --git a/cdist/conf/type/__rvm_gemset/gencode-remote b/cdist/conf/type/__rvm_gemset/gencode-remote index f0c0052b..78851f9a 100755 --- a/cdist/conf/type/__rvm_gemset/gencode-remote +++ b/cdist/conf/type/__rvm_gemset/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Evax Software # 2012 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__rvm_ruby/gencode-remote b/cdist/conf/type/__rvm_ruby/gencode-remote index f1de3906..9bbc6031 100755 --- a/cdist/conf/type/__rvm_ruby/gencode-remote +++ b/cdist/conf/type/__rvm_ruby/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Evax Software # diff --git a/cdist/conf/type/__rvm_ruby/manifest b/cdist/conf/type/__rvm_ruby/manifest index db8fd830..3f63eb11 100755 --- a/cdist/conf/type/__rvm_ruby/manifest +++ b/cdist/conf/type/__rvm_ruby/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index 6bbfa269..ae53c2fe 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 6a536e1b..9fad8896 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # 2014 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__ssh_dot_ssh/manifest b/cdist/conf/type/__ssh_dot_ssh/manifest index 4b797afb..bc3a3952 100755 --- a/cdist/conf/type/__ssh_dot_ssh/manifest +++ b/cdist/conf/type/__ssh_dot_ssh/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) # 2014 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__staged_file/gencode-local b/cdist/conf/type/__staged_file/gencode-local index 1a236789..8e2003af 100755 --- a/cdist/conf/type/__staged_file/gencode-local +++ b/cdist/conf/type/__staged_file/gencode-local @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # 2015 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__staged_file/manifest b/cdist/conf/type/__staged_file/manifest index 454948b4..1654e1d9 100755 --- a/cdist/conf/type/__staged_file/manifest +++ b/cdist/conf/type/__staged_file/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 0ab67a1a..63f0ba3c 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2016 Daniel Heule (hda at sfs.biz) diff --git a/cdist/conf/type/__sysctl/gencode-remote b/cdist/conf/type/__sysctl/gencode-remote index 0f3b0b40..b7fb02c8 100755 --- a/cdist/conf/type/__sysctl/gencode-remote +++ b/cdist/conf/type/__sysctl/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__sysctl/manifest b/cdist/conf/type/__sysctl/manifest index ac9117c4..2d8b8349 100755 --- a/cdist/conf/type/__sysctl/manifest +++ b/cdist/conf/type/__sysctl/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__timezone/gencode-remote b/cdist/conf/type/__timezone/gencode-remote index c07a61cb..d72da918 100755 --- a/cdist/conf/type/__timezone/gencode-remote +++ b/cdist/conf/type/__timezone/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index bcbe41c3..178a9ded 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Ramon Salvadó (rsalvado at gnuine dot com) # 2012-2015 Steven Armstrong (steven-cdist at armstrong.cc) diff --git a/cdist/conf/type/__update_alternatives/gencode-remote b/cdist/conf/type/__update_alternatives/gencode-remote index 19ea9968..0e7b0d89 100755 --- a/cdist/conf/type/__update_alternatives/gencode-remote +++ b/cdist/conf/type/__update_alternatives/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Nico Schottelius (nico-cdist at schottelius.org) # diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index 223d4d46..23762065 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2011 Nico Schottelius (nico-cdist at schottelius.org) diff --git a/cdist/conf/type/__user_groups/gencode-remote b/cdist/conf/type/__user_groups/gencode-remote index 6728228c..5518f333 100755 --- a/cdist/conf/type/__user_groups/gencode-remote +++ b/cdist/conf/type/__user_groups/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__yum_repo/manifest b/cdist/conf/type/__yum_repo/manifest index 950c3b7a..5f60d32c 100755 --- a/cdist/conf/type/__yum_repo/manifest +++ b/cdist/conf/type/__yum_repo/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) # diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index 26199c75..94c3f146 100755 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Daniel Heule (hda at sfs.biz) # diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote index d16ba8ee..e5b41cc6 100755 --- a/cdist/conf/type/__zypper_service/gencode-remote +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Daniel Heule (hda at sfs.biz) # diff --git a/cdist/conf/type/__zypper_service/manifest b/cdist/conf/type/__zypper_service/manifest index 7f853b3b..e4f0bcf6 100755 --- a/cdist/conf/type/__zypper_service/manifest +++ b/cdist/conf/type/__zypper_service/manifest @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2013 Daniel Heule (hda at sfs.biz) # From 9aa44657184f2f26faaa131356f9cba5cf056da5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Jun 2017 13:57:48 +0200 Subject: [PATCH 0506/1332] If script is executable then execute it, if not then assume it is a shell script. --- cdist/exec/local.py | 10 ++++++++-- docs/src/cdist-type.rst | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index e078dbd2..d30bc146 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -237,8 +237,14 @@ class Local(object): Return the output as a string. """ - command = [os.environ.get('CDIST_LOCAL_SHELL', "/bin/sh"), "-e"] - command.append(script) + if os.access(script, os.X_OK): + self.log.debug('%s is executable, running it', script) + command=[script] + else: + command = [os.environ.get('CDIST_LOCAL_SHELL', "/bin/sh"), "-e"] + self.log.debug('%s is NOT executable, running it with %s', + script, " ".join(command)) + command.append(script) return self.run(command=command, env=env, return_output=return_output, message_prefix=message_prefix, save_output=save_output) diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 2c5f9f6a..59423332 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -79,6 +79,12 @@ two underscores (__) to prevent collisions with other executables in $PATH. To implement a new type, create the directory **cdist/conf/type/__NAME**. +Type manifest and gencode can be written in any language. They just need to be +executable and have a proper shebang. If they are not executable then cdist assumes +they are written in shell so they are executed using '/bin/sh -e' or 'CDIST_LOCAL_SHELL'. + +For executable shell code it is suggested that shebang is '#!/bin/sh -e'. + Defining parameters ------------------- From 19b07dbbb21c5a5f86207c621453b561f208fb50 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Jun 2017 23:16:28 +0200 Subject: [PATCH 0507/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index fff80f8e..0791bd50 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Types: Fix install types (Steven Armstrong) * Core: Add -r command line option for setting remote base path (Steven Armstrong) + * Core: Allow manifest and gencode scripts to be written in any language (Darko Poljak) 4.4.4: 2017-06-16 * Core: Support -j parallelization for object prepare and object run (Darko Poljak) From adfec76bceb6470b5ed93eeed8d5dd31a6cbfaf3 Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Fri, 30 Jun 2017 16:01:07 +0100 Subject: [PATCH 0508/1332] Fix typos. --- docs/src/cdist-best-practice.rst | 8 ++++---- docs/src/cdist-explorer.rst | 4 ++-- docs/src/cdist-features.rst | 6 +++--- docs/src/cdist-hacker.rst | 14 +++++++------- docs/src/cdist-install.rst | 2 +- docs/src/cdist-manifest.rst | 4 ++-- docs/src/cdist-stages.rst | 5 ++--- docs/src/cdist-why.rst | 2 +- docs/src/man1/cdist.rst | 4 ++-- 9 files changed, 24 insertions(+), 25 deletions(-) diff --git a/docs/src/cdist-best-practice.rst b/docs/src/cdist-best-practice.rst index 493f1506..8f4f6df0 100644 --- a/docs/src/cdist-best-practice.rst +++ b/docs/src/cdist-best-practice.rst @@ -97,7 +97,7 @@ Including a possible common base that is reused across the different sites:: git merge common -The following **.git/config** is taken from a a real world scenario:: +The following **.git/config** is taken from a real world scenario: # Track upstream, merge from time to time [remote "upstream"] @@ -142,7 +142,7 @@ implement this scenario with a gateway host and sudo: - Setup the ssh-pubkey for this user that has the right to configure all hosts - Create a wrapper to update the cdist configuration in ~cdist/cdist - Allow every developer to execute this script via sudo as the user cdist -- Allow run of cdist as user cdist on specific hosts on a per user/group base +- Allow run of cdist as user cdist on specific hosts on a per user/group basis. - f.i. nico ALL=(ALL) NOPASSWD: /home/cdist/bin/cdist config hostabc @@ -213,11 +213,11 @@ Other content in cdist repository Usually the cdist repository contains all configuration items. Sometimes you may have additional resources that you would like to store in your central configuration -repositiory (like password files from KeepassX, +repository (like password files from KeepassX, Libreoffice diagrams, etc.). It is recommended to use a subfolder named "non-cdist" in the repository for such content: It allows you to -easily distinguish what is used by cdist and what not +easily distinguish what is used by cdist and what is not and also to store all important files in one repository. diff --git a/docs/src/cdist-explorer.rst b/docs/src/cdist-explorer.rst index 4bb61d7a..a3c4f490 100644 --- a/docs/src/cdist-explorer.rst +++ b/docs/src/cdist-explorer.rst @@ -3,8 +3,8 @@ Explorer Description ----------- -Explorer are small shell scripts, which will be executed on the target -host. The aim of the explorer is to give hints to types on how to act on the +Explorers are small shell scripts, which will be executed on the target +host. The aim of each explorer is to give hints to types on how to act on the target system. An explorer outputs the result to stdout, which is usually a one liner, but may be empty or multi line especially in the case of type explorers. diff --git a/docs/src/cdist-features.rst b/docs/src/cdist-features.rst index 7018d248..be56fa22 100644 --- a/docs/src/cdist-features.rst +++ b/docs/src/cdist-features.rst @@ -8,7 +8,7 @@ Simplicity Design + Type and core cleanly separated - + Sticks completly to the KISS (keep it simple and stupid) paradigma + + Sticks completely to the KISS (keep it simple and stupid) paradigm + Meaningful error messages - do not lose time debugging error messages + Consistency in behaviour, naming and documentation + No surprise factor: Only do what is obviously clear, no magic @@ -40,9 +40,9 @@ Requirements, Simplicity UNIX Reuse of existing tools like cat, find, mv, ... -UNIX, familar environment, documentation +UNIX, familiar environment, documentation Is available as manpages and HTML -UNIX, simplicity, familar environment +UNIX, simplicity, familiar environment cdist is configured in POSIX shell diff --git a/docs/src/cdist-hacker.rst b/docs/src/cdist-hacker.rst index d7d6a056..ea5dceb3 100644 --- a/docs/src/cdist-hacker.rst +++ b/docs/src/cdist-hacker.rst @@ -4,7 +4,7 @@ Hacking Welcome ------- Welcome dear hacker! I invite you to a tour of pointers to -get into the usable configuration mangament system, cdist. +get into the usable configuration management system, cdist. The first thing to know is probably that cdist is brought to you by people who care about how code looks like and who think @@ -21,18 +21,18 @@ subject prefixed with "[BUG] " or create an issue on github. Coding conventions (everywhere) ------------------------------- -If something should be better done or needs to fixed, add the word FIXME +If something should be improved or needs to be fixed, add the word FIXME nearby, so grepping for FIXME gives all positions that need to be fixed. -Indention is 4 spaces (welcome to the python world). +Indentation is 4 spaces (welcome to the python world). How to submit stuff for inclusion into upstream cdist ----------------------------------------------------- -If you did some cool changes to cdist, which you value as a benefit for -everybody using cdist, you're welcome to propose inclusion into upstream. +If you did some cool changes to cdist, which you think might be of benefit to other +cdist users, you're welcome to propose inclusion into upstream. -There are though some requirements to ensure your changes don't break others +There are some requirements to ensure your changes don't break other peoples work nor kill the authors brain: - All files should contain the usual header (Author, Copying, etc.) @@ -130,7 +130,7 @@ use **git stash** to stash your changes away:: git fetch -v origin git merge origin/master -Similar when you want to develop another new feature, you go back +Similarly when you want to develop another new feature, you go back to the master branch and create another branch based on it:: .. code-block:: sh diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst index 38db1a4e..1e1e8245 100644 --- a/docs/src/cdist-install.rst +++ b/docs/src/cdist-install.rst @@ -7,7 +7,7 @@ Requirements Source Host ~~~~~~~~~~~ -This is the machine you use to configure the target hosts. +This is the machine from which you will configure target hosts. * /bin/sh: A posix like shell (for instance bash, dash, zsh) * Python >= 3.2 diff --git a/docs/src/cdist-manifest.rst b/docs/src/cdist-manifest.rst index b29cf0d8..bb1ac69b 100644 --- a/docs/src/cdist-manifest.rst +++ b/docs/src/cdist-manifest.rst @@ -114,7 +114,7 @@ requirements can be added white space separated. Above the "require" variable is only set for the command that is immediately following it. Dependencies should always be declared that way. -On line 4 you can see that the instantion of a type "\__link" object needs +On line 4 you can see that the instantiation of a type "\__link" object needs the object "__file/etc/cdist-configured" to be present, before it can proceed. This also means that the "\__link" command must make sure, that either @@ -149,7 +149,7 @@ All objects that are created in a type manifest are automatically required from the type that is calling them. This is called "autorequirement" in cdist jargon. -You can find an more in depth description of the flow execution of manifests +You can find a more in depth description of the flow execution of manifests in `cdist execution stages `_ and of how types work in `cdist type `_. diff --git a/docs/src/cdist-stages.rst b/docs/src/cdist-stages.rst index fd19ce0d..751ba9c7 100644 --- a/docs/src/cdist-stages.rst +++ b/docs/src/cdist-stages.rst @@ -3,8 +3,7 @@ Execution stages Description ----------- -Starting the execution of deployment with cdist, cdist passes -through different stages. +When cdist is started, it passes through different stages. Stage 1: target information retrieval @@ -67,5 +66,5 @@ The cache stores the information from the current run for later use. Summary ------- -If, and only if, all the stages complete without an errors, the configuration +If, and only if, all the stages complete without errors, the configuration will be applied to the target. diff --git a/docs/src/cdist-why.rst b/docs/src/cdist-why.rst index e6aefefd..83f6c317 100644 --- a/docs/src/cdist-why.rst +++ b/docs/src/cdist-why.rst @@ -40,7 +40,7 @@ call cdist types, the result is always the same. Zero dependency configuration management ---------------------------------------- -Cdist requires very litte on a target system. Even better, +Cdist requires very little on a target system. Even better, in almost all cases all dependencies are usually fulfilled. Cdist does not require an agent or a high level programming languages on the target host: it will run on any host that diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index ea3ded12..9101d726 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -72,7 +72,7 @@ Configure/install one or more hosts. .. option:: -b, --beta - Enable beta functionalities. + Enable beta functionality. Can also be enabled using CDIST_BETA env var. @@ -244,7 +244,7 @@ CDIST_REMOTE_COPY Use this command for remote copy (should behave like scp). CDIST_BETA - Enable beta functionalities. + Enable beta functionality. EXIT STATUS ----------- From b42a6d74312818252aca1a5f77b956dc1cd63cde Mon Sep 17 00:00:00 2001 From: Mesar Hameed Date: Fri, 30 Jun 2017 16:45:14 +0100 Subject: [PATCH 0509/1332] Improvements to the english. --- docs/src/cdist-best-practice.rst | 2 +- docs/src/cdist-manifest.rst | 2 +- docs/src/cdist-why.rst | 4 ++-- docs/src/man1/cdist.rst | 17 +++++++++-------- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/src/cdist-best-practice.rst b/docs/src/cdist-best-practice.rst index 8f4f6df0..fdbb7a80 100644 --- a/docs/src/cdist-best-practice.rst +++ b/docs/src/cdist-best-practice.rst @@ -171,7 +171,7 @@ Templating } EOF -* in the manifest, export the relevant variables and add the following lines in your manifest: +* in the manifest, export the relevant variables and add the following lines to your manifest: .. code-block:: console diff --git a/docs/src/cdist-manifest.rst b/docs/src/cdist-manifest.rst index bb1ac69b..0e266943 100644 --- a/docs/src/cdist-manifest.rst +++ b/docs/src/cdist-manifest.rst @@ -51,7 +51,7 @@ The **initial manifest** is the entry point for cdist to find out, which **objects** to configure on the selected host. Cdist expects the initial manifest at **cdist/conf/manifest/init**. -Within this initial manifest you define, which objects should be +Within this initial manifest you define which objects should be created on which host. To distinguish between hosts, you can use the environment variable **__target_host** and/or **__target_hostname** and/or **__target_fqdn**. Let's have a look at a simple example:: diff --git a/docs/src/cdist-why.rst b/docs/src/cdist-why.rst index 83f6c317..1123a1de 100644 --- a/docs/src/cdist-why.rst +++ b/docs/src/cdist-why.rst @@ -42,7 +42,7 @@ Zero dependency configuration management Cdist requires very little on a target system. Even better, in almost all cases all dependencies are usually fulfilled. -Cdist does not require an agent or a high level programming +Cdist does not require an agent or high level programming languages on the target host: it will run on any host that has a **ssh server running** and a posix compatible shell (**/bin/sh**). Compared to other configuration management systems, @@ -52,7 +52,7 @@ Push based distribution ----------------------- Cdist uses the push based model for configuration. In this -scenario, one (or more) computers connect the target hosts +scenario, one (or more) computers connect to the target hosts and apply the configuration. That way the source host has very little requirements: Cdist can even run on a sysadmin notebook that is loosely connected to the network and has diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 9101d726..7112d14d 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -88,8 +88,8 @@ Configure/install one or more hosts. .. option:: -f HOSTFILE, --file HOSTFILE - Read additional hosts to operate on from specified file - or from stdin if '-' (each host on separate line). + Read specified file for a list of additional hosts to operate on + or if '-' is given, read stdin (one host per line). If no host or host file is specified then, by default, read hosts from stdin. For the file format see below. @@ -134,12 +134,13 @@ Configure/install one or more hosts. HOSTFILE FORMAT ~~~~~~~~~~~~~~~ -HOSTFILE contains hosts per line. -All characters after and including '#' until the end of line is a comment. -In a line, all leading and trailing whitespace characters are ignored. +The HOSTFILE contains one host per line. +A comment is started with '#' and continues to the end of the line. +Any leading and trailing whitespace on a line is ignored. Empty lines are ignored/skipped. -Hostfile line is processed like the following. First, all comments are + +The Hostfile lines are processed as follows. First, all comments are removed. Then all leading and trailing whitespace characters are stripped. If such a line results in empty line it is ignored/skipped. Otherwise, host string is used. @@ -275,10 +276,10 @@ options. For more details refer to :strong:`sshd_config`\ (5). When requirements for the same object are defined in different manifests (see example below), for example, in init manifest and in some other type manifest and those requirements differ then dependency resolver cannot detect -dependencies right. This happens because cdist cannot prepare all objects first +dependencies correctly. This happens because cdist cannot prepare all objects first and run all objects afterwards. Some object can depend on the result of type explorer(s) and explorers are executed during object run. cdist will detect -such case and write warning message. Example for such a case: +such case and display a warning message. An example of such a case: .. code-block:: sh From 7afa1057cd24173981e1a7243900f376e5f99d1d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 1 Jul 2017 09:21:51 +0200 Subject: [PATCH 0510/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 0791bd50..5c2d93ed 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Types: Fix install types (Steven Armstrong) * Core: Add -r command line option for setting remote base path (Steven Armstrong) * Core: Allow manifest and gencode scripts to be written in any language (Darko Poljak) + * Documentation: Improvements to the english and fix typos (Mesar Hameed) 4.4.4: 2017-06-16 * Core: Support -j parallelization for object prepare and object run (Darko Poljak) From b7873abf07f84da6087ce4f2b71db685e4b008d1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 1 Jul 2017 09:28:41 +0200 Subject: [PATCH 0511/1332] Improve english based on Mesar Hameed's contribution. --- cdist/argparse.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 5873b8ef..ea0fd159 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -95,7 +95,7 @@ def get_parsers(): parser['beta'] = argparse.ArgumentParser(add_help=False) parser['beta'].add_argument( '-b', '--beta', - help=('Enable beta functionalities. ' + help=('Enable beta functionality. ' 'Can also be enabled using CDIST_BETA env var.'), action='store_true', dest='beta', default='CDIST_BETA' in os.environ) @@ -160,10 +160,10 @@ def get_parsers(): 'host', nargs='*', help='host(s) to operate on') parser['config_args'].add_argument( '-f', '--file', - help=('Read additional hosts to operate on from specified file ' - 'or from stdin if \'-\' (each host on separate line). ' - 'If no host or host file is specified then, by default, ' - 'read hosts from stdin.'), + help=('Read specified file for a list of additional hosts to ' + 'operate on or if \'-\' is given, read stdin (one host per ' + 'line). If no host or host file is specified then, by ' + 'default, read hosts from stdin.'), dest='hostfile', required=False) parser['config_args'].add_argument( '-p', '--parallel', From 2a9bd77550078af2ce5bd3ba497e87c6490bbc2e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 1 Jul 2017 23:59:51 +0200 Subject: [PATCH 0512/1332] Merge custom cache path pattern from beta branch. --- cdist/__init__.py | 7 +++ cdist/argparse.py | 7 +++ cdist/config.py | 6 +- cdist/exec/local.py | 77 ++++++++++++++++++++------ cdist/hostsource.py | 38 +++++++------ cdist/test/exec/local.py | 37 +++++++++++++ completions/bash/cdist-completion.bash | 2 +- completions/zsh/_cdist | 2 +- docs/src/cdist-reference.rst.sh | 3 + docs/src/man1/cdist.rst | 40 +++++++++++-- 10 files changed, 176 insertions(+), 43 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index 6ea02d41..b0fd75ea 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -114,3 +114,10 @@ def str_hash(s): return hashlib.md5(s.encode('utf-8')).hexdigest() else: raise Error("Param should be string") + + +def home_dir(): + if 'HOME' in os.environ: + return os.path.join(os.environ['HOME'], ".cdist") + else: + return None diff --git a/cdist/argparse.py b/cdist/argparse.py index ea0fd159..3accedeb 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -116,6 +116,13 @@ def get_parsers(): # Config parser['config_main'] = argparse.ArgumentParser(add_help=False) + parser['config_main'].add_argument( + '-C', '--cache-path-pattern', + help=('Specify custom cache path pattern. It can also be set ' + 'by CDIST_CACHE_PATH_PATTERN environment variable. If ' + 'it is not set then default hostdir is used.'), + dest='cache_path_pattern', + default=os.environ.get('CDIST_CACHE_PATH_PATTERN')) parser['config_main'].add_argument( '-c', '--conf-dir', help=('Add configuration directory (can be repeated, ' diff --git a/cdist/config.py b/cdist/config.py index 271aea38..d342c657 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # # 2010-2015 Nico Schottelius (nico-cdist at schottelius.org) +# 2016-2017 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -223,7 +224,8 @@ class Config(object): base_root_path=host_base_path, host_dir_name=host_dir_name, initial_manifest=args.manifest, - add_conf_dirs=args.conf_dir) + add_conf_dirs=args.conf_dir, + cache_path_pattern=args.cache_path_pattern) remote = cdist.exec.remote.Remote( target_host=target_host, @@ -260,7 +262,7 @@ class Config(object): self.manifest.run_initial_manifest(self.local.initial_manifest) self.iterate_until_finished() - self.local.save_cache() + self.local.save_cache(start_time) self.log.info("Finished successful run in %s seconds", time.time() - start_time) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index d30bc146..fc2e7c09 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -2,7 +2,7 @@ # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2011-2015 Nico Schottelius (nico-cdist at schottelius.org) -# 2016 Darko Poljak (darko.poljak at gmail.com) +# 2016-2017 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -29,6 +29,8 @@ import subprocess import shutil import logging import tempfile +import time +import datetime import cdist import cdist.message @@ -51,7 +53,8 @@ class Local(object): host_dir_name, exec_path=sys.argv[0], initial_manifest=None, - add_conf_dirs=None): + add_conf_dirs=None, + cache_path_pattern=None): self.target_host = target_host self.hostdir = host_dir_name @@ -60,6 +63,7 @@ class Local(object): self.exec_path = exec_path self.custom_initial_manifest = initial_manifest self._add_conf_dirs = add_conf_dirs + self.cache_path_pattern = cache_path_pattern self._init_log() self._init_permissions() @@ -77,10 +81,7 @@ class Local(object): @property def home_dir(self): - if 'HOME' in os.environ: - return os.path.join(os.environ['HOME'], ".cdist") - else: - return None + return cdist.home_dir() def _init_log(self): self.log = logging.getLogger(self.target_host[0]) @@ -239,28 +240,70 @@ class Local(object): """ if os.access(script, os.X_OK): self.log.debug('%s is executable, running it', script) - command=[script] + command = [script] else: command = [os.environ.get('CDIST_LOCAL_SHELL', "/bin/sh"), "-e"] self.log.debug('%s is NOT executable, running it with %s', - script, " ".join(command)) + script, " ".join(command)) command.append(script) return self.run(command=command, env=env, return_output=return_output, message_prefix=message_prefix, save_output=save_output) - def save_cache(self): - destination = os.path.join(self.cache_path, self.hostdir) + def _cache_subpath_repl(self, matchobj): + if matchobj.group(2) == '%P': + repl = str(os.getpid()) + elif matchobj.group(2) == '%h': + repl = self.hostdir + elif matchobj.group(2) == '%N': + repl = self.target_host[0] + + return matchobj.group(1) + repl + + def _cache_subpath(self, start_time=time.time(), path_format=None): + if path_format: + repl_func = self._cache_subpath_repl + cache_subpath = re.sub(r'([^%]|^)(%h|%P|%N)', repl_func, + path_format) + dt = datetime.datetime.fromtimestamp(start_time) + cache_subpath = dt.strftime(cache_subpath) + else: + cache_subpath = self.hostdir + + i = 0 + while i < len(cache_subpath) and cache_subpath[i] == os.sep: + i += 1 + cache_subpath = cache_subpath[i:] + if not cache_subpath: + cache_subpath = self.hostdir + return cache_subpath + + def save_cache(self, start_time=time.time()): + self.log.debug("cache subpath pattern: {}".format( + self.cache_path_pattern)) + cache_subpath = self._cache_subpath(start_time, + self.cache_path_pattern) + self.log.debug("cache subpath: {}".format(cache_subpath)) + destination = os.path.join(self.cache_path, cache_subpath) self.log.debug("Saving " + self.base_path + " to " + destination) - try: - if os.path.exists(destination): - shutil.rmtree(destination) - except PermissionError as e: - raise cdist.Error( - "Cannot delete old cache %s: %s" % (destination, e)) + if not os.path.exists(destination): + shutil.move(self.base_path, destination) + else: + for direntry in os.listdir(self.base_path): + srcentry = os.path.join(self.base_path, direntry) + destentry = os.path.join(destination, direntry) + try: + if os.path.isdir(destentry): + shutil.rmtree(destentry) + elif os.path.exists(destentry): + os.remove(destentry) + except (PermissionError, OSError) as e: + raise cdist.Error( + "Cannot delete old cache entry {}: {}".format( + destentry, e)) + shutil.move(srcentry, destentry) - shutil.move(self.base_path, destination) # add target_host since cache dir can be hash-ed target_host host_cache_path = os.path.join(destination, "target_host") with open(host_cache_path, 'w') as hostf: diff --git a/cdist/hostsource.py b/cdist/hostsource.py index 9c2c0616..a7b8f0b4 100644 --- a/cdist/hostsource.py +++ b/cdist/hostsource.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2016 Darko Poljak (darko.poljak at gmail.com) +# 2016-2017 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -22,6 +22,25 @@ import fileinput +def hostfile_process_line(line, strip_func=str.strip): + """Return entry from read line or None if no entry present.""" + if not line: + return None + # remove comment if present + comment_index = line.find('#') + if comment_index >= 0: + foo = line[:comment_index] + else: + foo = line + # remove leading and trailing whitespaces + foo = strip_func(foo) + # skip empty lines + if foo: + return foo + else: + return None + + class HostSource(object): """ Host source object. @@ -32,22 +51,7 @@ class HostSource(object): self.source = source def _process_file_line(self, line): - """Return host from read line or None if no host present.""" - if not line: - return None - # remove comment if present - comment_index = line.find('#') - if comment_index >= 0: - host = line[:comment_index] - else: - host = line - # remove leading and trailing whitespaces - host = host.strip() - # skip empty lines - if host: - return host - else: - return None + return hostfile_process_line(line) def _hosts_from_sequence(self): for host in self.source: diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index 0efdfa0a..6336947c 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -26,6 +26,8 @@ import getpass import shutil import string import random +import time +import datetime import cdist from cdist import test @@ -224,6 +226,41 @@ class LocalTestCase(test.CdistTestCase): self.assertTrue(os.path.isdir(self.local.bin_path)) self.assertTrue(os.path.isdir(self.local.conf_path)) + def test_cache_subpath(self): + start_time = time.time() + dt = datetime.datetime.fromtimestamp(start_time) + pid = str(os.getpid()) + cases = [ + ['', self.local.hostdir, ], + ['/', self.local.hostdir, ], + ['//', self.local.hostdir, ], + ['/%%h', '%h', ], + ['%%h', '%h', ], + ['%P', pid, ], + ['x%P', 'x' + pid, ], + ['%h', self.hostdir, ], + ['%h/%Y-%m-%d/%H%M%S%f%P', + dt.strftime(self.hostdir + '/%Y-%m-%d/%H%M%S%f') + pid, ], + ['/%h/%Y-%m-%d/%H%M%S%f%P', + dt.strftime(self.hostdir + '/%Y-%m-%d/%H%M%S%f') + pid, ], + ['%Y-%m-%d/%H%M%S%f%P/%h', + dt.strftime('%Y-%m-%d/%H%M%S%f' + pid + os.sep + self.hostdir), ], + ['///%Y-%m-%d/%H%M%S%f%P/%h', + dt.strftime('%Y-%m-%d/%H%M%S%f' + pid + os.sep + self.hostdir), ], + ['%h/%Y-%m-%d/%H%M%S-%P', + dt.strftime(self.hostdir + '/%Y-%m-%d/%H%M%S-') + pid, ], + ['%Y-%m-%d/%H%M%S-%P/%h', + dt.strftime('%Y-%m-%d/%H%M%S-') + pid + os.sep + self.hostdir, ], + ['%N', self.local.target_host[0], ], + ] + for x in cases: + x.append(self.local._cache_subpath(start_time, x[0])) + # for fmt, expected, actual in cases: + # print('\'{}\' \'{}\' \'{}\''.format(fmt, expected, actual)) + for fmt, expected, actual in cases: + self.assertEqual(expected, actual) + + if __name__ == "__main__": import unittest diff --git a/completions/bash/cdist-completion.bash b/completions/bash/cdist-completion.bash index 1c4226c2..c6066ffb 100644 --- a/completions/bash/cdist-completion.bash +++ b/completions/bash/cdist-completion.bash @@ -37,7 +37,7 @@ _cdist() ;; config|install) opts="-h --help -d --debug -v --verbose -b --beta \ - -c --conf-dir -f --file -i --initial-manifest -j --jobs \ + -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs \ -n --dry-run -o --out-dir -p --parallel -s --sequential \ --remote-copy --remote-exec" COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) diff --git a/completions/zsh/_cdist b/completions/zsh/_cdist index 001356d4..f56c4ac7 100644 --- a/completions/zsh/_cdist +++ b/completions/zsh/_cdist @@ -36,7 +36,7 @@ _cdist() esac ;; config|install) - opts=(-h --help -d --debug -v --verbose -b --beta -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -s --sequential --remote-copy --remote-exec) + opts=(-h --help -d --debug -v --verbose -b --beta -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -s --sequential --remote-copy --remote-exec) compadd "$@" -- $opts ;; *) diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index 4b94b858..5889ded9 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -276,4 +276,7 @@ CDIST_REMOTE_COPY CDIST_BETA Enable beta functionalities. + +CDIST_CACHE_PATH_PATTERN + Custom cache path pattern. eof diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 7112d14d..73cbbd12 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -15,13 +15,13 @@ SYNOPSIS cdist banner [-h] [-d] [-v] - cdist config [-h] [-d] [-v] [-b] [-c CONF_DIR] [-f HOSTFILE] - [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-p] [-s] + cdist config [-h] [-d] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] + [-f HOSTFILE] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [host [host ...]] - cdist install [-h] [-d] [-v] [-b] [-c CONF_DIR] [-f HOSTFILE] - [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-p] [-s] + cdist install [-h] [-d] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] + [-f HOSTFILE] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [host [host ...]] @@ -76,6 +76,13 @@ Configure/install one or more hosts. Can also be enabled using CDIST_BETA env var. +.. option:: -C CACHE_PATH_PATTERN, --cache-path-pattern CACHE_PATH_PATTERN + + Sepcify custom cache path pattern. It can also be set by + CDIST_CACHE_PATH_PATTERN environment variable. If it is not set then + default hostdir is used. For more info on format see + :strong:`CACHE PATH PATTERN FORMAT` below. + .. option:: -c CONF_DIR, --conf-dir CONF_DIR Add a configuration directory. Can be specified multiple times. @@ -91,7 +98,8 @@ Configure/install one or more hosts. Read specified file for a list of additional hosts to operate on or if '-' is given, read stdin (one host per line). If no host or host file is specified then, by default, - read hosts from stdin. For the file format see below. + read hosts from stdin. For the file format see + :strong:`HOSTFILE FORMAT` below. .. option:: -i MANIFEST, --initial-manifest MANIFEST @@ -145,6 +153,24 @@ removed. Then all leading and trailing whitespace characters are stripped. If such a line results in empty line it is ignored/skipped. Otherwise, host string is used. +CACHE PATH PATTERN FORMAT +~~~~~~~~~~~~~~~~~~~~~~~~~ +Cache path pattern specifies path for a cache directory subdirectory. +In the path, '%N' will be substituted by the target host, '%h' will +be substituted by the calculated host directory, '%P' will be substituted +by the current process id. All format codes that +:strong:`python` :strong:`datetime.strftime()` function supports, except +'%h', are supported. These date/time directives format cdist config/install +start time. + +If empty pattern is specified then default calculated host directory +is used. + +Calculated host directory is a hash of a host cdist operates on. + +Resulting path is used to specify cache path subdirectory under which +current host cache data are saved. + SHELL ----- @@ -247,6 +273,9 @@ CDIST_REMOTE_COPY CDIST_BETA Enable beta functionality. +CDIST_CACHE_PATH_PATTERN + Custom cache path pattern. + EXIT STATUS ----------- The following exit values shall be returned: @@ -261,6 +290,7 @@ AUTHORS Originally written by Nico Schottelius and Steven Armstrong . + CAVEATS ------- When operating in parallel, either by operating in parallel for each host From a8dcba53a48f3f4f46b12665d644414dbb8a6c6f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 2 Jul 2017 00:07:02 +0200 Subject: [PATCH 0513/1332] Add missing -r option. --- docs/src/man1/cdist.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 73cbbd12..3bddbd02 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -16,13 +16,15 @@ SYNOPSIS cdist banner [-h] [-d] [-v] cdist config [-h] [-d] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] - [-f HOSTFILE] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] + [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] + [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] [host [host ...]] cdist install [-h] [-d] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] - [-f HOSTFILE] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] + [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] + [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] [host [host ...]] cdist shell [-h] [-d] [-v] [-s SHELL] From a6d2407b7362b228ff15df4ebabb2978da312446 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 2 Jul 2017 00:07:13 +0200 Subject: [PATCH 0514/1332] Add -r option to completions. --- completions/bash/cdist-completion.bash | 2 +- completions/zsh/_cdist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/completions/bash/cdist-completion.bash b/completions/bash/cdist-completion.bash index c6066ffb..6b58e2a2 100644 --- a/completions/bash/cdist-completion.bash +++ b/completions/bash/cdist-completion.bash @@ -38,7 +38,7 @@ _cdist() config|install) opts="-h --help -d --debug -v --verbose -b --beta \ -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs \ - -n --dry-run -o --out-dir -p --parallel -s --sequential \ + -n --dry-run -o --out-dir -p --parallel -r --remote-out-dir -s --sequential \ --remote-copy --remote-exec" COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 diff --git a/completions/zsh/_cdist b/completions/zsh/_cdist index f56c4ac7..082cad12 100644 --- a/completions/zsh/_cdist +++ b/completions/zsh/_cdist @@ -36,7 +36,7 @@ _cdist() esac ;; config|install) - opts=(-h --help -d --debug -v --verbose -b --beta -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -s --sequential --remote-copy --remote-exec) + opts=(-h --help -d --debug -v --verbose -b --beta -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -r --remote-out-dir -s --sequential --remote-copy --remote-exec) compadd "$@" -- $opts ;; *) From 35d2628941c6a27ede068ff7dc3ed47fd6f78216 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 2 Jul 2017 00:16:00 +0200 Subject: [PATCH 0515/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 5c2d93ed..976fa600 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Core: Add -r command line option for setting remote base path (Steven Armstrong) * Core: Allow manifest and gencode scripts to be written in any language (Darko Poljak) * Documentation: Improvements to the english and fix typos (Mesar Hameed) + * Core: Merge -C custom cache path pattern option from beta branch (Darko Poljak) 4.4.4: 2017-06-16 * Core: Support -j parallelization for object prepare and object run (Darko Poljak) From 138705e3dc7150ad37e828fa91efefef73b2beed Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 2 Jul 2017 00:32:43 +0200 Subject: [PATCH 0516/1332] Code improvements. --- cdist/config.py | 65 +++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index d342c657..19679a4c 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -74,6 +74,24 @@ class Config(object): "Error reading hosts from \'{}\': {}".format( source, e)) + @staticmethod + def construct_remote_exec_copy_patterns(args): + # default remote cmd patterns + args.remote_exec_pattern = None + args.remote_copy_pattern = None + + args_dict = vars(args) + # if remote-exec and/or remote-copy args are None then user + # didn't specify command line options nor env vars: + # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC + if (args_dict['remote_copy'] is None or + args_dict['remote_exec'] is None): + mux_opts = inspect_ssh_mux_opts() + if args_dict['remote_exec'] is None: + args.remote_exec_pattern = cdist.REMOTE_EXEC + mux_opts + if args_dict['remote_copy'] is None: + args.remote_copy_pattern = cdist.REMOTE_COPY + mux_opts + @classmethod def _check_and_prepare_args(cls, args): if args.manifest == '-' and args.hostfile == '-': @@ -99,30 +117,6 @@ class Config(object): args.manifest = initial_manifest_temp_path atexit.register(lambda: os.remove(initial_manifest_temp_path)) - # default remote cmd patterns - args.remote_exec_pattern = None - args.remote_copy_pattern = None - - args_dict = vars(args) - # if remote-exec and/or remote-copy args are None then user - # didn't specify command line options nor env vars: - # inspect multiplexing options for default cdist.REMOTE_COPY/EXEC - if (args_dict['remote_copy'] is None or - args_dict['remote_exec'] is None): - mux_opts = inspect_ssh_mux_opts() - if args_dict['remote_exec'] is None: - args.remote_exec_pattern = cdist.REMOTE_EXEC + mux_opts - if args_dict['remote_copy'] is None: - args.remote_copy_pattern = cdist.REMOTE_COPY + mux_opts - - @classmethod - def _base_root_path(cls, args): - if args.out_path: - base_root_path = args.out_path - else: - base_root_path = tempfile.mkdtemp() - return base_root_path - @classmethod def commandline(cls, args): """Configure remote system""" @@ -136,13 +130,14 @@ class Config(object): failed_hosts = [] time_start = time.time() - base_root_path = cls._base_root_path(args) + cls.construct_remote_exec_copy_patterns(args) + base_root_path = cls.create_base_root_path(args.out_path) hostcnt = 0 for host in itertools.chain(cls.hosts(args.host), cls.hosts(args.hostfile)): - hostdir = cdist.str_hash(host) - host_base_path = os.path.join(base_root_path, hostdir) + host_base_path, hostdir = cls.create_host_base_dirs( + host, base_root_path) log.debug("Base root path for target host \"{}\" is \"{}\"".format( host, host_base_path)) @@ -252,6 +247,22 @@ class Config(object): else: raise + @staticmethod + def create_base_root_path(out_path=None): + if out_path: + base_root_path = out_path + else: + base_root_path = tempfile.mkdtemp() + + return base_root_path + + @staticmethod + def create_host_base_dirs(host, base_root_path): + hostdir = cdist.str_hash(host) + host_base_path = os.path.join(base_root_path, hostdir) + + return (host_base_path, hostdir) + def run(self): """Do what is most often done: deploy & cleanup""" start_time = time.time() From c052e507eb4103c6a82a80db0b5e7b4837dc5562 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sun, 2 Jul 2017 11:50:22 +0300 Subject: [PATCH 0517/1332] shellcheck __apt_mark --- cdist/conf/type/__apt_mark/explorer/apt_version | 2 +- cdist/conf/type/__apt_mark/explorer/package_installed | 2 +- cdist/conf/type/__apt_mark/explorer/state | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__apt_mark/explorer/apt_version b/cdist/conf/type/__apt_mark/explorer/apt_version index 32a0a58f..827d9db2 100644 --- a/cdist/conf/type/__apt_mark/explorer/apt_version +++ b/cdist/conf/type/__apt_mark/explorer/apt_version @@ -26,6 +26,6 @@ apt_version_is=$(dpkg-query --show --showformat '${Version}' apt) apt_version_should=0.8.14.2 -dpkg --compare-versions $apt_version_should le $apt_version_is \ +dpkg --compare-versions "$apt_version_should" le "$apt_version_is" \ && echo 0 \ || echo 1 diff --git a/cdist/conf/type/__apt_mark/explorer/package_installed b/cdist/conf/type/__apt_mark/explorer/package_installed index c78ac3a9..c37c5e76 100644 --- a/cdist/conf/type/__apt_mark/explorer/package_installed +++ b/cdist/conf/type/__apt_mark/explorer/package_installed @@ -24,7 +24,7 @@ else name="$__object_id" fi -dpkg-query --show --showformat '${Status}' $name 2>/dev/null \ +dpkg-query --show --showformat '${Status}' "$name" 2>/dev/null \ | grep -q 'ok installed' \ && echo 0 \ || echo 1 diff --git a/cdist/conf/type/__apt_mark/explorer/state b/cdist/conf/type/__apt_mark/explorer/state index 3b70003a..565ad70f 100644 --- 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 -q $name && echo hold || echo unhold +apt-mark showhold | grep -q "$name" && echo hold || echo unhold From e4d9f78349550a591c2e17676661312b519da07e Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sun, 2 Jul 2017 11:51:59 +0300 Subject: [PATCH 0518/1332] grep fixed string --- cdist/conf/type/__apt_mark/explorer/package_installed | 2 +- cdist/conf/type/__apt_mark/explorer/state | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__apt_mark/explorer/package_installed b/cdist/conf/type/__apt_mark/explorer/package_installed index c37c5e76..059e44f4 100644 --- a/cdist/conf/type/__apt_mark/explorer/package_installed +++ b/cdist/conf/type/__apt_mark/explorer/package_installed @@ -25,6 +25,6 @@ else fi dpkg-query --show --showformat '${Status}' "$name" 2>/dev/null \ - | grep -q 'ok installed' \ + | grep -Fq 'ok installed' \ && echo 0 \ || echo 1 diff --git a/cdist/conf/type/__apt_mark/explorer/state b/cdist/conf/type/__apt_mark/explorer/state index 565ad70f..1dfdc911 100644 --- 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 -q "$name" && echo hold || echo unhold +apt-mark showhold | grep -Fq "$name" && echo hold || echo unhold From df437851f0f756fa9aee6f379e3ce33337c5fc73 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sun, 2 Jul 2017 12:19:40 +0300 Subject: [PATCH 0519/1332] add -e --- cdist/conf/type/__apt_mark/explorer/apt_version | 2 +- cdist/conf/type/__apt_mark/explorer/package_installed | 2 +- cdist/conf/type/__apt_mark/explorer/state | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__apt_mark/explorer/apt_version b/cdist/conf/type/__apt_mark/explorer/apt_version index 827d9db2..7bb90cc2 100644 --- a/cdist/conf/type/__apt_mark/explorer/apt_version +++ b/cdist/conf/type/__apt_mark/explorer/apt_version @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Ander Punnar (cdist at kvlt.ee) # diff --git a/cdist/conf/type/__apt_mark/explorer/package_installed b/cdist/conf/type/__apt_mark/explorer/package_installed index 059e44f4..0b072cbc 100644 --- a/cdist/conf/type/__apt_mark/explorer/package_installed +++ b/cdist/conf/type/__apt_mark/explorer/package_installed @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Ander Punnar (cdist at kvlt.ee) # diff --git a/cdist/conf/type/__apt_mark/explorer/state b/cdist/conf/type/__apt_mark/explorer/state index 1dfdc911..b7fe08fa 100644 --- a/cdist/conf/type/__apt_mark/explorer/state +++ b/cdist/conf/type/__apt_mark/explorer/state @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e # # 2016 Ander Punnar (cdist at kvlt.ee) # From 49f9760eacfd9eecdd3bee325efffb0bc92c66cd Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Mon, 3 Jul 2017 15:18:27 +0300 Subject: [PATCH 0520/1332] +x --- cdist/conf/type/__apt_mark/explorer/apt_version | 0 cdist/conf/type/__apt_mark/explorer/package_installed | 0 cdist/conf/type/__apt_mark/explorer/state | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 cdist/conf/type/__apt_mark/explorer/apt_version mode change 100644 => 100755 cdist/conf/type/__apt_mark/explorer/package_installed mode change 100644 => 100755 cdist/conf/type/__apt_mark/explorer/state diff --git a/cdist/conf/type/__apt_mark/explorer/apt_version b/cdist/conf/type/__apt_mark/explorer/apt_version old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__apt_mark/explorer/package_installed b/cdist/conf/type/__apt_mark/explorer/package_installed old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__apt_mark/explorer/state b/cdist/conf/type/__apt_mark/explorer/state old mode 100644 new mode 100755 From 0e8302c20403da8a487b0ba5363741a14f01c079 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 4 Jul 2017 19:23:51 +0300 Subject: [PATCH 0521/1332] if no --source, then create only if there's no file --- cdist/conf/type/__file/gencode-local | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index c79fc16a..932251fe 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -29,8 +29,11 @@ upload_file= create_file= if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then if [ ! -f "$__object/parameter/source" ]; then - create_file=1 - echo create >> "$__messages_out" + remote_stat="$(cat "$__object/explorer/stat")" + if [ -z "$remote_stat" ]; then + create_file=1 + echo create >> "$__messages_out" + fi else source="$(cat "$__object/parameter/source")" if [ "$source" = "-" ]; then From 6a6716035bfd52043ac34621ab49b3019fb30fe8 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 4 Jul 2017 19:25:08 +0300 Subject: [PATCH 0522/1332] one space too much --- cdist/conf/type/__file/gencode-local | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 932251fe..aec4e43e 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -31,8 +31,8 @@ if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then if [ ! -f "$__object/parameter/source" ]; then remote_stat="$(cat "$__object/explorer/stat")" if [ -z "$remote_stat" ]; then - create_file=1 - echo create >> "$__messages_out" + create_file=1 + echo create >> "$__messages_out" fi else source="$(cat "$__object/parameter/source")" From 01ca5910ecb463dcb1e546ce26e499e0614afeb9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Jul 2017 23:49:27 +0200 Subject: [PATCH 0523/1332] increase ControlPersist to 30 to workaround #542 Signed-off-by: Steven Armstrong --- cdist/util/remoteutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/util/remoteutil.py b/cdist/util/remoteutil.py index 2bd12fdf..4950ef8b 100644 --- a/cdist/util/remoteutil.py +++ b/cdist/util/remoteutil.py @@ -36,7 +36,7 @@ def inspect_ssh_mux_opts(): wanted_mux_opts = { "ControlPath": "{}", "ControlMaster": "auto", - "ControlPersist": "10", + "ControlPersist": "30", } mux_opts = " ".join([" -o {}={}".format( x, wanted_mux_opts[x]) for x in wanted_mux_opts]) From c63ab44c9cefcedd355d6952677d3cdab9ac61fe Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Jun 2017 10:18:53 +0200 Subject: [PATCH 0524/1332] Define better warning facility. --- cdist/__init__.py | 2 +- cdist/argparse.py | 31 +++++++++++++++++++++++-------- cdist/log.py | 35 +++++++++++++++++++++++++++++++++++ cdist/util/ipaddr.py | 4 ++-- docs/src/man1/cdist.rst | 10 +++++++--- scripts/cdist | 3 --- 6 files changed, 68 insertions(+), 17 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index b0fd75ea..d92205a6 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -20,9 +20,9 @@ # import os -import subprocess import hashlib +import cdist.log import cdist.version VERSION = cdist.version.VERSION diff --git a/cdist/argparse.py b/cdist/argparse.py index 3accedeb..8689be79 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -17,13 +17,20 @@ EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/" parser = None +_verbosity_level_off = -2 +_verbosity_level_debug = 3 _verbosity_level = { - 0: logging.ERROR, - 1: logging.WARNING, - 2: logging.INFO, + _verbosity_level_off: logging.OFF, + -1: logging.ERROR, + 0: logging.WARNING, + 1: logging.INFO, + 2: logging.VERBOSE, + 3: logging.DEBUG, + 4: logging.TRACE, } +# All verbosity levels above 4 are TRACE. _verbosity_level = collections.defaultdict( - lambda: logging.DEBUG, _verbosity_level) + lambda: logging.TRACE, _verbosity_level) def add_beta_command(cmd): @@ -83,13 +90,18 @@ def get_parsers(): '-d', '--debug', help=('Set log level to debug (deprecated, use -vvv instead)'), action='store_true', default=False) + parser['loglevel'].add_argument( + '-q', '--quiet', + help='Quiet mode: disables logging, including WARNING and ERROR', + action='store_true', default=False) parser['loglevel'].add_argument( '-v', '--verbose', help=('Increase the verbosity level. Every instance of -v ' 'increments the verbosity level by one. Its default value ' - 'is 0. There are 4 levels of verbosity. The order of levels ' - 'from the lowest to the highest are: ERROR (0), ' - 'WARNING (1), INFO (2) and DEBUG (3 or higher).'), + 'is 0 which includes ERROR and WARNING levels. ' + 'The levels, in order from the lowest to the highest, are: ' + 'ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) ' + 'TRACE (4 or higher).'), action='count', default=0) parser['beta'] = argparse.ArgumentParser(add_help=False) @@ -213,10 +225,13 @@ def get_parsers(): def handle_loglevel(args): if args.debug: retval = "-d/--debug is deprecated, use -vvv instead" - args.verbose = 3 + args.verbose = _verbosity_level_debug else: retval = None + if args.quiet: + args.verbose = _verbosity_level_off + logging.root.setLevel(_verbosity_level[args.verbose]) return retval diff --git a/cdist/log.py b/cdist/log.py index 2341c282..ce0addcc 100644 --- a/cdist/log.py +++ b/cdist/log.py @@ -23,6 +23,31 @@ import logging +# Define additional cdist logging levels. +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) + + +logging.verbose = _verbose + +logging.TRACE = logging.DEBUG - 5 +logging.addLevelName(logging.TRACE, 'TRACE') + + +def _trace(msg, *args, **kwargs): + logging.log(logging.TRACE, msg, *args, **kwargs) + + +logging.trace = _trace + + class Log(logging.Logger): def __init__(self, name): @@ -37,3 +62,13 @@ class Log(logging.Logger): record.msg = self.name + ": " + str(record.msg) return True + + def verbose(self, msg, *args, **kwargs): + self.log(logging.VERBOSE, msg, *args, **kwargs) + + def trace(self, msg, *args, **kwargs): + self.log(logging.TRACE, msg, *args, **kwargs) + + +logging.setLoggerClass(Log) +logging.basicConfig(format='%(levelname)s: %(message)s') diff --git a/cdist/util/ipaddr.py b/cdist/util/ipaddr.py index a747aeb5..b9d1ab30 100644 --- a/cdist/util/ipaddr.py +++ b/cdist/util/ipaddr.py @@ -45,7 +45,7 @@ def resolve_target_host_name(host): log.debug("derived host_name for host \"{}\": {}".format( host, host_name)) except (socket.gaierror, socket.herror) as e: - log.warn("Could not derive host_name for {}" + log.warning("Could not derive host_name for {}" ", $host_name will be empty. Error is: {}".format(host, e)) # in case of error provide empty value host_name = '' @@ -59,7 +59,7 @@ def resolve_target_fqdn(host): log.debug("derived host_fqdn for host \"{}\": {}".format( host, host_fqdn)) except socket.herror as e: - log.warn("Could not derive host_fqdn for {}" + log.warning("Could not derive host_fqdn for {}" ", $host_fqdn will be empty. Error is: {}".format(host, e)) # in case of error provide empty value host_fqdn = '' diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 3bddbd02..dbfda34f 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -50,12 +50,16 @@ All commands accept the following options: Set log level to debug (deprecated, use -vvv instead) +.. option:: -q, --quiet + + Quiet mode: disables logging, including WARNING and ERROR + .. option:: -v, --verbose Increase the verbosity level. Every instance of -v increments the verbosity - level by one. Its default value is 0. There are 4 levels of verbosity. The - order of levels from the lowest to the highest are: ERROR (0), WARNING (1), - INFO (2) and DEBUG (3 or higher). + level by one. Its default value is 0 which includes ERROR and WARNING levels. + The levels, in order from the lowest to the highest, are: + ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) TRACE (4 or higher). .. option:: -V, --version diff --git a/scripts/cdist b/scripts/cdist index 498091b8..9719e6ee 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -80,10 +80,7 @@ if __name__ == "__main__": import os import re import cdist - import cdist.log - logging.setLoggerClass(cdist.log.Log) - logging.basicConfig(format='%(levelname)s: %(message)s') log = logging.getLogger("cdist") if re.match("__", os.path.basename(sys.argv[0])): From 248656b81fe761626085daec7bafb0354cfca811 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Jun 2017 23:36:42 +0200 Subject: [PATCH 0525/1332] First iteration of logging cleanup. --- cdist/config.py | 24 ++++++++++++------------ cdist/core/explorer.py | 20 ++++++++++---------- cdist/core/manifest.py | 2 +- cdist/emulator.py | 6 +++--- cdist/exec/local.py | 18 +++++++++--------- cdist/exec/remote.py | 20 ++++++++++---------- cdist/shell.py | 4 ++-- scripts/cdist | 4 ++-- 8 files changed, 49 insertions(+), 49 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 19679a4c..f6b0cc20 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -144,7 +144,7 @@ class Config(object): hostcnt += 1 if args.parallel: - log.debug("Creating child process for %s", host) + log.trace("Creating child process for %s", host) process[host] = multiprocessing.Process( target=cls.onehost, args=(host, host_base_path, hostdir, args, True)) @@ -159,7 +159,7 @@ class Config(object): # Catch errors in parallel mode when joining if args.parallel: for host in process.keys(): - log.debug("Joining process %s", host) + log.trace("Joining process %s", host) process[host].join() if not process[host].exitcode == 0: @@ -300,7 +300,7 @@ class Config(object): return objects_changed def _iterate_once_sequential(self): - self.log.info("Iteration in sequential mode") + self.log.debug("Iteration in sequential mode") objects_changed = False for cdist_object in self.object_list(): @@ -327,7 +327,7 @@ class Config(object): return objects_changed def _iterate_once_parallel(self): - self.log.info("Iteration in parallel mode in {} jobs".format( + self.log.debug("Iteration in parallel mode in {} jobs".format( self.jobs)) objects_changed = False @@ -350,15 +350,15 @@ class Config(object): self.object_prepare(cargo[0]) objects_changed = True elif cargo: - self.log.debug("Multiprocessing start method is {}".format( + self.log.trace("Multiprocessing start method is {}".format( multiprocessing.get_start_method())) - self.log.debug(("Starting multiprocessing Pool for {} parallel " + self.log.trace(("Starting multiprocessing Pool for {} parallel " "objects preparation".format(n))) args = [ (c, ) for c in cargo ] mp_pool_run(self.object_prepare, args, jobs=self.jobs) - self.log.debug(("Multiprocessing for parallel object " + self.log.trace(("Multiprocessing for parallel object " "preparation finished")) objects_changed = True @@ -386,15 +386,15 @@ class Config(object): self.object_run(cargo[0]) objects_changed = True elif cargo: - self.log.debug("Multiprocessing start method is {}".format( + self.log.trace("Multiprocessing start method is {}".format( multiprocessing.get_start_method())) - self.log.debug(("Starting multiprocessing Pool for {} parallel " + self.log.trace(("Starting multiprocessing Pool for {} parallel " "object run".format(n))) args = [ (c, ) for c in cargo ] mp_pool_run(self.object_run, args, jobs=self.jobs) - self.log.debug(("Multiprocessing for parallel object " + self.log.trace(("Multiprocessing for parallel object " "run finished")) objects_changed = True @@ -473,7 +473,7 @@ class Config(object): def object_run(self, cdist_object): """Run gencode and code for an object""" - self.log.debug("Trying to run object %s" % (cdist_object.name)) + self.log.verbose("Trying to run object %s" % (cdist_object.name)) if cdist_object.state == core.CdistObject.STATE_DONE: raise cdist.Error(("Attempting to run an already finished " "object: %s"), cdist_object) @@ -500,5 +500,5 @@ class Config(object): self.log.info("Skipping code execution due to DRY RUN") # Mark this object as done - self.log.debug("Finishing run of " + cdist_object.name) + self.log.trace("Finishing run of " + cdist_object.name) cdist_object.state = core.CdistObject.STATE_DONE diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 45afc5c0..aea17d83 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -95,7 +95,7 @@ class Explorer(object): out_path directory. """ - self.log.info("Running global explorers") + self.log.trace("Running global explorers") self.transfer_global_explorers() if self.jobs is None: self._run_global_explorers_seq(out_path) @@ -109,22 +109,22 @@ class Explorer(object): fd.write(output) def _run_global_explorers_seq(self, out_path): - self.log.info("Running global explorers sequentially") + self.log.debug("Running global explorers sequentially") for explorer in self.list_global_explorer_names(): self._run_global_explorer(explorer, out_path) def _run_global_explorers_parallel(self, out_path): - self.log.info("Running global explorers in {} parallel jobs".format( + self.log.debug("Running global explorers in {} parallel jobs".format( self.jobs)) - self.log.debug("Multiprocessing start method is {}".format( + self.log.trace("Multiprocessing start method is {}".format( multiprocessing.get_start_method())) - self.log.debug(("Starting multiprocessing Pool for global " + self.log.trace(("Starting multiprocessing Pool for global " "explorers run")) args = [ (e, out_path, ) for e in self.list_global_explorer_names() ] mp_pool_run(self._run_global_explorer, args, jobs=self.jobs) - self.log.debug(("Multiprocessing run for global explorers " + self.log.trace(("Multiprocessing run for global explorers " "finished")) # logger is not pickable, so remove it when we pickle @@ -168,15 +168,15 @@ class Explorer(object): in the object. """ - self.log.debug("Transfering type explorers for type: %s", + self.log.trace("Transfering type explorers for type: %s", cdist_object.cdist_type) self.transfer_type_explorers(cdist_object.cdist_type) - self.log.debug("Transfering object parameters for object: %s", + self.log.trace("Transfering object parameters for object: %s", cdist_object.name) self.transfer_object_parameters(cdist_object) for explorer in self.list_type_explorer_names(cdist_object.cdist_type): output = self.run_type_explorer(explorer, cdist_object) - self.log.debug("Running type explorer '%s' for object '%s'", + self.log.trace("Running type explorer '%s' for object '%s'", explorer, cdist_object.name) cdist_object.explorers[explorer] = output @@ -203,7 +203,7 @@ class Explorer(object): remote side.""" if cdist_type.explorers: if cdist_type.name in self._type_explorers_transferred: - self.log.debug("Skipping retransfer of type explorers for: %s", + self.log.trace("Skipping retransfer of type explorers for: %s", cdist_type) else: source = os.path.join(self.local.type_path, diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 29f96c4f..cd0fde9c 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -145,7 +145,7 @@ class Manifest(object): else: user_supplied = True - self.log.info("Running initial manifest " + initial_manifest) + self.log.trace("Running initial manifest " + initial_manifest) if not os.path.isfile(initial_manifest): raise NoInitialManifestError(initial_manifest, user_supplied) diff --git a/cdist/emulator.py b/cdist/emulator.py index cdbe5b08..09813d64 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -98,7 +98,7 @@ class Emulator(object): self.save_stdin() self.record_requirements() self.record_auto_requirements() - self.log.debug("Finished %s %s" % ( + self.log.trace("Finished %s %s" % ( self.cdist_object.path, self.parameters)) def __init_log(self): @@ -148,7 +148,7 @@ class Emulator(object): # And finally parse/verify parameter self.args = parser.parse_args(self.argv[1:]) - self.log.debug('Args: %s' % self.args) + self.log.trace('Args: %s' % self.args) def setup_object(self): # Setup object - and ensure it is not in args @@ -240,7 +240,7 @@ class Emulator(object): self.object_source))) raise - self.log.debug("Recording requirement: %s", requirement) + self.log.trace("Recording requirement: %s", requirement) # Save the sanitised version, not the user supplied one # (__file//bar => __file/bar) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index fc2e7c09..be3cde4c 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -163,7 +163,7 @@ class Local(object): with open(self.object_marker_file, 'w') as fd: fd.write("%s\n" % self.object_marker_name) - self.log.debug("Object marker %s saved in %s" % ( + self.log.trace("Object marker %s saved in %s" % ( self.object_marker_name, self.object_marker_file)) def _init_cache_dir(self, cache_dir): @@ -178,12 +178,12 @@ class Local(object): def rmdir(self, path): """Remove directory on the local side.""" - self.log.debug("Local rmdir: %s", path) + self.log.trace("Local rmdir: %s", path) shutil.rmtree(path) def mkdir(self, path): """Create directory on the local side.""" - self.log.debug("Local mkdir: %s", path) + self.log.trace("Local mkdir: %s", path) os.makedirs(path, exist_ok=True) def run(self, command, env=None, return_output=False, message_prefix=None, @@ -192,7 +192,7 @@ class Local(object): Return the output as a string. """ - self.log.debug("Local run: %s", command) + self.log.trace("Local run: %s", command) assert isinstance(command, (list, tuple)), ( "list or tuple argument expected, got: %s" % command) @@ -214,9 +214,9 @@ class Local(object): try: if save_output: output, errout = exec_util.call_get_output(command, env=env) - self.log.debug("Local stdout: {}".format(output)) + self.log.trace("Local stdout: {}".format(output)) # Currently, stderr is not captured. - # self.log.debug("Local stderr: {}".format(errout)) + # self.log.trace("Local stderr: {}".format(errout)) if return_output: return output.decode() else: @@ -279,7 +279,7 @@ class Local(object): return cache_subpath def save_cache(self, start_time=time.time()): - self.log.debug("cache subpath pattern: {}".format( + self.log.trace("cache subpath pattern: {}".format( self.cache_path_pattern)) cache_subpath = self._cache_subpath(start_time, self.cache_path_pattern) @@ -340,7 +340,7 @@ class Local(object): if os.path.exists(dst): os.unlink(dst) - self.log.debug("Linking %s to %s ..." % (src, dst)) + self.log.trace("Linking %s to %s ..." % (src, dst)) try: os.symlink(src, dst) except OSError as e: @@ -352,7 +352,7 @@ class Local(object): src = os.path.abspath(self.exec_path) for cdist_type in core.CdistType.list_types(self.type_path): dst = os.path.join(self.bin_path, cdist_type.name) - self.log.debug("Linking emulator: %s to %s", src, dst) + self.log.trace("Linking emulator: %s to %s", src, dst) try: os.symlink(src, dst) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 042b7103..ff4ad30a 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -111,17 +111,17 @@ class Remote(object): def rmdir(self, path): """Remove directory on the remote side.""" - self.log.debug("Remote rmdir: %s", path) + self.log.trace("Remote rmdir: %s", path) self.run(["rm", "-rf", path]) def mkdir(self, path): """Create directory on the remote side.""" - self.log.debug("Remote mkdir: %s", path) + self.log.trace("Remote mkdir: %s", path) self.run(["mkdir", "-p", path]) def transfer(self, source, destination, jobs=None): """Transfer a file or directory to the remote side.""" - self.log.debug("Remote transfer: %s -> %s", source, destination) + self.log.trace("Remote transfer: %s -> %s", source, destination) self.rmdir(destination) if os.path.isdir(source): self.mkdir(destination) @@ -147,11 +147,11 @@ class Remote(object): def _transfer_dir_parallel(self, source, destination, jobs): """Transfer a directory to the remote side in parallel mode.""" - self.log.info("Remote transfer in {} parallel jobs".format( + self.log.debug("Remote transfer in {} parallel jobs".format( jobs)) - self.log.debug("Multiprocessing start method is {}".format( + self.log.trace("Multiprocessing start method is {}".format( multiprocessing.get_start_method())) - self.log.debug(("Starting multiprocessing Pool for parallel " + self.log.trace(("Starting multiprocessing Pool for parallel " "remote transfer")) args = [] for f in glob.glob1(source, '*'): @@ -161,7 +161,7 @@ class Remote(object): _wrap_addr(self.target_host[0]), destination)]) args.append((command, )) mp_pool_run(self._run_command, args, jobs=jobs) - self.log.debug(("Multiprocessing for parallel transfer " + self.log.trace(("Multiprocessing for parallel transfer " "finished")) def run_script(self, script, env=None, return_output=False): @@ -226,12 +226,12 @@ class Remote(object): os_environ['__target_hostname'] = self.target_host[1] os_environ['__target_fqdn'] = self.target_host[2] - self.log.debug("Remote run: %s", command) + self.log.trace("Remote run: %s", command) try: output, errout = exec_util.call_get_output(command, env=os_environ) - self.log.debug("Remote stdout: {}".format(output)) + self.log.trace("Remote stdout: {}".format(output)) # Currently, stderr is not captured. - # self.log.debug("Remote stderr: {}".format(errout)) + # self.log.trace("Remote stderr: {}".format(errout)) if return_output: return output.decode() except subprocess.CalledProcessError as e: diff --git a/cdist/shell.py b/cdist/shell.py index 9378efc3..662f8f7d 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -86,10 +86,10 @@ class Shell(object): self._init_files_dirs() self._init_environment() - log.info("Starting shell...") + log.trace("Starting shell...") # save_output=False -> do not catch stdout and stderr self.local.run([self.shell], self.env, save_output=False) - log.info("Finished shell.") + log.trace("Finished shell.") @classmethod def commandline(cls, args): diff --git a/scripts/cdist b/scripts/cdist index 9719e6ee..492bbec6 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -44,8 +44,8 @@ def commandline(): if retval: log.warning(retval) - log.debug(args) - log.info("version %s" % cdist.VERSION) + log.trace(args) + log.verbose("version %s" % cdist.VERSION) # Work around python 3.3 bug: # http://bugs.python.org/issue16308 From 127c05a882e79c50822ff4ad1226d8ca532b047d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Jun 2017 23:43:39 +0200 Subject: [PATCH 0526/1332] 2nd iteration of logging cleanup. --- cdist/core/explorer.py | 2 +- cdist/core/manifest.py | 2 +- cdist/emulator.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index aea17d83..f2f1f15b 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -95,7 +95,7 @@ class Explorer(object): out_path directory. """ - self.log.trace("Running global explorers") + self.log.info("Running global explorers") self.transfer_global_explorers() if self.jobs is None: self._run_global_explorers_seq(out_path) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index cd0fde9c..29f96c4f 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -145,7 +145,7 @@ class Manifest(object): else: user_supplied = True - self.log.trace("Running initial manifest " + initial_manifest) + self.log.info("Running initial manifest " + initial_manifest) if not os.path.isfile(initial_manifest): raise NoInitialManifestError(initial_manifest, user_supplied) diff --git a/cdist/emulator.py b/cdist/emulator.py index 09813d64..78d75b26 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -240,7 +240,7 @@ class Emulator(object): self.object_source))) raise - self.log.trace("Recording requirement: %s", requirement) + self.log.debug("Recording requirement: %s", requirement) # Save the sanitised version, not the user supplied one # (__file//bar => __file/bar) From a722f3c63486d1f3ed4f93727f935a3b8dab3731 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 29 Jun 2017 09:22:59 +0200 Subject: [PATCH 0527/1332] 3rd iteration of logging cleanup. --- cdist/config.py | 8 +++++++- cdist/core/cdist_object.py | 3 --- cdist/core/cdist_type.py | 1 - cdist/core/code.py | 3 --- cdist/core/explorer.py | 2 ++ cdist/core/manifest.py | 4 ++-- cdist/emulator.py | 4 ++-- cdist/exec/local.py | 2 +- scripts/cdist | 2 +- 9 files changed, 15 insertions(+), 14 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index f6b0cc20..4109fa85 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -464,6 +464,7 @@ class Config(object): def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" + self.log.info("Preparing object {}".format(cdist_object.name)) self.log.info( "Running manifest and explorers for " + cdist_object.name) self.explorer.run_type_explorers(cdist_object) @@ -473,6 +474,7 @@ class Config(object): def object_run(self, cdist_object): """Run gencode and code for an object""" + self.log.info("Running object " + cdist_object.name) self.log.verbose("Trying to run object %s" % (cdist_object.name)) if cdist_object.state == core.CdistObject.STATE_DONE: raise cdist.Error(("Attempting to run an already finished " @@ -481,7 +483,7 @@ class Config(object): cdist_type = cdist_object.cdist_type # Generate - self.log.info("Generating code for %s" % (cdist_object.name)) + self.log.debug("Generating code for %s" % (cdist_object.name)) cdist_object.code_local = self.code.run_gencode_local(cdist_object) cdist_object.code_remote = self.code.run_gencode_remote(cdist_object) if cdist_object.code_local or cdist_object.code_remote: @@ -492,8 +494,12 @@ class Config(object): if cdist_object.code_local or cdist_object.code_remote: self.log.info("Executing code for %s" % (cdist_object.name)) if cdist_object.code_local: + self.log.trace("Executing local code for %s" + % (cdist_object.name)) self.code.run_code_local(cdist_object) if cdist_object.code_remote: + self.log.trace("Executing remote code for %s" + % (cdist_object.name)) self.code.transfer_code_remote(cdist_object) self.code.run_code_remote(cdist_object) else: diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 262db8bf..410dfafc 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -22,7 +22,6 @@ # import fnmatch -import logging import os import collections @@ -30,8 +29,6 @@ import cdist import cdist.core from cdist.util import fsproperty -log = logging.getLogger(__name__) - class IllegalObjectIdError(cdist.Error): def __init__(self, object_id, message=None): diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 14865386..339d5995 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -21,7 +21,6 @@ # import os - import cdist diff --git a/cdist/core/code.py b/cdist/core/code.py index e9e2edf0..6917e7ba 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -21,13 +21,10 @@ # # -import logging import os import cdist -log = logging.getLogger(__name__) - ''' common: diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index f2f1f15b..b5c00897 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -168,6 +168,8 @@ class Explorer(object): in the object. """ + self.log.info("Running type explorers for {}".format( + cdist_object.cdist_type)) self.log.trace("Transfering type explorers for type: %s", cdist_object.cdist_type) self.transfer_type_explorers(cdist_object.cdist_type) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 29f96c4f..16c08353 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -145,12 +145,11 @@ class Manifest(object): else: user_supplied = True - self.log.info("Running initial manifest " + initial_manifest) - if not os.path.isfile(initial_manifest): raise NoInitialManifestError(initial_manifest, user_supplied) message_prefix = "initialmanifest" + self.log.info("Running initial manifest " + initial_manifest) self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest), message_prefix=message_prefix, @@ -177,6 +176,7 @@ class Manifest(object): cdist_object.cdist_type.manifest_path) message_prefix = cdist_object.name if os.path.isfile(type_manifest): + self.log.info("Running type manifest " + type_manifest) self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object), message_prefix=message_prefix, diff --git a/cdist/emulator.py b/cdist/emulator.py index 78d75b26..7c9dfcca 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -256,10 +256,10 @@ class Emulator(object): # (this would leed to an circular dependency) if ("CDIST_ORDER_DEPENDENCY" in self.env and 'CDIST_OVERRIDE' not in self.env): - # load object name created bevor this one from typeorder file ... + # load object name created befor this one from typeorder file ... with open(self.typeorder_path, 'r') as typecreationfile: typecreationorder = typecreationfile.readlines() - # get the type created bevore this one ... + # get the type created before this one ... try: lastcreatedtype = typecreationorder[-2].strip() if 'require' in self.env: diff --git a/cdist/exec/local.py b/cdist/exec/local.py index be3cde4c..2ff31466 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -192,7 +192,6 @@ class Local(object): Return the output as a string. """ - self.log.trace("Local run: %s", command) assert isinstance(command, (list, tuple)), ( "list or tuple argument expected, got: %s" % command) @@ -211,6 +210,7 @@ class Local(object): message = cdist.message.Message(message_prefix, self.messages_path) env.update(message.env) + self.log.trace("Local run: %s", command) try: if save_output: output, errout = exec_util.call_get_output(command, env=env) diff --git a/scripts/cdist b/scripts/cdist index 492bbec6..605c5a6c 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -45,7 +45,7 @@ def commandline(): log.warning(retval) log.trace(args) - log.verbose("version %s" % cdist.VERSION) + log.info("version %s" % cdist.VERSION) # Work around python 3.3 bug: # http://bugs.python.org/issue16308 From a37d286d6759aeb8d58943da97d28e5eb5da7701 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 29 Jun 2017 10:18:46 +0200 Subject: [PATCH 0528/1332] Suppress subprocess script output in quiet mode. --- cdist/config.py | 6 ++++-- cdist/exec/local.py | 18 +++++++++++++++--- cdist/exec/remote.py | 11 +++++++++-- cdist/exec/util.py | 8 ++++---- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 4109fa85..b17ec67f 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -220,13 +220,15 @@ class Config(object): host_dir_name=host_dir_name, initial_manifest=args.manifest, add_conf_dirs=args.conf_dir, - cache_path_pattern=args.cache_path_pattern) + cache_path_pattern=args.cache_path_pattern, + quiet_mode=args.quiet) remote = cdist.exec.remote.Remote( target_host=target_host, remote_exec=remote_exec, remote_copy=remote_copy, - base_path=args.remote_out_path) + base_path=args.remote_out_path, + quiet_mode=args.quiet) c = cls(local, remote, dry_run=args.dry_run, jobs=args.jobs) c.run() diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 2ff31466..06127660 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -54,7 +54,8 @@ class Local(object): exec_path=sys.argv[0], initial_manifest=None, add_conf_dirs=None, - cache_path_pattern=None): + cache_path_pattern=None, + quiet_mode=False): self.target_host = target_host self.hostdir = host_dir_name @@ -64,6 +65,7 @@ class Local(object): self.custom_initial_manifest = initial_manifest self._add_conf_dirs = add_conf_dirs self.cache_path_pattern = cache_path_pattern + self.quiet_mode = quiet_mode self._init_log() self._init_permissions() @@ -212,8 +214,13 @@ class Local(object): self.log.trace("Local run: %s", command) try: + if self.quiet_mode: + stderr = subprocess.DEVNULL + else: + stderr = None if save_output: - output, errout = exec_util.call_get_output(command, env=env) + output, errout = exec_util.call_get_output( + command, env=env, stderr=stderr) self.log.trace("Local stdout: {}".format(output)) # Currently, stderr is not captured. # self.log.trace("Local stderr: {}".format(errout)) @@ -223,7 +230,12 @@ class Local(object): # In some cases no output is saved. # This is used for shell command, stdout and stderr # must not be catched. - subprocess.check_call(command, env=env) + if self.quiet_mode: + stdout = subprocess.DEVNULL + else: + stdout = None + subprocess.check_call(command, env=env, stderr=stderr, + stdout=stdout) except subprocess.CalledProcessError as e: exec_util.handle_called_process_error(e, command) except OSError as error: diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index ff4ad30a..2a27bae4 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -62,7 +62,8 @@ class Remote(object): target_host, remote_exec, remote_copy, - base_path=None): + base_path=None, + quiet_mode=None): self.target_host = target_host self._exec = remote_exec self._copy = remote_copy @@ -71,6 +72,7 @@ class Remote(object): self.base_path = base_path else: self.base_path = "/var/lib/cdist" + self.quiet_mode = quiet_mode self.conf_path = os.path.join(self.base_path, "conf") self.object_path = os.path.join(self.base_path, "object") @@ -228,7 +230,12 @@ class Remote(object): self.log.trace("Remote run: %s", command) try: - output, errout = exec_util.call_get_output(command, env=os_environ) + if self.quiet_mode: + stderr = subprocess.DEVNULL + else: + stderr = None + output, errout = exec_util.call_get_output( + command, env=os_environ, stderr=stderr) self.log.trace("Remote stdout: {}".format(output)) # Currently, stderr is not captured. # self.log.trace("Remote stderr: {}".format(errout)) diff --git a/cdist/exec/util.py b/cdist/exec/util.py index 864a73a3..9ed7103b 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -116,14 +116,14 @@ import cdist # return (result.stdout, result.stderr) -def call_get_output(command, env=None): +def call_get_output(command, env=None, stderr=None): """Run the given command with the given environment. Return the tuple of stdout and stderr output as a byte strings. """ assert isinstance(command, (list, tuple)), ( "list or tuple argument expected, got: {}".format(command)) - return (_call_get_stdout(command, env), None) + return (_call_get_stdout(command, env, stderr), None) def handle_called_process_error(err, command): @@ -140,7 +140,7 @@ def handle_called_process_error(err, command): err.returncode, err.output)) -def _call_get_stdout(command, env=None): +def _call_get_stdout(command, env=None, stderr=None): """Run the given command with the given environment. Return the stdout output as a byte string, stderr is ignored. """ @@ -148,7 +148,7 @@ def _call_get_stdout(command, env=None): "list or tuple argument expected, got: {}".format(command)) with TemporaryFile() as fout: - subprocess.check_call(command, env=env, stdout=fout) + subprocess.check_call(command, env=env, stdout=fout, stderr=stderr) fout.seek(0) output = fout.read() From 015861e63bc7d0a9ad9b246d14d8fa35dd9c9abf Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 29 Jun 2017 14:46:35 +0200 Subject: [PATCH 0529/1332] pep8 --- cdist/exec/local.py | 3 ++- cdist/util/ipaddr.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 06127660..6c285204 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -297,7 +297,8 @@ class Local(object): self.cache_path_pattern) self.log.debug("cache subpath: {}".format(cache_subpath)) destination = os.path.join(self.cache_path, cache_subpath) - self.log.debug("Saving " + self.base_path + " to " + destination) + self.log.trace(("Saving cache: " + self.base_path + " to " + + destination)) if not os.path.exists(destination): shutil.move(self.base_path, destination) diff --git a/cdist/util/ipaddr.py b/cdist/util/ipaddr.py index b9d1ab30..0bcb0a83 100644 --- a/cdist/util/ipaddr.py +++ b/cdist/util/ipaddr.py @@ -46,7 +46,7 @@ def resolve_target_host_name(host): host, host_name)) except (socket.gaierror, socket.herror) as e: log.warning("Could not derive host_name for {}" - ", $host_name will be empty. Error is: {}".format(host, e)) + ", $host_name will be empty. Error is: {}".format(host, e)) # in case of error provide empty value host_name = '' return host_name @@ -60,7 +60,7 @@ def resolve_target_fqdn(host): host, host_fqdn)) except socket.herror as e: log.warning("Could not derive host_fqdn for {}" - ", $host_fqdn will be empty. Error is: {}".format(host, e)) + ", $host_fqdn will be empty. Error is: {}".format(host, e)) # in case of error provide empty value host_fqdn = '' return host_fqdn From cef1d215b265ff4f9cba1406d6ad08062387c02c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 30 Jun 2017 09:08:22 +0200 Subject: [PATCH 0530/1332] Finally remove deprecated -d/--debug option. --- cdist/argparse.py | 13 ------------- docs/src/man1/cdist.rst | 18 +++++++----------- scripts/cdist | 6 ++---- 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 8689be79..8208d1f0 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -18,7 +18,6 @@ parser = None _verbosity_level_off = -2 -_verbosity_level_debug = 3 _verbosity_level = { _verbosity_level_off: logging.OFF, -1: logging.ERROR, @@ -86,10 +85,6 @@ def get_parsers(): parser = {} # Options _all_ parsers have in common parser['loglevel'] = argparse.ArgumentParser(add_help=False) - parser['loglevel'].add_argument( - '-d', '--debug', - help=('Set log level to debug (deprecated, use -vvv instead)'), - action='store_true', default=False) parser['loglevel'].add_argument( '-q', '--quiet', help='Quiet mode: disables logging, including WARNING and ERROR', @@ -223,15 +218,7 @@ def get_parsers(): def handle_loglevel(args): - if args.debug: - retval = "-d/--debug is deprecated, use -vvv instead" - args.verbose = _verbosity_level_debug - else: - retval = None - if args.quiet: args.verbose = _verbosity_level_off logging.root.setLevel(_verbosity_level[args.verbose]) - - return retval diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index dbfda34f..edcad828 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -11,23 +11,23 @@ SYNOPSIS :: - cdist [-h] [-d] [-v] [-V] {banner,config,shell,install} ... + cdist [-h] [-v] [-V] {banner,config,shell,install} ... - cdist banner [-h] [-d] [-v] + cdist banner [-h] [-v] - cdist config [-h] [-d] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] + cdist config [-h] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] [host [host ...]] - cdist install [-h] [-d] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] + cdist install [-h] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] [host [host ...]] - cdist shell [-h] [-d] [-v] [-s SHELL] + cdist shell [-h] [-v] [-s SHELL] DESCRIPTION @@ -46,10 +46,6 @@ All commands accept the following options: Show the help screen -.. option:: -d, --debug - - Set log level to debug (deprecated, use -vvv instead) - .. option:: -q, --quiet Quiet mode: disables logging, including WARNING and ERROR @@ -211,7 +207,7 @@ EXAMPLES .. code-block:: sh # Configure ikq05.ethz.ch with debug enabled - % cdist config -d ikq05.ethz.ch + % cdist config -vvv ikq05.ethz.ch # Configure hosts in parallel and use a different configuration directory % cdist config -c ~/p/cdist-nutzung \ @@ -245,7 +241,7 @@ EXAMPLES [--group GROUP] [--owner OWNER] [--mode MODE] object_id # Install ikq05.ethz.ch with debug enabled - % cdist install -d ikq05.ethz.ch + % cdist install -vvv ikq05.ethz.ch ENVIRONMENT ----------- diff --git a/scripts/cdist b/scripts/cdist index 605c5a6c..b55091f9 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -40,12 +40,10 @@ def commandline(): args = parser['main'].parse_args(sys.argv[1:]) # Loglevels are handled globally in here - retval = cdist.argparse.handle_loglevel(args) - if retval: - log.warning(retval) + cdist.argparse.handle_loglevel(args) - log.trace(args) log.info("version %s" % cdist.VERSION) + log.trace(args) # Work around python 3.3 bug: # http://bugs.python.org/issue16308 From f6e1174adb16d89af78f2dbfbafd1c1eda167c67 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 3 Jul 2017 13:32:39 +0200 Subject: [PATCH 0531/1332] start moving info log messages to verbose Signed-off-by: Steven Armstrong --- cdist/config.py | 13 ++++++------- cdist/core/explorer.py | 4 ++-- cdist/core/manifest.py | 4 ++-- scripts/cdist | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index b17ec67f..d0478c8c 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -166,7 +166,7 @@ class Config(object): failed_hosts.append(host) time_end = time.time() - log.info("Total processing time for %s host(s): %s", hostcnt, + log.verbose("Total processing time for %s host(s): %s", hostcnt, (time_end - time_start)) if len(failed_hosts) > 0: @@ -466,8 +466,8 @@ class Config(object): def object_prepare(self, cdist_object): """Prepare object: Run type explorer + manifest""" - self.log.info("Preparing object {}".format(cdist_object.name)) - self.log.info( + self.log.verbose("Preparing object {}".format(cdist_object.name)) + self.log.verbose( "Running manifest and explorers for " + cdist_object.name) self.explorer.run_type_explorers(cdist_object) self.manifest.run_type_manifest(cdist_object) @@ -476,8 +476,7 @@ class Config(object): def object_run(self, cdist_object): """Run gencode and code for an object""" - self.log.info("Running object " + cdist_object.name) - self.log.verbose("Trying to run object %s" % (cdist_object.name)) + self.log.verbose("Running object " + cdist_object.name) if cdist_object.state == core.CdistObject.STATE_DONE: raise cdist.Error(("Attempting to run an already finished " "object: %s"), cdist_object) @@ -494,7 +493,7 @@ class Config(object): # Execute if not self.dry_run: if cdist_object.code_local or cdist_object.code_remote: - self.log.info("Executing code for %s" % (cdist_object.name)) + self.log.info("Updating %s" % (cdist_object.name)) if cdist_object.code_local: self.log.trace("Executing local code for %s" % (cdist_object.name)) @@ -505,7 +504,7 @@ class Config(object): self.code.transfer_code_remote(cdist_object) self.code.run_code_remote(cdist_object) else: - self.log.info("Skipping code execution due to DRY RUN") + self.log.verbose("Skipping code execution due to DRY RUN") # Mark this object as done self.log.trace("Finishing run of " + cdist_object.name) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index b5c00897..0d47e45e 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -95,7 +95,7 @@ class Explorer(object): out_path directory. """ - self.log.info("Running global explorers") + self.log.verbose("Running global explorers") self.transfer_global_explorers() if self.jobs is None: self._run_global_explorers_seq(out_path) @@ -168,7 +168,7 @@ class Explorer(object): in the object. """ - self.log.info("Running type explorers for {}".format( + self.log.verbose("Running type explorers for {}".format( cdist_object.cdist_type)) self.log.trace("Transfering type explorers for type: %s", cdist_object.cdist_type) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 16c08353..d8570097 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -149,7 +149,7 @@ class Manifest(object): raise NoInitialManifestError(initial_manifest, user_supplied) message_prefix = "initialmanifest" - self.log.info("Running initial manifest " + initial_manifest) + self.log.verbose("Running initial manifest " + initial_manifest) self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest), message_prefix=message_prefix, @@ -176,7 +176,7 @@ class Manifest(object): cdist_object.cdist_type.manifest_path) message_prefix = cdist_object.name if os.path.isfile(type_manifest): - self.log.info("Running type manifest " + type_manifest) + self.log.verbose("Running type manifest " + type_manifest) self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object), message_prefix=message_prefix, diff --git a/scripts/cdist b/scripts/cdist index b55091f9..81220ca3 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -42,7 +42,7 @@ def commandline(): # Loglevels are handled globally in here cdist.argparse.handle_loglevel(args) - log.info("version %s" % cdist.VERSION) + log.verbose("version %s" % cdist.VERSION) log.trace(args) # Work around python 3.3 bug: From a1d73f72811c9675952d070b5c84e969a698a3c9 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Jul 2017 16:46:27 +0200 Subject: [PATCH 0532/1332] log changing object as Processing instead of Updating Signed-off-by: Steven Armstrong --- cdist/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index d0478c8c..0d847dea 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -493,7 +493,7 @@ class Config(object): # Execute if not self.dry_run: if cdist_object.code_local or cdist_object.code_remote: - self.log.info("Updating %s" % (cdist_object.name)) + self.log.info("Processing %s" % (cdist_object.name)) if cdist_object.code_local: self.log.trace("Executing local code for %s" % (cdist_object.name)) From 9fe242054709e2de7e149a56a1813577d4c23db8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 5 Jul 2017 16:40:02 +0200 Subject: [PATCH 0533/1332] also log start of config run Signed-off-by: Steven Armstrong --- cdist/config.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 0d847dea..eee47d03 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -269,6 +269,8 @@ class Config(object): """Do what is most often done: deploy & cleanup""" start_time = time.time() + self.log.info("Starting configuration run") + self._init_files_dirs() self.explorer.run_global_explorers(self.local.global_explorer_out_path) @@ -276,8 +278,8 @@ class Config(object): self.iterate_until_finished() self.local.save_cache(start_time) - self.log.info("Finished successful run in %s seconds", - time.time() - start_time) + self.log.info("Finished successful run in {:.2f} seconds".format( + time.time() - start_time)) def object_list(self): """Short name for object list retrieval""" From 93ab184e3af6e44600d043b5bbd1220c713042d0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 6 Jul 2017 07:34:08 +0200 Subject: [PATCH 0534/1332] Update changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 976fa600..72ae5737 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,8 @@ next: * Core: Allow manifest and gencode scripts to be written in any language (Darko Poljak) * Documentation: Improvements to the english and fix typos (Mesar Hameed) * Core: Merge -C custom cache path pattern option from beta branch (Darko Poljak) + * Core: Improve and cleanup logging (Darko Poljak, Steven Armstrong) + * Core: Remove deprecated -d option (Darko Poljak) 4.4.4: 2017-06-16 * Core: Support -j parallelization for object prepare and object run (Darko Poljak) From 9c914308f6f1376d5f11ae3875bb2be173d546c5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 6 Jul 2017 12:43:17 +0200 Subject: [PATCH 0535/1332] Fix ssh connection multiplexing race condition #542 Increase ControlPersist to 2h. After host run run ssh mux master exit command. If custom remote exec/copy is specified then do nothing. --- cdist/__init__.py | 2 +- cdist/config.py | 37 +++++++++++++++++++++++++++++++++---- cdist/util/remoteutil.py | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index b0fd75ea..31e59794 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -20,7 +20,6 @@ # import os -import subprocess import hashlib import cdist.version @@ -44,6 +43,7 @@ BANNER = """ REMOTE_COPY = "scp -o User=root" REMOTE_EXEC = "ssh -o User=root" +REMOTE_CMDS_CLEANUP_PATTERN = "ssh -o User=root -O exit -S {}" class Error(Exception): diff --git a/cdist/config.py b/cdist/config.py index 19679a4c..bd9d7bf8 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -47,13 +47,15 @@ from cdist.util.remoteutil import inspect_ssh_mux_opts class Config(object): """Cdist main class to hold arbitrary data""" - def __init__(self, local, remote, dry_run=False, jobs=None): + def __init__(self, local, remote, dry_run=False, jobs=None, + cleanup_cmds=[]): self.local = local self.remote = remote self._open_logger() self.dry_run = dry_run self.jobs = jobs + self.cleanup_cmds = cleanup_cmds self.explorer = core.Explorer(self.local.target_host, self.local, self.remote, jobs=self.jobs) @@ -91,6 +93,11 @@ class Config(object): args.remote_exec_pattern = cdist.REMOTE_EXEC + mux_opts if args_dict['remote_copy'] is None: args.remote_copy_pattern = cdist.REMOTE_COPY + mux_opts + if mux_opts: + cleanup_pattern = cdist.REMOTE_CMDS_CLEANUP_PATTERN + else: + cleanup_pattern = "" + args.remote_cmds_cleanup_pattern = cleanup_pattern @classmethod def _check_and_prepare_args(cls, args): @@ -196,7 +203,12 @@ class Config(object): remote_copy = args.remote_copy_pattern.format(control_path) else: remote_copy = args.remote_copy - return (remote_exec, remote_copy, ) + if args.remote_cmds_cleanup_pattern: + remote_cmds_cleanup = args.remote_cmds_cleanup_pattern.format( + control_path) + else: + remote_cmds_cleanup = "" + return (remote_exec, remote_copy, remote_cmds_cleanup, ) @classmethod def onehost(cls, host, host_base_path, host_dir_name, args, parallel): @@ -205,7 +217,8 @@ class Config(object): log = logging.getLogger(host) try: - remote_exec, remote_copy = cls._resolve_remote_cmds(args) + remote_exec, remote_copy, cleanup_cmd = cls._resolve_remote_cmds( + args) log.debug("remote_exec for host \"{}\": {}".format( host, remote_exec)) log.debug("remote_copy for host \"{}\": {}".format( @@ -228,7 +241,11 @@ class Config(object): remote_copy=remote_copy, base_path=args.remote_out_path) - c = cls(local, remote, dry_run=args.dry_run, jobs=args.jobs) + cleanup_cmds = [] + if cleanup_cmd: + cleanup_cmds.append(cleanup_cmd) + c = cls(local, remote, dry_run=args.dry_run, jobs=args.jobs, + cleanup_cmds=cleanup_cmds) c.run() except cdist.Error as e: @@ -272,11 +289,23 @@ class Config(object): self.explorer.run_global_explorers(self.local.global_explorer_out_path) self.manifest.run_initial_manifest(self.local.initial_manifest) self.iterate_until_finished() + self.cleanup() self.local.save_cache(start_time) self.log.info("Finished successful run in %s seconds", time.time() - start_time) + def cleanup(self): + self.log.debug("Running cleanup commands") + for cleanup_cmd in self.cleanup_cmds: + cmd = cleanup_cmd.split() + cmd.append(self.local.target_host[0]) + try: + self.local.run(cmd, return_output=False, save_output=False) + except cdist.Error as e: + # Log warning but continue. + self.log.warning("Cleanup command failed: %s", e) + def object_list(self): """Short name for object list retrieval""" for cdist_object in core.CdistObject.list_objects( diff --git a/cdist/util/remoteutil.py b/cdist/util/remoteutil.py index 2bd12fdf..505c4598 100644 --- a/cdist/util/remoteutil.py +++ b/cdist/util/remoteutil.py @@ -36,7 +36,7 @@ def inspect_ssh_mux_opts(): wanted_mux_opts = { "ControlPath": "{}", "ControlMaster": "auto", - "ControlPersist": "10", + "ControlPersist": "2h", } mux_opts = " ".join([" -o {}={}".format( x, wanted_mux_opts[x]) for x in wanted_mux_opts]) From 80c3dd7572329b4352b5637767b9d1786ce41011 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 6 Jul 2017 13:30:57 +0200 Subject: [PATCH 0536/1332] Ignore directory entries that begin with dot('.'). --- cdist/core/__init__.py | 1 + cdist/core/cdist_object.py | 2 +- cdist/core/cdist_type.py | 9 +++++---- cdist/core/util.py | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 cdist/core/util.py diff --git a/cdist/core/__init__.py b/cdist/core/__init__.py index 41e00a3a..8c384b3c 100644 --- a/cdist/core/__init__.py +++ b/cdist/core/__init__.py @@ -27,3 +27,4 @@ from cdist.core.cdist_object import IllegalObjectIdError from cdist.core.explorer import Explorer from cdist.core.manifest import Manifest from cdist.core.code import Code +from cdist.core.util import listdir diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 262db8bf..3167792b 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -107,7 +107,7 @@ class CdistObject(object): @classmethod def list_type_names(cls, object_base_path): """Return a list of type names""" - return os.listdir(object_base_path) + return cdist.core.listdir(object_base_path) @staticmethod def split_name(object_name): diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 14865386..9e2446f4 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -23,6 +23,7 @@ import os import cdist +import cdist.core class NoSuchTypeError(cdist.Error): @@ -75,7 +76,7 @@ class CdistType(object): @classmethod def list_type_names(cls, base_path): """Return a list of type names""" - return os.listdir(base_path) + return cdist.core.listdir(base_path) _instances = {} @@ -117,8 +118,8 @@ class CdistType(object): """Return a list of available explorers""" if not self.__explorers: try: - self.__explorers = os.listdir(os.path.join(self.absolute_path, - "explorer")) + self.__explorers = cdist.core.listdir( + os.path.join(self.absolute_path, "explorer")) except EnvironmentError: # error ignored self.__explorers = [] @@ -222,7 +223,7 @@ class CdistType(object): defaults_dir = os.path.join(self.absolute_path, "parameter", "default") - for name in os.listdir(defaults_dir): + for name in cdist.core.listdir(defaults_dir): try: with open(os.path.join(defaults_dir, name)) as fd: defaults[name] = fd.read().strip() diff --git a/cdist/core/util.py b/cdist/core/util.py new file mode 100644 index 00000000..a8216ef9 --- /dev/null +++ b/cdist/core/util.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# +# 2017 Darko Poljak (darko.poljak 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 . +# +# + +import os + + +def listdir(path='.', include_dot=False): + """os.listdir but do not include entries whose names begin with a dot('.') + if include_dot is False. + """ + return [x for x in os.listdir(path) if include_dot or not _ishidden(x)] + + +def _ishidden(path): + return path[0] in ('.', b'.'[0]) From f9b632eebb90658a92b84420ef1b388d266c3151 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 6 Jul 2017 17:22:25 +0200 Subject: [PATCH 0537/1332] Improve listdir. --- cdist/core/util.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cdist/core/util.py b/cdist/core/util.py index a8216ef9..ca48c4c8 100644 --- a/cdist/core/util.py +++ b/cdist/core/util.py @@ -26,7 +26,10 @@ def listdir(path='.', include_dot=False): """os.listdir but do not include entries whose names begin with a dot('.') if include_dot is False. """ - return [x for x in os.listdir(path) if include_dot or not _ishidden(x)] + if include_dot: + return os.listdir(path) + else: + return [x for x in os.listdir(path) if not _ishidden(x)] def _ishidden(path): From 1f12faecca35ef783ef21f6672fc58da51002657 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 6 Jul 2017 22:58:58 +0200 Subject: [PATCH 0538/1332] Update changelog --- docs/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 72ae5737..77cc23fe 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,11 +9,12 @@ next: * Core: Merge -C custom cache path pattern option from beta branch (Darko Poljak) * Core: Improve and cleanup logging (Darko Poljak, Steven Armstrong) * Core: Remove deprecated -d option (Darko Poljak) + * Type __file: If no --source then create only if there is no file (Ander Punnar) 4.4.4: 2017-06-16 * Core: Support -j parallelization for object prepare and object run (Darko Poljak) * Type __install_mkfs: mkfs.vfat does not support -q (Nico Schottelius) - * Types __go_get, __daemontools*, __prometheus*: Fix missing dependencies, fix arguments(Kamila Součková) + * Types __go_get, __daemontools*, __prometheus*: Fix missing dependencies, fix arguments (Kamila Součková) 4.4.3: 2017-06-13 * Type __golang_from_vendor: Install golang from https://golang.org/dl/ (Kamila Součková) From d9a358bdf365056dc5302bf086943716574ff168 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 7 Jul 2017 02:10:06 +0200 Subject: [PATCH 0539/1332] add forgotten symlink Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_chroot_mount/gencode-local | 1 + 1 file changed, 1 insertion(+) create mode 120000 cdist/conf/type/__install_chroot_mount/gencode-local diff --git a/cdist/conf/type/__install_chroot_mount/gencode-local b/cdist/conf/type/__install_chroot_mount/gencode-local new file mode 120000 index 00000000..68dcbd6a --- /dev/null +++ b/cdist/conf/type/__install_chroot_mount/gencode-local @@ -0,0 +1 @@ +../__chroot_mount/gencode-local \ No newline at end of file From 4e27c863ef11b651ec3157c8e4b893b338437d6c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 14 Jul 2017 14:50:39 +0200 Subject: [PATCH 0540/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 77cc23fe..d778993f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Core: Improve and cleanup logging (Darko Poljak, Steven Armstrong) * Core: Remove deprecated -d option (Darko Poljak) * Type __file: If no --source then create only if there is no file (Ander Punnar) + * Core: Ignore directory entries that begin with dot('.') (Darko Poljak) 4.4.4: 2017-06-16 * Core: Support -j parallelization for object prepare and object run (Darko Poljak) From 31899b22639d09164d5bdb15693e214415e18909 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 15 Jul 2017 22:16:25 +0200 Subject: [PATCH 0541/1332] Add missing shebangs. --- cdist/conf/type/__golang_from_vendor/manifest | 2 ++ cdist/conf/type/__grafana_dashboard/manifest | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cdist/conf/type/__golang_from_vendor/manifest b/cdist/conf/type/__golang_from_vendor/manifest index 9d320830..cf164524 100755 --- a/cdist/conf/type/__golang_from_vendor/manifest +++ b/cdist/conf/type/__golang_from_vendor/manifest @@ -1 +1,3 @@ +#!/bin/sh -e + __line go_in_path --line 'export PATH=/usr/local/go/bin:$PATH' --file /etc/profile diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest index b6e3020e..898770dd 100755 --- a/cdist/conf/type/__grafana_dashboard/manifest +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -1,3 +1,5 @@ +#!/bin/sh -e + os=$(cat $__global/explorer/os) os_version=$(cat $__global/explorer/os_version) From 126a1812a5965778461ac3f371aaba2d14db7e0b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 14 Jul 2017 21:47:30 +0200 Subject: [PATCH 0542/1332] Fix parallel object prepare and run steps. Add nonparallel type marker. --- cdist/conf/type/__package/nonparallel | 0 cdist/conf/type/__package_apt/nonparallel | 0 cdist/conf/type/__package_dpkg/nonparallel | 0 cdist/conf/type/__package_emerge/nonparallel | 0 .../__package_emerge_dependencies/nonparallel | 0 .../conf/type/__package_luarocks/nonparallel | 0 cdist/conf/type/__package_opkg/nonparallel | 0 cdist/conf/type/__package_pacman/nonparallel | 0 cdist/conf/type/__package_pip/nonparallel | 0 .../type/__package_pkg_freebsd/nonparallel | 0 .../type/__package_pkg_openbsd/nonparallel | 0 .../type/__package_pkgng_freebsd/nonparallel | 0 cdist/conf/type/__package_rubygem/nonparallel | 0 .../type/__package_update_index/nonparallel | 0 .../type/__package_upgrade_all/nonparallel | 0 cdist/conf/type/__package_yum/nonparallel | 0 cdist/conf/type/__package_zypper/nonparallel | 0 cdist/config.py | 87 ++++++++++++++----- cdist/core/cdist_type.py | 9 ++ cdist/core/code.py | 4 +- cdist/core/explorer.py | 13 ++- cdist/exec/remote.py | 2 +- cdist/test/cdist_type/__init__.py | 10 +++ .../fixtures/__nonparallel/nonparallel | 0 .../fixtures/__not_nonparallel/.keep | 0 25 files changed, 97 insertions(+), 28 deletions(-) create mode 100644 cdist/conf/type/__package/nonparallel create mode 100644 cdist/conf/type/__package_apt/nonparallel create mode 100644 cdist/conf/type/__package_dpkg/nonparallel create mode 100644 cdist/conf/type/__package_emerge/nonparallel create mode 100644 cdist/conf/type/__package_emerge_dependencies/nonparallel create mode 100644 cdist/conf/type/__package_luarocks/nonparallel create mode 100644 cdist/conf/type/__package_opkg/nonparallel create mode 100644 cdist/conf/type/__package_pacman/nonparallel create mode 100644 cdist/conf/type/__package_pip/nonparallel create mode 100644 cdist/conf/type/__package_pkg_freebsd/nonparallel create mode 100644 cdist/conf/type/__package_pkg_openbsd/nonparallel create mode 100644 cdist/conf/type/__package_pkgng_freebsd/nonparallel create mode 100644 cdist/conf/type/__package_rubygem/nonparallel create mode 100644 cdist/conf/type/__package_update_index/nonparallel create mode 100644 cdist/conf/type/__package_upgrade_all/nonparallel create mode 100644 cdist/conf/type/__package_yum/nonparallel create mode 100644 cdist/conf/type/__package_zypper/nonparallel create mode 100644 cdist/test/cdist_type/fixtures/__nonparallel/nonparallel create mode 100644 cdist/test/cdist_type/fixtures/__not_nonparallel/.keep diff --git a/cdist/conf/type/__package/nonparallel b/cdist/conf/type/__package/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_apt/nonparallel b/cdist/conf/type/__package_apt/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_dpkg/nonparallel b/cdist/conf/type/__package_dpkg/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_emerge/nonparallel b/cdist/conf/type/__package_emerge/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_emerge_dependencies/nonparallel b/cdist/conf/type/__package_emerge_dependencies/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_luarocks/nonparallel b/cdist/conf/type/__package_luarocks/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_opkg/nonparallel b/cdist/conf/type/__package_opkg/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_pacman/nonparallel b/cdist/conf/type/__package_pacman/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_pip/nonparallel b/cdist/conf/type/__package_pip/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_pkg_freebsd/nonparallel b/cdist/conf/type/__package_pkg_freebsd/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_pkg_openbsd/nonparallel b/cdist/conf/type/__package_pkg_openbsd/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_pkgng_freebsd/nonparallel b/cdist/conf/type/__package_pkgng_freebsd/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_rubygem/nonparallel b/cdist/conf/type/__package_rubygem/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_update_index/nonparallel b/cdist/conf/type/__package_update_index/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_upgrade_all/nonparallel b/cdist/conf/type/__package_upgrade_all/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_yum/nonparallel b/cdist/conf/type/__package_yum/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_zypper/nonparallel b/cdist/conf/type/__package_zypper/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/config.py b/cdist/config.py index eee47d03..fccc93a0 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -167,7 +167,7 @@ class Config(object): time_end = time.time() log.verbose("Total processing time for %s host(s): %s", hostcnt, - (time_end - time_start)) + (time_end - time_start)) if len(failed_hosts) > 0: raise cdist.Error("Failed to configure the following hosts: " + @@ -356,10 +356,34 @@ class Config(object): elif cargo: self.log.trace("Multiprocessing start method is {}".format( multiprocessing.get_start_method())) + + self.log.trace("Multiprocessing cargo: %s", cargo) + + cargo_types = set() + for c in cargo: + cargo_types.add(c.cdist_type) + self.log.trace("Multiprocessing cargo_types: %s", cargo_types) + nt = len(cargo_types) + if nt == 1: + self.log.debug(("Only one type, transfering explorers " + "sequentially")) + self.explorer.transfer_type_explorers(cargo_types.pop()) + else: + self.log.trace(("Starting multiprocessing Pool for {} " + "parallel transfering types' explorers".format( + nt))) + args = [ + (ct, ) for ct in cargo_types + ] + mp_pool_run(self.explorer.transfer_type_explorers, args, + jobs=self.jobs) + self.log.trace(("Multiprocessing for parallel transfering " + "types' explorers finished")) + self.log.trace(("Starting multiprocessing Pool for {} parallel " "objects preparation".format(n))) args = [ - (c, ) for c in cargo + (c, False, ) for c in cargo ] mp_pool_run(self.object_prepare, args, jobs=self.jobs) self.log.trace(("Multiprocessing for parallel object " @@ -382,25 +406,44 @@ class Config(object): # self.object_run(cdist_object) # objects_changed = True - cargo.append(cdist_object) - n = len(cargo) - if n == 1: - self.log.debug("Only one object, running sequentially") - self.object_run(cargo[0]) - objects_changed = True - elif cargo: - self.log.trace("Multiprocessing start method is {}".format( - multiprocessing.get_start_method())) - self.log.trace(("Starting multiprocessing Pool for {} parallel " - "object run".format(n))) - args = [ - (c, ) for c in cargo - ] - mp_pool_run(self.object_run, args, jobs=self.jobs) - self.log.trace(("Multiprocessing for parallel object " - "run finished")) - objects_changed = True + # put objects in chuncks of distinct types + # so that there is no more than one object + # of the same type in one chunk because there is a + # possibility of object's process locking which + # prevents parallel execution at remote + # and do this only for nonparallel marked types + for chunk in cargo: + for obj in chunk: + if (obj.cdist_type == cdist_object.cdist_type and + cdist_object.cdist_type.is_nonparallel): + break + else: + chunk.append(cdist_object) + break + else: + chunk = [cdist_object, ] + cargo.append(chunk) + + for chunk in cargo: + self.log.trace("Running chunk: %s", chunk) + n = len(chunk) + if n == 1: + self.log.debug("Only one object, running sequentially") + self.object_run(chunk[0]) + objects_changed = True + elif chunk: + self.log.trace("Multiprocessing start method is {}".format( + multiprocessing.get_start_method())) + self.log.trace(("Starting multiprocessing Pool for {} " + "parallel object run".format(n))) + args = [ + (c, ) for c in chunk + ] + mp_pool_run(self.object_run, args, jobs=self.jobs) + self.log.trace(("Multiprocessing for parallel object " + "run finished")) + objects_changed = True return objects_changed @@ -466,12 +509,12 @@ class Config(object): ("The requirements of the following objects could not be " "resolved:\n%s") % ("\n".join(info_string))) - def object_prepare(self, cdist_object): + def object_prepare(self, cdist_object, transfer_type_explorers=True): """Prepare object: Run type explorer + manifest""" self.log.verbose("Preparing object {}".format(cdist_object.name)) self.log.verbose( "Running manifest and explorers for " + cdist_object.name) - self.explorer.run_type_explorers(cdist_object) + self.explorer.run_type_explorers(cdist_object, transfer_type_explorers) self.manifest.run_type_manifest(cdist_object) cdist_object.state = core.CdistObject.STATE_PREPARED diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index c2d45cdd..1f7c3eb5 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -66,6 +66,9 @@ class CdistType(object): self.__boolean_parameters = None self.__parameter_defaults = None + def __hash__(self): + return hash(self.name) + @classmethod def list_types(cls, base_path): """Return a list of type instances""" @@ -112,6 +115,12 @@ class CdistType(object): (if not: for configuration)""" return os.path.isfile(os.path.join(self.absolute_path, "install")) + @property + def is_nonparallel(self): + """Check whether a type is a non parallel, i.e. its objects + cannot run in parallel.""" + return os.path.isfile(os.path.join(self.absolute_path, "nonparallel")) + @property def explorers(self): """Return a list of available explorers""" diff --git a/cdist/core/code.py b/cdist/core/code.py index 6917e7ba..900188bf 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -141,7 +141,9 @@ class Code(object): destination = os.path.join(self.remote.object_path, cdist_object.code_remote_path) # FIXME: BUG: do not create destination, but top level of destination! - self.remote.mkdir(destination) + # self.remote.mkdir(destination) + # FIX? + self.remote.mkdir(os.path.dirname(destination)) self.remote.transfer(source, destination) def _run_code(self, cdist_object, which, env=None): diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 0d47e45e..d604c015 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -163,16 +163,21 @@ class Explorer(object): except EnvironmentError: return [] - def run_type_explorers(self, cdist_object): + def run_type_explorers(self, cdist_object, transfer_type_explorers=True): """Run the type explorers for the given object and save their output in the object. """ self.log.verbose("Running type explorers for {}".format( cdist_object.cdist_type)) - self.log.trace("Transfering type explorers for type: %s", - cdist_object.cdist_type) - self.transfer_type_explorers(cdist_object.cdist_type) + if transfer_type_explorers: + self.log.trace("Transfering type explorers for type: %s", + cdist_object.cdist_type) + self.transfer_type_explorers(cdist_object.cdist_type) + else: + self.log.trace(("No need for transfering type explorers for " + "type: %s"), + cdist_object.cdist_type) self.log.trace("Transfering object parameters for object: %s", cdist_object.name) self.transfer_object_parameters(cdist_object) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 2a27bae4..9588db74 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -124,7 +124,7 @@ class Remote(object): def transfer(self, source, destination, jobs=None): """Transfer a file or directory to the remote side.""" self.log.trace("Remote transfer: %s -> %s", source, destination) - self.rmdir(destination) + # self.rmdir(destination) if os.path.isdir(source): self.mkdir(destination) if jobs: diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index 6ed3f87c..6e11383b 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -113,6 +113,16 @@ class TypeTestCase(test.CdistTestCase): cdist_type = core.CdistType(base_path, '__not_singleton') self.assertFalse(cdist_type.is_singleton) + def test_nonparallel_is_nonparallel(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, '__nonparallel') + self.assertTrue(cdist_type.is_nonparallel) + + def test_not_nonparallel_is_nonparallel(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, '__not_nonparallel') + self.assertFalse(cdist_type.is_nonparallel) + def test_install_is_install(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__install') diff --git a/cdist/test/cdist_type/fixtures/__nonparallel/nonparallel b/cdist/test/cdist_type/fixtures/__nonparallel/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/cdist_type/fixtures/__not_nonparallel/.keep b/cdist/test/cdist_type/fixtures/__not_nonparallel/.keep new file mode 100644 index 00000000..e69de29b From 660d01ce0c8f31703b7611347ecc7f5b43ed80af Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 19 Jul 2017 07:49:06 +0200 Subject: [PATCH 0543/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index d778993f..fee1e1ff 100644 --- a/docs/changelog +++ b/docs/changelog @@ -11,6 +11,7 @@ next: * Core: Remove deprecated -d option (Darko Poljak) * Type __file: If no --source then create only if there is no file (Ander Punnar) * Core: Ignore directory entries that begin with dot('.') (Darko Poljak) + * Core: Fix parallel object prepare and run steps and add nonparallel type marker (Darko Poljak) 4.4.4: 2017-06-16 * Core: Support -j parallelization for object prepare and object run (Darko Poljak) From 2beb55be5417b2c11a958cc3902cc4c1e72a33f2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 19 Jul 2017 07:52:57 +0200 Subject: [PATCH 0544/1332] Remove FIXME comment due to fix appliance --- cdist/core/code.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cdist/core/code.py b/cdist/core/code.py index 900188bf..1b5fe1d6 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -140,9 +140,6 @@ class Code(object): cdist_object.code_remote_path) destination = os.path.join(self.remote.object_path, cdist_object.code_remote_path) - # FIXME: BUG: do not create destination, but top level of destination! - # self.remote.mkdir(destination) - # FIX? self.remote.mkdir(os.path.dirname(destination)) self.remote.transfer(source, destination) From a20b7167cddc55abfad21d4fec1a43d50a7dd432 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 19 Jul 2017 07:58:14 +0200 Subject: [PATCH 0545/1332] pep8 --- cdist/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index fccc93a0..450fde29 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -416,7 +416,7 @@ class Config(object): for chunk in cargo: for obj in chunk: if (obj.cdist_type == cdist_object.cdist_type and - cdist_object.cdist_type.is_nonparallel): + cdist_object.cdist_type.is_nonparallel): break else: chunk.append(cdist_object) From 4a72592ae5eda559851078b1779cb9bbde685511 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 20 Jul 2017 18:45:44 +0200 Subject: [PATCH 0546/1332] Document nonparallel type flag. --- docs/src/cdist-type.rst | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 59423332..bfe3c35d 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -64,15 +64,23 @@ If a type is flagged with 'install' flag then it is used only with install comma With other commands, i.e. config, these types are skipped if used. +Nonparallel types +----------------- +If a type is flagged with 'nonparallel' flag then its objects cannot be run in parallel +when using -j option. Example of such a type is __package_dpkg type where dpkg itself +prevents to be run in more than one instance. + + How to write a new type ----------------------- A type consists of -- parameter (optional) -- manifest (optional) -- singleton (optional) -- explorer (optional) -- gencode (optional) +- parameter (optional) +- manifest (optional) +- singleton (optional) +- explorer (optional) +- gencode (optional) +- nonparallel (optional) Types are stored below cdist/conf/type/. Their name should always be prefixed with two underscores (__) to prevent collisions with other executables in $PATH. @@ -240,6 +248,19 @@ install: create the (empty) file "install" in your type directory: With other commands, i.e. config, it will be skipped if used. +Nonparallel - only one instance can be run at a time +---------------------------------------------------- +If objects of a type must not or cannot be run in parallel when using -j +option, you must mark it as nonparallel: create the (empty) file "nonparallel" +in your type directory: + +.. code-block:: sh + + touch cdist/conf/type/__NAME/nonparallel + +For example, package types are nonparallel types. + + The type explorers ------------------ If a type needs to explore specific details, it can provide type specific From 6a256213f11ba938c0a8e90438b625a32eb085c6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 20 Jul 2017 20:08:15 +0200 Subject: [PATCH 0547/1332] Add missing -r option argument in cdist man page. --- docs/src/man1/cdist.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index edcad828..3ee10326 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -125,7 +125,7 @@ Configure/install one or more hosts. Operate on multiple hosts in parallel -.. option:: -r, --remote-out-dir +.. option:: -r REMOTE_OUT_PATH, --remote-out-dir REMOTE_OUT_PATH Directory to save cdist output in on the target host From b705893f3884e39dfd313aed5273bdf1b54b1271 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 20 Jul 2017 20:12:08 +0200 Subject: [PATCH 0548/1332] Add missing -q in cdist man page. --- docs/src/man1/cdist.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 3ee10326..37ea4969 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -11,23 +11,23 @@ SYNOPSIS :: - cdist [-h] [-v] [-V] {banner,config,shell,install} ... + cdist [-h] [-q] [-v] [-V] {banner,config,shell,install} ... - cdist banner [-h] [-v] + cdist banner [-h] [-q] [-v] - cdist config [-h] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] + cdist config [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] [host [host ...]] - cdist install [-h] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] + cdist install [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] [host [host ...]] - cdist shell [-h] [-v] [-s SHELL] + cdist shell [-h] [-q] [-v] [-s SHELL] DESCRIPTION From 2b6177c9f74abb14f490e6be2e932ac3da86a5ab Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 20 Jul 2017 20:48:07 +0200 Subject: [PATCH 0549/1332] Fix rst. --- docs/src/cdist-best-practice.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/cdist-best-practice.rst b/docs/src/cdist-best-practice.rst index fdbb7a80..45aba11b 100644 --- a/docs/src/cdist-best-practice.rst +++ b/docs/src/cdist-best-practice.rst @@ -97,7 +97,7 @@ Including a possible common base that is reused across the different sites:: git merge common -The following **.git/config** is taken from a real world scenario: +The following **.git/config** is taken from a real world scenario:: # Track upstream, merge from time to time [remote "upstream"] From e2a1519332e176e3a3c2d48e5a17b373070f03b5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 20 Jul 2017 22:04:44 +0200 Subject: [PATCH 0550/1332] Merge inventory from beta branch. --- .gitignore | 3 + cdist/argparse.py | 166 +++++- cdist/conf/type/__install_stage/man.rst | 6 +- cdist/config.py | 49 +- cdist/core/code.py | 3 + cdist/core/explorer.py | 1 + cdist/core/manifest.py | 2 + cdist/exec/local.py | 5 + cdist/inventory.py | 390 ++++++++++++++ cdist/shell.py | 3 + cdist/test/__init__.py | 1 + cdist/test/code/__init__.py | 5 + .../type/__dump_environment/gencode-local | 1 + cdist/test/config/__init__.py | 3 + cdist/test/emulator/__init__.py | 7 + cdist/test/explorer/__init__.py | 1 + cdist/test/inventory/__init__.py | 476 ++++++++++++++++++ cdist/test/manifest/__init__.py | 5 + .../fixtures/conf/manifest/dump_environment | 1 + .../conf/type/__dump_environment/manifest | 1 + completions/bash/cdist-completion.bash | 59 ++- completions/zsh/_cdist | 41 +- docs/changelog | 4 + docs/src/cdist-inventory.rst | 211 ++++++++ docs/src/cdist-reference.rst.sh | 10 + docs/src/index.rst | 1 + docs/src/man1/cdist.rst | 349 ++++++++++++- scripts/cdist | 1 + 28 files changed, 1769 insertions(+), 36 deletions(-) create mode 100644 cdist/inventory.py create mode 100644 cdist/test/inventory/__init__.py create mode 100644 docs/src/cdist-inventory.rst diff --git a/.gitignore b/.gitignore index 4258c2eb..55374d6d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ docs/src/cdist-reference.rst # Ignore cdist cache for version control /cache/ +# Ignore inventory basedir +cdist/inventory/ + # Python: cache, distutils, distribution in general __pycache__/ *.pyc diff --git a/cdist/argparse.py b/cdist/argparse.py index 8208d1f0..16b9d054 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -7,10 +7,10 @@ import collections # set of beta sub-commands -BETA_COMMANDS = set(('install', )) +BETA_COMMANDS = set(('install', 'inventory', )) # set of beta arguments for sub-commands BETA_ARGS = { - 'config': set(('jobs', )), + 'config': set(('jobs', 'tag', 'all_tagged_hosts', )), } EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/" # Parser others can reuse @@ -121,6 +121,17 @@ def get_parsers(): 'banner', parents=[parser['loglevel']]) parser['banner'].set_defaults(func=cdist.banner.banner) + parser['inventory_common'] = argparse.ArgumentParser(add_help=False) + parser['inventory_common'].add_argument( + '-I', '--inventory', + help=('Use specified custom inventory directory. ' + 'Inventory directory is set up by the following rules: ' + 'if this argument is set then specified directory is used, ' + 'if CDIST_INVENTORY_DIR env var is set then its value is ' + 'used, if HOME env var is set then ~/.cdist/inventory is ' + 'used, otherwise distribution inventory directory is used.'), + dest="inventory_dir", required=False) + # Config parser['config_main'] = argparse.ArgumentParser(add_help=False) parser['config_main'].add_argument( @@ -156,6 +167,10 @@ def get_parsers(): # remote-copy and remote-exec defaults are environment variables # if set; if not then None - these will be futher handled after # parsing to determine implementation default + parser['config_main'].add_argument( + '-r', '--remote-out-dir', + help='Directory to save cdist output in on the target host', + dest="remote_out_path") parser['config_main'].add_argument( '--remote-copy', help='Command to use for remote copy (should behave like scp)', @@ -170,6 +185,15 @@ def get_parsers(): # Config parser['config_args'] = argparse.ArgumentParser(add_help=False) + parser['config_args'].add_argument( + '-A', '--all-tagged', + help=('use all hosts present in tags db'), + action="store_true", dest="all_tagged_hosts", default=False) + parser['config_args'].add_argument( + '-a', '--all', + help=('list hosts that have all specified tags, ' + 'if -t/--tag is specified'), + action="store_true", dest="has_all_tags", default=False) parser['config_args'].add_argument( 'host', nargs='*', help='host(s) to operate on') parser['config_args'].add_argument( @@ -183,17 +207,19 @@ def get_parsers(): '-p', '--parallel', help='operate on multiple hosts in parallel', action='store_true', dest='parallel') - parser['config_args'].add_argument( - '-r', '--remote-out-dir', - help='Directory to save cdist output in on the target host', - dest="remote_out_path") parser['config_args'].add_argument( '-s', '--sequential', help='operate on multiple hosts sequentially (default)', action='store_false', dest='parallel') + parser['config_args'].add_argument( + '-t', '--tag', + help=('host is specified by tag, not hostname/address; ' + 'list all hosts that contain any of specified tags'), + dest='tag', required=False, action="store_true", default=False) parser['config'] = parser['sub'].add_parser( 'config', parents=[parser['loglevel'], parser['beta'], parser['config_main'], + parser['inventory_common'], parser['config_args']]) parser['config'].set_defaults(func=cdist.config.Config.commandline) @@ -202,6 +228,134 @@ def get_parsers(): parents=[parser['config']]) parser['install'].set_defaults(func=cdist.install.Install.commandline) + # Inventory + parser['inventory'] = parser['sub'].add_parser( + 'inventory', parents=[parser['loglevel'], parser['beta'], + parser['inventory_common']]) + parser['invsub'] = parser['inventory'].add_subparsers( + title="Inventory commands", dest="subcommand") + + parser['add-host'] = parser['invsub'].add_parser( + 'add-host', parents=[parser['loglevel'], parser['beta'], + parser['inventory_common']]) + parser['add-host'].add_argument( + 'host', nargs='*', help='host(s) to add') + parser['add-host'].add_argument( + '-f', '--file', + help=('Read additional hosts to add from specified file ' + 'or from stdin if \'-\' (each host on separate line). ' + 'If no host or host file is specified then, by default, ' + 'read from stdin.'), + dest='hostfile', required=False) + + parser['add-tag'] = parser['invsub'].add_parser( + 'add-tag', parents=[parser['loglevel'], parser['beta'], + parser['inventory_common']]) + parser['add-tag'].add_argument( + 'host', nargs='*', + help='list of host(s) for which tags are added') + parser['add-tag'].add_argument( + '-f', '--file', + help=('Read additional hosts to add tags from specified file ' + 'or from stdin if \'-\' (each host on separate line). ' + 'If no host or host file is specified then, by default, ' + 'read from stdin. If no tags/tagfile nor hosts/hostfile' + ' are specified then tags are read from stdin and are' + ' added to all hosts.'), + dest='hostfile', required=False) + parser['add-tag'].add_argument( + '-T', '--tag-file', + help=('Read additional tags to add from specified file ' + 'or from stdin if \'-\' (each tag on separate line). ' + 'If no tag or tag file is specified then, by default, ' + 'read from stdin. If no tags/tagfile nor hosts/hostfile' + ' are specified then tags are read from stdin and are' + ' added to all hosts.'), + dest='tagfile', required=False) + parser['add-tag'].add_argument( + '-t', '--taglist', + help=("Tag list to be added for specified host(s), comma separated" + " values"), + dest="taglist", required=False) + + parser['del-host'] = parser['invsub'].add_parser( + 'del-host', parents=[parser['loglevel'], parser['beta'], + parser['inventory_common']]) + parser['del-host'].add_argument( + 'host', nargs='*', help='host(s) to delete') + parser['del-host'].add_argument( + '-a', '--all', help=('Delete all hosts'), + dest='all', required=False, action="store_true", default=False) + parser['del-host'].add_argument( + '-f', '--file', + help=('Read additional hosts to delete from specified file ' + 'or from stdin if \'-\' (each host on separate line). ' + 'If no host or host file is specified then, by default, ' + 'read from stdin.'), + dest='hostfile', required=False) + + parser['del-tag'] = parser['invsub'].add_parser( + 'del-tag', parents=[parser['loglevel'], parser['beta'], + parser['inventory_common']]) + parser['del-tag'].add_argument( + 'host', nargs='*', + help='list of host(s) for which tags are deleted') + parser['del-tag'].add_argument( + '-a', '--all', + help=('Delete all tags for specified host(s)'), + dest='all', required=False, action="store_true", default=False) + parser['del-tag'].add_argument( + '-f', '--file', + help=('Read additional hosts to delete tags for from specified ' + 'file or from stdin if \'-\' (each host on separate line). ' + 'If no host or host file is specified then, by default, ' + 'read from stdin. If no tags/tagfile nor hosts/hostfile' + ' are specified then tags are read from stdin and are' + ' deleted from all hosts.'), + dest='hostfile', required=False) + parser['del-tag'].add_argument( + '-T', '--tag-file', + help=('Read additional tags from specified file ' + 'or from stdin if \'-\' (each tag on separate line). ' + 'If no tag or tag file is specified then, by default, ' + 'read from stdin. If no tags/tagfile nor' + ' hosts/hostfile are specified then tags are read from' + ' stdin and are added to all hosts.'), + dest='tagfile', required=False) + parser['del-tag'].add_argument( + '-t', '--taglist', + help=("Tag list to be deleted for specified host(s), " + "comma separated values"), + dest="taglist", required=False) + + parser['list'] = parser['invsub'].add_parser( + 'list', parents=[parser['loglevel'], parser['beta'], + parser['inventory_common']]) + parser['list'].add_argument( + 'host', nargs='*', help='host(s) to list') + parser['list'].add_argument( + '-a', '--all', + help=('list hosts that have all specified tags, ' + 'if -t/--tag is specified'), + action="store_true", dest="has_all_tags", default=False) + parser['list'].add_argument( + '-f', '--file', + help=('Read additional hosts to list from specified file ' + 'or from stdin if \'-\' (each host on separate line). ' + 'If no host or host file is specified then, by default, ' + 'list all.'), dest='hostfile', required=False) + parser['list'].add_argument( + '-H', '--host-only', help=('Suppress tags listing'), + action="store_true", dest="list_only_host", default=False) + parser['list'].add_argument( + '-t', '--tag', + help=('host is specified by tag, not hostname/address; ' + 'list all hosts that contain any of specified tags'), + action="store_true", default=False) + + parser['inventory'].set_defaults( + func=cdist.inventory.Inventory.commandline) + # Shell parser['shell'] = parser['sub'].add_parser( 'shell', parents=[parser['loglevel']]) diff --git a/cdist/conf/type/__install_stage/man.rst b/cdist/conf/type/__install_stage/man.rst index 6c68c543..e33e1e90 100644 --- a/cdist/conf/type/__install_stage/man.rst +++ b/cdist/conf/type/__install_stage/man.rst @@ -17,9 +17,9 @@ REQUIRED PARAMETERS uri The uri from which to fetch the tarball. Can be anything understood by curl, e.g: - | http://path/to/stage.tgz - | tftp:///path/to/stage.tgz - | file:///local/path/stage.tgz + | http://path/to/stage.tgz + | tftp:///path/to/stage.tgz + | file:///local/path/stage.tgz OPTIONAL PARAMETERS diff --git a/cdist/config.py b/cdist/config.py index 450fde29..2c9721f5 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -38,6 +38,9 @@ import cdist.hostsource import cdist.exec.local import cdist.exec.remote + +from cdist import inventory + import cdist.util.ipaddr as ipaddr from cdist import core @@ -134,11 +137,42 @@ class Config(object): base_root_path = cls.create_base_root_path(args.out_path) hostcnt = 0 - for host in itertools.chain(cls.hosts(args.host), - cls.hosts(args.hostfile)): + + if args.tag or args.all_tagged_hosts: + inventory.determine_default_inventory_dir(args) + if args.all_tagged_hosts: + inv_list = inventory.InventoryList( + hosts=None, istag=True, hostfile=None, + db_basedir=args.inventory_dir) + else: + inv_list = inventory.InventoryList( + hosts=args.host, istag=True, hostfile=args.hostfile, + db_basedir=args.inventory_dir, + has_all_tags=args.has_all_tags) + it = inv_list.entries() + else: + it = itertools.chain(cls.hosts(args.host), + cls.hosts(args.hostfile)) + for entry in it: + if isinstance(entry, tuple): + # if configuring by specified tags + host = entry[0] + host_tags = entry[1] + else: + # if configuring by host then check inventory for tags + host = entry + inventory.determine_default_inventory_dir(args) + inv_list = inventory.InventoryList( + hosts=(host,), db_basedir=args.inventory_dir) + inv = tuple(inv_list.entries()) + if inv: + # host is present in inventory and has tags + host_tags = inv[0][1] + else: + # host is not present in inventory or has no tags + host_tags = None host_base_path, hostdir = cls.create_host_base_dirs( host, base_root_path) - log.debug("Base root path for target host \"{}\" is \"{}\"".format( host, host_base_path)) @@ -147,11 +181,12 @@ class Config(object): log.trace("Creating child process for %s", host) process[host] = multiprocessing.Process( target=cls.onehost, - args=(host, host_base_path, hostdir, args, True)) + args=(host, host_tags, host_base_path, hostdir, args, + True)) process[host].start() else: try: - cls.onehost(host, host_base_path, hostdir, + cls.onehost(host, host_tags, host_base_path, hostdir, args, parallel=False) except cdist.Error as e: failed_hosts.append(host) @@ -199,7 +234,8 @@ class Config(object): return (remote_exec, remote_copy, ) @classmethod - def onehost(cls, host, host_base_path, host_dir_name, args, parallel): + def onehost(cls, host, host_tags, host_base_path, host_dir_name, args, + parallel): """Configure ONE system""" log = logging.getLogger(host) @@ -216,6 +252,7 @@ class Config(object): local = cdist.exec.local.Local( target_host=target_host, + target_host_tags=host_tags, base_root_path=host_base_path, host_dir_name=host_dir_name, initial_manifest=args.manifest, diff --git a/cdist/core/code.py b/cdist/core/code.py index 1b5fe1d6..173d192d 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -56,6 +56,7 @@ gencode-local __object_fq: full qualified object id, iow: $type.name + / + object_id __type: full qualified path to the type's dir __files: full qualified path to the files dir + __target_host_tags: comma spearated list of host tags returns: string containing the generated code or None @@ -74,6 +75,7 @@ gencode-remote __object_fq: full qualified object id, iow: $type.name + / + object_id __type: full qualified path to the type's dir __files: full qualified path to the files dir + __target_host_tags: comma spearated list of host tags returns: string containing the generated code or None @@ -106,6 +108,7 @@ class Code(object): '__target_fqdn': self.target_host[2], '__global': self.local.base_path, '__files': self.local.files_path, + '__target_host_tags': self.local.target_host_tags, } def _run_gencode(self, cdist_object, which): diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index d604c015..38f2a921 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -77,6 +77,7 @@ class Explorer(object): '__target_hostname': self.target_host[1], '__target_fqdn': self.target_host[2], '__explorer': self.remote.global_explorer_path, + '__target_host_tags': self.local.target_host_tags, } self._type_explorers_transferred = [] self.jobs = jobs diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index d8570097..6f941550 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -42,6 +42,7 @@ common: types are defined for use in type emulator == local.type_path __files: full qualified path to the files dir + __target_host_tags: comma spearated list of host tags initial manifest is: script: full qualified path to the initial manifest @@ -109,6 +110,7 @@ class Manifest(object): '__target_hostname': self.target_host[1], '__target_fqdn': self.target_host[2], '__files': self.local.files_path, + '__target_host_tags': self.local.target_host_tags, } if self.log.getEffectiveLevel() == logging.DEBUG: diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 6c285204..23ad4ce9 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -49,6 +49,7 @@ class Local(object): """ def __init__(self, target_host, + target_host_tags, base_root_path, host_dir_name, exec_path=sys.argv[0], @@ -58,6 +59,10 @@ class Local(object): quiet_mode=False): self.target_host = target_host + if target_host_tags is None: + self.target_host_tags = "" + else: + self.target_host_tags = ",".join(target_host_tags) self.hostdir = host_dir_name self.base_path = os.path.join(base_root_path, "data") diff --git a/cdist/inventory.py b/cdist/inventory.py new file mode 100644 index 00000000..ccb4428f --- /dev/null +++ b/cdist/inventory.py @@ -0,0 +1,390 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 2016 Darko Poljak (darko.poljak 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 . +# +# + +import cdist +import logging +import os +import os.path +import itertools +import sys +from cdist.hostsource import hostfile_process_line + +DIST_INVENTORY_DB_NAME = "inventory" + +dist_inventory_db = os.path.abspath(os.path.join( + os.path.dirname(cdist.__file__), DIST_INVENTORY_DB_NAME)) + + +def determine_default_inventory_dir(args): + # The order of inventory dir setting by decreasing priority + # 1. inventory_dir argument + # 2. CDIST_INVENTORY_DIR env var if set + # 3. ~/.cdist/inventory if HOME env var is set + # 4. distribution inventory directory + if not args.inventory_dir: + if 'CDIST_INVENTORY_DIR' in os.environ: + args.inventory_dir = os.environ['CDIST_INVENTORY_DIR'] + else: + home = cdist.home_dir() + if home: + args.inventory_dir = os.path.join(home, DIST_INVENTORY_DB_NAME) + else: + args.inventory_dir = dist_inventory_db + + +def contains_all(big, little): + """Return True if big contains all elements from little, + False otherwise. + """ + return set(little).issubset(set(big)) + + +def contains_any(big, little): + """Return True if big contains any element from little, + False otherwise. + """ + for x in little: + if x in big: + return True + return False + + +def check_always_true(x, y): + return True + + +def rstrip_nl(s): + '''str.rstrip "\n" from s''' + return str.rstrip(s, "\n") + + +class Inventory(object): + """Inventory main class""" + + def __init__(self, db_basedir=dist_inventory_db): + self.db_basedir = db_basedir + self.log = logging.getLogger("inventory") + self.init_db() + + def init_db(self): + self.log.debug("Init db: {}".format(self.db_basedir)) + if not os.path.exists(self.db_basedir): + os.makedirs(self.db_basedir, exist_ok=True) + elif not os.path.isdir(self.db_basedir): + raise cdist.Error(("Invalid inventory db basedir \'{}\'," + " must be a directory").format(self.db_basedir)) + + @staticmethod + def strlist_to_list(slist): + if slist: + result = [x for x in slist.split(',') if x] + else: + result = [] + return result + + def _input_values(self, source): + """Yield input values from source. + Source can be a sequence or filename (stdin if '-'). + In case of filename each line represents one input value. + """ + if isinstance(source, str): + import fileinput + try: + with fileinput.FileInput(files=(source)) as f: + for x in f: + result = hostfile_process_line(x, strip_func=rstrip_nl) + if result: + yield result + except (IOError, OSError) as e: + raise cdist.Error("Error reading from \'{}\'".format( + source)) + else: + if source: + for x in source: + if x: + yield x + + def _host_path(self, host): + hostpath = os.path.join(self.db_basedir, host) + return hostpath + + def _all_hosts(self): + return os.listdir(self.db_basedir) + + def _check_host(self, hostpath): + if not os.path.exists(hostpath): + return False + else: + if not os.path.isfile(hostpath): + raise cdist.Error(("Host path \'{}\' exists, but is not" + " a valid file").format(hostpath)) + return True + + def _read_host_tags(self, hostpath): + result = set() + with open(hostpath, "rt") as f: + for tag in f: + tag = tag.rstrip("\n") + if tag: + result.add(tag) + return result + + def _get_host_tags(self, host): + hostpath = self._host_path(host) + if self._check_host(hostpath): + return self._read_host_tags(hostpath) + else: + return None + + def _write_host_tags(self, host, tags): + hostpath = self._host_path(host) + if self._check_host(hostpath): + with open(hostpath, "wt") as f: + for tag in tags: + f.write("{}\n".format(tag)) + return True + else: + return False + + @classmethod + def commandline(cls, args): + """Manipulate inventory db""" + log = logging.getLogger("cdist") + if 'taglist' in args: + args.taglist = cls.strlist_to_list(args.taglist) + determine_default_inventory_dir(args) + + log.info("Using inventory: {}".format(args.inventory_dir)) + log.debug("Inventory args: {}".format(vars(args))) + log.debug("Inventory command: {}".format(args.subcommand)) + + if args.subcommand == "list": + c = InventoryList(hosts=args.host, istag=args.tag, + hostfile=args.hostfile, + db_basedir=args.inventory_dir, + list_only_host=args.list_only_host, + has_all_tags=args.has_all_tags) + elif args.subcommand == "add-host": + c = InventoryHost(hosts=args.host, hostfile=args.hostfile, + db_basedir=args.inventory_dir) + elif args.subcommand == "del-host": + c = InventoryHost(hosts=args.host, hostfile=args.hostfile, + all=args.all, db_basedir=args.inventory_dir, + action="del") + elif args.subcommand == "add-tag": + c = InventoryTag(hosts=args.host, tags=args.taglist, + hostfile=args.hostfile, tagfile=args.tagfile, + db_basedir=args.inventory_dir) + elif args.subcommand == "del-tag": + c = InventoryTag(hosts=args.host, tags=args.taglist, + hostfile=args.hostfile, tagfile=args.tagfile, + all=args.all, db_basedir=args.inventory_dir, + action="del") + else: + raise cdist.Error("Unknown inventory command \'{}\'".format( + args.subcommand)) + c.run() + + +class InventoryList(Inventory): + def __init__(self, hosts=None, istag=False, hostfile=None, + list_only_host=False, has_all_tags=False, + db_basedir=dist_inventory_db): + super().__init__(db_basedir) + self.hosts = hosts + self.istag = istag + self.hostfile = hostfile + self.list_only_host = list_only_host + self.has_all_tags = has_all_tags + + def _print(self, host, tags): + if self.list_only_host: + print("{}".format(host)) + else: + print("{} {}".format(host, ",".join(sorted(tags)))) + + def _do_list(self, it_tags, it_hosts, check_func): + if (it_tags is not None): + param_tags = set(it_tags) + self.log.debug("param_tags: {}".format(param_tags)) + else: + param_tags = set() + for host in it_hosts: + self.log.debug("host: {}".format(host)) + tags = self._get_host_tags(host) + if tags is None: + self.log.info("Host \'{}\' not found, skipped".format(host)) + continue + self.log.debug("tags: {}".format(tags)) + if check_func(tags, param_tags): + yield host, tags + + def entries(self): + if not self.hosts and not self.hostfile: + self.log.info("Listing all hosts") + it_hosts = self._all_hosts() + it_tags = None + check_func = check_always_true + else: + it = itertools.chain(self._input_values(self.hosts), + self._input_values(self.hostfile)) + if self.istag: + self.log.info("Listing by tag(s)") + it_hosts = self._all_hosts() + it_tags = it + if self.has_all_tags: + check_func = contains_all + else: + check_func = contains_any + else: + self.log.info("Listing by host(s)") + it_hosts = it + it_tags = None + check_func = check_always_true + for host, tags in self._do_list(it_tags, it_hosts, check_func): + yield host, tags + + def host_entries(self): + for host, tags in self.entries(): + yield host + + def run(self): + for host, tags in self.entries(): + self._print(host, tags) + + +class InventoryHost(Inventory): + def __init__(self, hosts=None, hostfile=None, + db_basedir=dist_inventory_db, all=False, action="add"): + super().__init__(db_basedir) + self.actions = ("add", "del") + if action not in self.actions: + raise cdist.Error("Invalid action \'{}\', valid actions are:" + " {}\n".format(action, self.actions.keys())) + self.action = action + self.hosts = hosts + self.hostfile = hostfile + self.all = all + + if not self.hosts and not self.hostfile: + self.hostfile = "-" + + def _new_hostpath(self, hostpath): + # create empty file + with open(hostpath, "w"): + pass + + def _action(self, host): + if self.action == "add": + self.log.info("Adding host \'{}\'".format(host)) + elif self.action == "del": + self.log.info("Deleting host \'{}\'".format(host)) + hostpath = self._host_path(host) + self.log.debug("hostpath: {}".format(hostpath)) + if self.action == "add" and not os.path.exists(hostpath): + self._new_hostpath(hostpath) + else: + if not os.path.isfile(hostpath): + raise cdist.Error(("Host path \'{}\' is" + " not a valid file").format(hostpath)) + if self.action == "del": + os.remove(hostpath) + + def run(self): + if self.action == "del" and self.all: + self.log.debug("Doing for all hosts") + it = self._all_hosts() + else: + self.log.debug("Doing for specified hosts") + it = itertools.chain(self._input_values(self.hosts), + self._input_values(self.hostfile)) + for host in it: + self._action(host) + + +class InventoryTag(Inventory): + def __init__(self, hosts=None, tags=None, hostfile=None, tagfile=None, + db_basedir=dist_inventory_db, all=False, action="add"): + super().__init__(db_basedir) + self.actions = ("add", "del") + if action not in self.actions: + raise cdist.Error("Invalid action \'{}\', valid actions are:" + " {}\n".format(action, self.actions.keys())) + self.action = action + self.hosts = hosts + self.tags = tags + self.hostfile = hostfile + self.tagfile = tagfile + self.all = all + + if not self.hosts and not self.hostfile: + self.allhosts = True + else: + self.allhosts = False + if not self.tags and not self.tagfile: + self.tagfile = "-" + + if self.hostfile == "-" and self.tagfile == "-": + raise cdist.Error("Cannot read both, hosts and tags, from stdin") + + def _read_input_tags(self): + self.input_tags = set() + for tag in itertools.chain(self._input_values(self.tags), + self._input_values(self.tagfile)): + self.input_tags.add(tag) + + def _action(self, host): + host_tags = self._get_host_tags(host) + if host_tags is None: + print("Host \'{}\' does not exist, skipping".format(host), + file=sys.stderr) + return + self.log.debug("existing host_tags: {}".format(host_tags)) + if self.action == "del" and self.all: + host_tags = set() + else: + for tag in self.input_tags: + if self.action == "add": + self.log.info("Adding tag \'{}\' for host \'{}\'".format( + tag, host)) + host_tags.add(tag) + elif self.action == "del": + self.log.info("Deleting tag \'{}\' for host \'{}\'".format( + tag, host)) + if tag in host_tags: + host_tags.remove(tag) + self.log.debug("new host tags: {}".format(host_tags)) + if not self._write_host_tags(host, host_tags): + self.log.info("{} does not exist, skipped".format(host)) + + def run(self): + if self.allhosts: + self.log.debug("Doing for all hosts") + it = self._all_hosts() + else: + self.log.debug("Doing for specified hosts") + it = itertools.chain(self._input_values(self.hosts), + self._input_values(self.hostfile)) + if not(self.action == "del" and self.all): + self._read_input_tags() + for host in it: + self._action(host) diff --git a/cdist/shell.py b/cdist/shell.py index 662f8f7d..44cdd49d 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -44,6 +44,7 @@ class Shell(object): "cdist-shell-no-target-host", "cdist-shell-no-target-host", ) + self.target_host_tags = "" host_dir_name = cdist.str_hash(self.target_host[0]) base_root_path = tempfile.mkdtemp() @@ -51,6 +52,7 @@ class Shell(object): self.local = cdist.exec.local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=host_base_path, host_dir_name=host_dir_name) @@ -77,6 +79,7 @@ class Shell(object): '__manifest': self.local.manifest_path, '__explorer': self.local.global_explorer_path, '__files': self.local.files_path, + '__target_host_tags': self.local.target_host_tags, } self.env.update(additional_env) diff --git a/cdist/test/__init__.py b/cdist/test/__init__.py index 83b0c618..faa3686a 100644 --- a/cdist/test/__init__.py +++ b/cdist/test/__init__.py @@ -42,6 +42,7 @@ class CdistTestCase(unittest.TestCase): 'cdisttesthost', 'cdisttesthost', ) + target_host_tags = "tag1,tag2,tag3" def mkdtemp(self, **kwargs): return tempfile.mkdtemp(prefix='tmp.cdist.test.', **kwargs) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 83c93f8b..50da2b8a 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -46,6 +46,7 @@ class CodeTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=cdist.test.cdist_exec_path, @@ -97,6 +98,8 @@ class CodeTestCase(test.CdistTestCase): self.cdist_object.object_id) self.assertEqual(output_dict['__object_name'], self.cdist_object.name) self.assertEqual(output_dict['__files'], self.local.files_path) + self.assertEqual(output_dict['__target_host_tags'], + self.local.target_host_tags) def test_run_gencode_remote_environment(self): output_string = self.code.run_gencode_remote(self.cdist_object) @@ -120,6 +123,8 @@ class CodeTestCase(test.CdistTestCase): self.cdist_object.object_id) self.assertEqual(output_dict['__object_name'], self.cdist_object.name) self.assertEqual(output_dict['__files'], self.local.files_path) + self.assertEqual(output_dict['__target_host_tags'], + self.local.target_host_tags) def test_transfer_code_remote(self): self.cdist_object.code_remote = self.code.run_gencode_remote( diff --git a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local index 7fa70342..56744a27 100755 --- a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local +++ b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local @@ -9,3 +9,4 @@ echo "echo __object: $__object" echo "echo __object_id: $__object_id" echo "echo __object_name: $__object_name" echo "echo __files: $__files" +echo "echo __target_host_tags: $__target_host_tags" diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index af1aa38f..5ff98269 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -60,6 +60,7 @@ class ConfigRunTestCase(test.CdistTestCase): os.makedirs(self.host_base_path) self.local = cdist.exec.local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=self.host_base_path, host_dir_name=self.hostdir) @@ -164,6 +165,7 @@ class ConfigRunTestCase(test.CdistTestCase): """Test if the dryrun option is working like expected""" drylocal = cdist.exec.local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=self.host_base_path, host_dir_name=self.hostdir, # exec_path can not derivated from sys.argv in case of unittest @@ -181,6 +183,7 @@ class ConfigRunTestCase(test.CdistTestCase): """Test to show dependency resolver warning message.""" local = cdist.exec.local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=os.path.abspath(os.path.join( diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 51de3180..664ab20b 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -53,6 +53,7 @@ class EmulatorTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=host_base_path, host_dir_name=hostdir, exec_path=test.cdist_exec_path, @@ -156,6 +157,7 @@ class EmulatorConflictingRequirementsTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=host_base_path, host_dir_name=hostdir, exec_path=test.cdist_exec_path, @@ -246,6 +248,7 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=host_base_path, host_dir_name=hostdir, exec_path=test.cdist_exec_path, @@ -279,6 +282,7 @@ class OverrideTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=host_base_path, host_dir_name=hostdir, exec_path=test.cdist_exec_path, @@ -322,6 +326,7 @@ class ArgumentsTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=host_base_path, host_dir_name=hostdir, exec_path=test.cdist_exec_path, @@ -445,6 +450,7 @@ class StdinTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=host_base_path, host_dir_name=hostdir, exec_path=test.cdist_exec_path, @@ -511,6 +517,7 @@ class EmulatorAlreadyExistingRequirementsWarnTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=host_base_path, host_dir_name=hostdir, exec_path=test.cdist_exec_path, diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index fc66020d..928b4e0d 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -50,6 +50,7 @@ class ExplorerClassTestCase(test.CdistTestCase): self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=base_root_path, host_dir_name=hostdir, exec_path=test.cdist_exec_path, diff --git a/cdist/test/inventory/__init__.py b/cdist/test/inventory/__init__.py new file mode 100644 index 00000000..4c0dd936 --- /dev/null +++ b/cdist/test/inventory/__init__.py @@ -0,0 +1,476 @@ +# -*- coding: utf-8 -*- +# +# 2016 Darko Poljak (darko.poljak 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 . +# +# + +import os +import shutil +import cdist +import os.path as op +import unittest +import sys +from cdist import test +from cdist import inventory +from io import StringIO + +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +inventory_dir = op.join(fixtures, "inventory") + + +class InventoryTestCase(test.CdistTestCase): + + def _create_host_with_tags(self, host, tags): + os.makedirs(inventory_dir, exist_ok=True) + hostfile = op.join(inventory_dir, host) + with open(hostfile, "w") as f: + for x in tags: + f.write("{}\n".format(x)) + + def setUp(self): + self.maxDiff = None + self.db = { + "loadbalancer1": ["loadbalancer", "all", "europe", ], + "loadbalancer2": ["loadbalancer", "all", "europe", ], + "loadbalancer3": ["loadbalancer", "all", "africa", ], + "loadbalancer4": ["loadbalancer", "all", "africa", ], + "web1": ["web", "all", "static", ], + "web2": ["web", "all", "dynamic", ], + "web3": ["web", "all", "dynamic", ], + "shell1": ["shell", "all", "free", ], + "shell2": ["shell", "all", "free", ], + "shell3": ["shell", "all", "charge", ], + "shell4": ["shell", "all", "charge", ], + "monty": ["web", "python", "shell", ], + "python": ["web", "python", "shell", ], + } + for x in self.db: + self.db[x] = sorted(self.db[x]) + for host in self.db: + self._create_host_with_tags(host, self.db[host]) + self.sys_stdout = sys.stdout + out = StringIO() + sys.stdout = out + + def _get_output(self): + sys.stdout.flush() + output = sys.stdout.getvalue().strip() + return output + + def tearDown(self): + sys.stdout = self.sys_stdout + shutil.rmtree(inventory_dir) + + def test_inventory_create_db(self): + dbdir = op.join(fixtures, "foo") + inv = inventory.Inventory(db_basedir=dbdir) + self.assertTrue(os.path.isdir(dbdir)) + self.assertEqual(inv.db_basedir, dbdir) + shutil.rmtree(inv.db_basedir) + + # InventoryList + def test_inventory_list_print(self): + invList = inventory.InventoryList(db_basedir=inventory_dir) + invList.run() + output = self._get_output() + self.assertTrue(' ' in output) + + def test_inventory_list_print_host_only(self): + invList = inventory.InventoryList(db_basedir=inventory_dir, + list_only_host=True) + invList.run() + output = self._get_output() + self.assertFalse(' ' in output) + + def test_inventory_list_all(self): + invList = inventory.InventoryList(db_basedir=inventory_dir) + entries = invList.entries() + db = {host: sorted(tags) for host, tags in entries} + self.assertEqual(db, self.db) + + def test_inventory_list_by_host_hosts(self): + hosts = ("web1", "web2", "web3",) + invList = inventory.InventoryList(db_basedir=inventory_dir, + hosts=hosts) + entries = invList.entries() + db = {host: sorted(tags) for host, tags in entries} + expected_db = {host: sorted(self.db[host]) for host in hosts} + self.assertEqual(db, expected_db) + + def test_inventory_list_by_host_hostfile(self): + hosts = ("web1", "web2", "web3",) + hostfile = op.join(fixtures, "hosts") + with open(hostfile, "w") as f: + for x in hosts: + f.write("{}\n".format(x)) + invList = inventory.InventoryList(db_basedir=inventory_dir, + hostfile=hostfile) + entries = invList.entries() + db = {host: sorted(tags) for host, tags in entries} + expected_db = {host: sorted(self.db[host]) for host in hosts} + self.assertEqual(db, expected_db) + os.remove(hostfile) + + def test_inventory_list_by_host_hosts_hostfile(self): + hosts = ("shell1", "shell4",) + hostsf = ("web1", "web2", "web3",) + hostfile = op.join(fixtures, "hosts") + with open(hostfile, "w") as f: + for x in hostsf: + f.write("{}\n".format(x)) + invList = inventory.InventoryList(db_basedir=inventory_dir, + hosts=hosts, hostfile=hostfile) + entries = invList.entries() + db = {host: sorted(tags) for host, tags in entries} + import itertools + expected_db = {host: sorted(self.db[host]) for host in + itertools.chain(hostsf, hosts)} + self.assertEqual(db, expected_db) + os.remove(hostfile) + + def _gen_expected_db_for_tags(self, tags): + db = {} + for host in self.db: + for tag in tags: + if tag in self.db[host]: + db[host] = self.db[host] + break + return db + + def _gen_expected_db_for_has_all_tags(self, tags): + db = {} + for host in self.db: + if set(tags).issubset(set(self.db[host])): + db[host] = self.db[host] + return db + + def test_inventory_list_by_tag_hosts(self): + tags = ("web", "shell",) + invList = inventory.InventoryList(db_basedir=inventory_dir, + istag=True, hosts=tags) + entries = invList.entries() + db = {host: sorted(tags) for host, tags in entries} + expected_db = self._gen_expected_db_for_tags(tags) + self.assertEqual(db, expected_db) + + def test_inventory_list_by_tag_hostfile(self): + tags = ("web", "shell",) + tagfile = op.join(fixtures, "tags") + with open(tagfile, "w") as f: + for x in tags: + f.write("{}\n".format(x)) + invList = inventory.InventoryList(db_basedir=inventory_dir, + istag=True, hostfile=tagfile) + entries = invList.entries() + db = {host: sorted(tags) for host, tags in entries} + expected_db = self._gen_expected_db_for_tags(tags) + self.assertEqual(db, expected_db) + os.remove(tagfile) + + def test_inventory_list_by_tag_hosts_hostfile(self): + tags = ("web", "shell",) + tagsf = ("dynamic", "europe",) + tagfile = op.join(fixtures, "tags") + with open(tagfile, "w") as f: + for x in tagsf: + f.write("{}\n".format(x)) + invList = inventory.InventoryList(db_basedir=inventory_dir, + istag=True, hosts=tags, + hostfile=tagfile) + entries = invList.entries() + db = {host: sorted(tags) for host, tags in entries} + import itertools + expected_db = self._gen_expected_db_for_tags(tags + tagsf) + self.assertEqual(db, expected_db) + os.remove(tagfile) + + def test_inventory_list_by_tag_has_all_tags(self): + tags = ("web", "python", "shell",) + invList = inventory.InventoryList(db_basedir=inventory_dir, + istag=True, hosts=tags, + has_all_tags=True) + entries = invList.entries() + db = {host: sorted(tags) for host, tags in entries} + expected_db = self._gen_expected_db_for_has_all_tags(tags) + self.assertEqual(db, expected_db) + + # InventoryHost + def test_inventory_host_add_hosts(self): + hosts = ("spam", "eggs", "foo",) + invHost = inventory.InventoryHost(db_basedir=inventory_dir, + action="add", hosts=hosts) + invHost.run() + invList = inventory.InventoryList(db_basedir=inventory_dir) + expected_hosts = tuple(x for x in invList.host_entries() if x in hosts) + self.assertEqual(sorted(hosts), sorted(expected_hosts)) + + def test_inventory_host_add_hostfile(self): + hosts = ("spam-new", "eggs-new", "foo-new",) + hostfile = op.join(fixtures, "hosts") + with open(hostfile, "w") as f: + for x in hosts: + f.write("{}\n".format(x)) + invHost = inventory.InventoryHost(db_basedir=inventory_dir, + action="add", hostfile=hostfile) + invHost.run() + invList = inventory.InventoryList(db_basedir=inventory_dir) + expected_hosts = tuple(x for x in invList.host_entries() if x in hosts) + self.assertEqual(sorted(hosts), sorted(expected_hosts)) + os.remove(hostfile) + + def test_inventory_host_add_hosts_hostfile(self): + hosts = ("spam-spam", "eggs-spam", "foo-spam",) + hostf = ("spam-eggs-spam", "spam-foo-spam",) + hostfile = op.join(fixtures, "hosts") + with open(hostfile, "w") as f: + for x in hostf: + f.write("{}\n".format(x)) + invHost = inventory.InventoryHost(db_basedir=inventory_dir, + action="add", hosts=hosts, + hostfile=hostfile) + invHost.run() + invList = inventory.InventoryList(db_basedir=inventory_dir, + hosts=hosts + hostf) + expected_hosts = tuple(invList.host_entries()) + self.assertEqual(sorted(hosts + hostf), sorted(expected_hosts)) + os.remove(hostfile) + + def test_inventory_host_del_hosts(self): + hosts = ("web1", "shell1",) + invHost = inventory.InventoryHost(db_basedir=inventory_dir, + action="del", hosts=hosts) + invHost.run() + invList = inventory.InventoryList(db_basedir=inventory_dir, + hosts=hosts) + expected_hosts = tuple(invList.host_entries()) + self.assertTupleEqual(expected_hosts, ()) + + def test_inventory_host_del_hostfile(self): + hosts = ("loadbalancer3", "loadbalancer4",) + hostfile = op.join(fixtures, "hosts") + with open(hostfile, "w") as f: + for x in hosts: + f.write("{}\n".format(x)) + invHost = inventory.InventoryHost(db_basedir=inventory_dir, + action="del", hostfile=hostfile) + invHost.run() + invList = inventory.InventoryList(db_basedir=inventory_dir, + hosts=hosts) + expected_hosts = tuple(invList.host_entries()) + self.assertTupleEqual(expected_hosts, ()) + os.remove(hostfile) + + def test_inventory_host_del_hosts_hostfile(self): + hosts = ("loadbalancer1", "loadbalancer2",) + hostf = ("web2", "shell2",) + hostfile = op.join(fixtures, "hosts") + with open(hostfile, "w") as f: + for x in hostf: + f.write("{}\n".format(x)) + invHost = inventory.InventoryHost(db_basedir=inventory_dir, + action="del", hosts=hosts, + hostfile=hostfile) + invHost.run() + invList = inventory.InventoryList(db_basedir=inventory_dir, + hosts=hosts + hostf) + expected_hosts = tuple(invList.host_entries()) + self.assertTupleEqual(expected_hosts, ()) + os.remove(hostfile) + + @unittest.expectedFailure + def test_inventory_host_invalid_host(self): + try: + invalid_hostfile = op.join(inventory_dir, "invalid") + os.mkdir(invalid_hostfile) + hosts = ("invalid",) + invHost = inventory.InventoryHost(db_basedir=inventory_dir, + action="del", hosts=hosts) + invHost.run() + except e: + os.rmdir(invalid_hostfile) + raise e + + # InventoryTag + def test_inventory_tag_init(self): + invTag = inventory.InventoryTag(db_basedir=inventory_dir, + action="add") + self.assertTrue(invTag.allhosts) + self.assertEqual(invTag.tagfile, "-") + + def test_inventory_tag_stdin_multiple_hosts(self): + try: + invTag = inventory.InventoryTag(db_basedir=inventory_dir, + action="add", tagfile="-", + hosts=("host1", "host2",)) + except e: + self.fail() + + def test_inventory_tag_stdin_hostfile(self): + try: + invTag = inventory.InventoryTag(db_basedir=inventory_dir, + action="add", tagfile="-", + hostfile="hosts") + except e: + self.fail() + + @unittest.expectedFailure + def test_inventory_tag_stdin_both(self): + invTag = inventory.InventoryTag(db_basedir=inventory_dir, + action="add", tagfile="-", + hostfile="-") + + def test_inventory_tag_add_for_all_hosts(self): + tags = ("spam-spam-spam", "spam-spam-eggs",) + tagsf = ("spam-spam-spam-eggs", "spam-spam-eggs-spam",) + tagfile = op.join(fixtures, "tags") + with open(tagfile, "w") as f: + for x in tagsf: + f.write("{}\n".format(x)) + invTag = inventory.InventoryTag(db_basedir=inventory_dir, + action="add", tags=tags, + tagfile=tagfile) + invTag.run() + invList = inventory.InventoryList(db_basedir=inventory_dir) + failed = False + for host, taglist in invList.entries(): + for x in tagsf + tags: + if x not in taglist: + failed = True + break + if failed: + break + os.remove(tagfile) + if failed: + self.fail() + + def test_inventory_tag_add(self): + tags = ("spam-spam-spam", "spam-spam-eggs",) + tagsf = ("spam-spam-spam-eggs", "spam-spam-eggs-spam",) + hosts = ("loadbalancer1", "loadbalancer2", "shell2",) + hostsf = ("web2", "web3",) + tagfile = op.join(fixtures, "tags") + with open(tagfile, "w") as f: + for x in tagsf: + f.write("{}\n".format(x)) + hostfile = op.join(fixtures, "hosts") + with open(hostfile, "w") as f: + for x in hostsf: + f.write("{}\n".format(x)) + invTag = inventory.InventoryTag(db_basedir=inventory_dir, + action="add", tags=tags, + tagfile=tagfile, hosts=hosts, + hostfile=hostfile) + invTag.run() + invList = inventory.InventoryList(db_basedir=inventory_dir, + hosts=hosts + hostsf) + failed = False + for host, taglist in invList.entries(): + if host not in hosts + hostsf: + failed = True + break + for x in tagsf + tags: + if x not in taglist: + failed = True + break + if failed: + break + os.remove(tagfile) + os.remove(hostfile) + if failed: + self.fail() + + def test_inventory_tag_del_for_all_hosts(self): + tags = ("all",) + tagsf = ("charge",) + tagfile = op.join(fixtures, "tags") + with open(tagfile, "w") as f: + for x in tagsf: + f.write("{}\n".format(x)) + invTag = inventory.InventoryTag(db_basedir=inventory_dir, + action="del", tags=tags, + tagfile=tagfile) + invTag.run() + invList = inventory.InventoryList(db_basedir=inventory_dir) + failed = False + for host, taglist in invList.entries(): + for x in tagsf + tags: + if x in taglist: + failed = True + break + if failed: + break + os.remove(tagfile) + if failed: + self.fail() + + def test_inventory_tag_del(self): + tags = ("europe", "africa",) + tagsf = ("free", ) + hosts = ("loadbalancer1", "loadbalancer2", "shell2",) + hostsf = ("web2", "web3",) + tagfile = op.join(fixtures, "tags") + with open(tagfile, "w") as f: + for x in tagsf: + f.write("{}\n".format(x)) + hostfile = op.join(fixtures, "hosts") + with open(hostfile, "w") as f: + for x in hostsf: + f.write("{}\n".format(x)) + invTag = inventory.InventoryTag(db_basedir=inventory_dir, + action="del", tags=tags, + tagfile=tagfile, hosts=hosts, + hostfile=hostfile) + invTag.run() + invList = inventory.InventoryList(db_basedir=inventory_dir, + hosts=hosts + hostsf) + failed = False + for host, taglist in invList.entries(): + if host not in hosts + hostsf: + failed = True + break + for x in tagsf + tags: + if x in taglist: + failed = True + break + if failed: + break + os.remove(tagfile) + os.remove(hostfile) + if failed: + self.fail() + + def test_inventory_tag_del_all_tags(self): + hosts = ("web3", "shell1",) + hostsf = ("shell2", "loadbalancer1",) + hostfile = op.join(fixtures, "hosts") + with open(hostfile, "w") as f: + for x in hostsf: + f.write("{}\n".format(x)) + invHost = inventory.InventoryHost(db_basedir=inventory_dir, + action="del", all=True, + hosts=hosts, hostfile=hostfile) + invHost.run() + invList = inventory.InventoryList(db_basedir=inventory_dir, + hosts=hosts + hostsf) + for host, htags in invList.entries(): + self.assertEqual(htags, ()) + os.remove(hostfile) + +if __name__ == "__main__": + unittest.main() diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index 3e07c1a7..e0da2d9f 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -53,6 +53,7 @@ class ManifestTestCase(test.CdistTestCase): base_root_path = os.path.join(out_path, hostdir) self.local = local.Local( target_host=self.target_host, + target_host_tags=self.target_host_tags, base_root_path=base_root_path, host_dir_name=hostdir, exec_path=cdist.test.cdist_exec_path, @@ -93,6 +94,8 @@ class ManifestTestCase(test.CdistTestCase): self.local.type_path) self.assertEqual(output_dict['__manifest'], self.local.manifest_path) self.assertEqual(output_dict['__files'], self.local.files_path) + self.assertEqual(output_dict['__target_host_tags'], + self.local.target_host_tags) def test_type_manifest_environment(self): cdist_type = core.CdistType(self.local.type_path, '__dump_environment') @@ -126,6 +129,8 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__object_id'], cdist_object.object_id) self.assertEqual(output_dict['__object_name'], cdist_object.name) self.assertEqual(output_dict['__files'], self.local.files_path) + self.assertEqual(output_dict['__target_host_tags'], + self.local.target_host_tags) def test_debug_env_setup(self): current_level = self.log.getEffectiveLevel() diff --git a/cdist/test/manifest/fixtures/conf/manifest/dump_environment b/cdist/test/manifest/fixtures/conf/manifest/dump_environment index 702145e2..9f9df372 100755 --- a/cdist/test/manifest/fixtures/conf/manifest/dump_environment +++ b/cdist/test/manifest/fixtures/conf/manifest/dump_environment @@ -9,4 +9,5 @@ __global: $__global __cdist_type_base_path: $__cdist_type_base_path __manifest: $__manifest __files: $__files +__target_host_tags: $__target_host_tags DONE diff --git a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest index 757d07b5..fec5cb3f 100755 --- a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest +++ b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest @@ -13,4 +13,5 @@ __object: $__object __object_id: $__object_id __object_name: $__object_name __files: $__files +__target_host_tags: $__target_host_tags DONE diff --git a/completions/bash/cdist-completion.bash b/completions/bash/cdist-completion.bash index 6b58e2a2..1311384a 100644 --- a/completions/bash/cdist-completion.bash +++ b/completions/bash/cdist-completion.bash @@ -5,8 +5,8 @@ _cdist() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" prevprev="${COMP_WORDS[COMP_CWORD-2]}" - opts="-h --help -d --debug -v --verbose -V --version" - cmds="banner shell config install" + opts="-h --help -q --quiet -v --verbose -V --version" + cmds="banner config install inventory shell" case "${prevprev}" in shell) @@ -18,6 +18,41 @@ _cdist() ;; esac ;; + inventory) + case "${prev}" in + list) + opts="-h --help -q --quiet -v --verbose -b --beta \ + -I --invento/y -a --all -f --file -H --host-only \ + -t --tag" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + add-host) + opts="-h --help -q --quiet -v --verbose -b --beta \ + -I --inventory -f --file" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + del-host) + opts="-h --help -q --quiet -v --verbose -b --beta \ + -I --inventory -a --all -f --file" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + add-tag) + opts="-h --help -q --quiet -v --verbose -b --beta \ + -I --inventory -f --file -T --tag-file -t --taglist" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + del-tag) + opts="-h --help -q --quiet -v --verbose -b --beta \ + -I --inventory -a --all -f --file -T --tag-file -t --taglist" + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + ;; + esac + ;; esac case "${prev}" in @@ -26,23 +61,31 @@ _cdist() return 0 ;; banner) - opts="-h --help -d --debug -v --verbose" + opts="-h --help -q --quiet -v --verbose" COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 ;; shell) - opts="-h --help -d --debug -v --verbose -s --shell" + opts="-h --help -q --quiet -v --verbose -s --shell" COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 ;; config|install) - opts="-h --help -d --debug -v --verbose -b --beta \ - -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs \ - -n --dry-run -o --out-dir -p --parallel -r --remote-out-dir -s --sequential \ - --remote-copy --remote-exec" + opts="-h --help -q --quiet -v --verbose -b --beta \ + -I --inventory -C --cache-path-pattern -c --conf-dir \ + -f --file -i --initial-manifest -A --all-tagged \ + -j --jobs -n --dry-run -o --out-dir -p --parallel \ + -r --remote-out-dir \ + -s --sequential --remote-copy --remote-exec -t --tag -a --all" COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 ;; + inventory) + cmds="list add-host del-host add-tag del-tag" + opts="-h --help -q --quiet -v --verbose" + COMPREPLY=( $(compgen -W "${opts} ${cmds}" -- ${cur}) ) + return 0 + ;; *) ;; esac diff --git a/completions/zsh/_cdist b/completions/zsh/_cdist index 082cad12..405023ed 100644 --- a/completions/zsh/_cdist +++ b/completions/zsh/_cdist @@ -11,16 +11,16 @@ _cdist() case $state in opts_cmds) - _arguments '1:Options and commands:(banner config shell install -h --help -d --debug -v --verbose -V --version)' + _arguments '1:Options and commands:(banner config install inventory shell -h --help -q --quiet -v --verbose -V --version)' ;; *) case $words[2] in -*) - opts=(-h --help -d --debug -v --verbose -V --version) + opts=(-h --help -q --quiet -v --verbose -V --version) compadd "$@" -- $opts ;; banner) - opts=(-h --help -d --debug -v --verbose) + opts=(-h --help -q --quiet -v --verbose) compadd "$@" -- $opts ;; shell) @@ -30,16 +30,45 @@ _cdist() compadd "$@" -- $shells ;; *) - opts=(-h --help -d --debug -v --verbose -s --shell) + opts=(-h --help -q --quiet -v --verbose -s --shell) compadd "$@" -- $opts ;; esac ;; config|install) - opts=(-h --help -d --debug -v --verbose -b --beta -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -r --remote-out-dir -s --sequential --remote-copy --remote-exec) + opts=(-h --help -q --quiet -v --verbose -a --all -b --beta -C --cache-path-pattern -c --conf-dir -f --file -i --initial-manifest -j --jobs -n --dry-run -o --out-dir -p --parallel -r --remote-out-dir -s --sequential --remote-copy --remote-exec -t --tag -I --inventory -A --all-tagged) compadd "$@" -- $opts ;; - *) + inventory) + case $words[3] in + list) + opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -a --all -f --file -H --host-only -t --tag) + compadd "$@" -- $opts + ;; + add-host) + opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -f --file) + compadd "$@" -- $opts + ;; + del-host) + opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -a --all -f --file) + compadd "$@" -- $opts + ;; + add-tag) + opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -f --file -T --tag-file -t --taglist) + compadd "$@" -- $opts + ;; + del-tag) + opts=(-h --help -q --quiet -v --verbose -b --beta -I --inventory -a --all -f --file -T --tag-file -t --taglist) + compadd "$@" -- $opts + ;; + *) + cmds=(list add-host del-host add-tag del-tag) + opts=(-h --help -q --quiet -v --verbose) + compadd "$@" -- $cmds $opts + ;; + esac + ;; + *) ;; esac esac diff --git a/docs/changelog b/docs/changelog index fee1e1ff..b8c58adf 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,10 @@ Changelog --------- next: + * Core: Add inventory functionality (Darko Poljak) + * Core: Expose inventory host tags in __target_host_tags env var (Darko Poljak) + +4.5.0: 2017-07-20 * Types: Fix install types (Steven Armstrong) * Core: Add -r command line option for setting remote base path (Steven Armstrong) * Core: Allow manifest and gencode scripts to be written in any language (Darko Poljak) diff --git a/docs/src/cdist-inventory.rst b/docs/src/cdist-inventory.rst new file mode 100644 index 00000000..584fe310 --- /dev/null +++ b/docs/src/cdist-inventory.rst @@ -0,0 +1,211 @@ +Inventory +========= + +Introduction +------------ + +cdist comes with simple built-in tag based inventory. It is a simple inventory +with list of hosts and a host has a list of tags. +Inventory functionality is still in **beta** so it can be used only if beta +command line flag is specified (-b, --beta) or setting CDIST_BETA env var. + +Description +----------- + +The idea is to have simple tagging inventory. There is a list of hosts and for +each host there are tags. Inventory database is a set of files under inventory +database base directory. Filename equals hostname. Each file contains tags for +hostname with each tag on its own line. + +Using inventory you can now configure hosts by selecting them by tags. + +Tags have no values, as tags are just tags. Tag name-value would in this +context mean that host has two tags and it is selected by specifying that both +tags are present. + +This inventory is **KISS** cdist built-in inventory database. You can maintain it +using cdist inventory interface or using standard UNIX tools. + +cdist inventory interface +------------------------- + +With cdist inventory interface you can list host(s) and tag(s), add host(s), +add tag(s), delete host(s) and delete tag(s). + +Configuring hosts using inventory +--------------------------------- + +config command now has new options, **-t**, **-a** and **-A**. + +**-A** means that all hosts in tag db is selected. + +**-a** means that selected hosts must contain ALL specified tags. + +**-t** means that host specifies tag - all hosts that have specified tags are +selected. + +Examples +-------- + +.. code-block:: sh + + # List inventory content + $ cdist inventory list -b + + # List inventory for specified host localhost + $ cdist inventory list -b localhost + + # List inventory for specified tag loadbalancer + $ cdist inventory list -b -t loadbalancer + + # Add hosts to inventory + $ cdist inventory add-host -b web1 web2 web3 + + # Delete hosts from file old-hosts from inventory + $ cdist inventory del-host -b -f old-hosts + + # Add tags to specifed hosts + $ cdist inventory add-tag -b -t europe,croatia,web,static web1 web2 + + # Add tag to all hosts in inventory + $ cdist inventory add-tag -b -t vm + + # Delete all tags from specified host + $ cdist inventory del-tag -b -a localhost + + # Delete tags read from stdin from hosts specified by file hosts + $ cdist inventory del-tag -b -T - -f hosts + + # Configure hosts from inventory with any of specified tags + $ cdist config -b -t web dynamic + + # Configure hosts from inventory with all specified tags + $ cdist config -b -t -a web dynamic + + # Configure all hosts from inventory db + $ cdist config -b -A + +Example of manipulating database +-------------------------------- + +.. code-block:: sh + + $ python3 scripts/cdist inventory list -b + $ python3 scripts/cdist inventory add-host -b localhost + $ python3 scripts/cdist inventory add-host -b test.mycloud.net + $ python3 scripts/cdist inventory list -b + localhost + test.mycloud.net + $ python3 scripts/cdist inventory add-host -b web1.mycloud.net web2.mycloud.net shell1.mycloud.net shell2.mycloud.net + $ python3 scripts/cdist inventory list -b + localhost + test.mycloud.net + web1.mycloud.net + web2.mycloud.net + shell1.mycloud.net + shell2.mycloud.net + $ python3 scripts/cdist inventory add-tag -b -t web web1.mycloud.net web2.mycloud.net + $ python3 scripts/cdist inventory add-tag -b -t shell shell1.mycloud.net shell2.mycloud.net + $ python3 scripts/cdist inventory add-tag -b -t cloud + $ python3 scripts/cdist inventory list -b + localhost cloud + test.mycloud.net cloud + web1.mycloud.net cloud,web + web2.mycloud.net cloud,web + shell1.mycloud.net cloud,shell + shell2.mycloud.net cloud,shell + $ python3 scripts/cdist inventory add-tag -b -t test,web,shell test.mycloud.net + $ python3 scripts/cdist inventory list -b + localhost cloud + test.mycloud.net cloud,shell,test,web + web1.mycloud.net cloud,web + web2.mycloud.net cloud,web + shell1.mycloud.net cloud,shell + shell2.mycloud.net cloud,shell + $ python3 scripts/cdist inventory del-tag -b -t shell test.mycloud.net + $ python3 scripts/cdist inventory list -b + localhost cloud + test.mycloud.net cloud,test,web + web1.mycloud.net cloud,web + web2.mycloud.net cloud,web + shell1.mycloud.net cloud,shell + shell2.mycloud.net cloud,shell + $ python3 scripts/cdist inventory add-tag -b -t all + $ python3 scripts/cdist inventory add-tag -b -t mistake + $ python3 scripts/cdist inventory list -b + localhost all,cloud,mistake + test.mycloud.net all,cloud,mistake,test,web + web1.mycloud.net all,cloud,mistake,web + web2.mycloud.net all,cloud,mistake,web + shell1.mycloud.net all,cloud,mistake,shell + shell2.mycloud.net all,cloud,mistake,shell + $ python3 scripts/cdist inventory del-tag -b -t mistake + $ python3 scripts/cdist inventory list -b + localhost all,cloud + test.mycloud.net all,cloud,test,web + web1.mycloud.net all,cloud,web + web2.mycloud.net all,cloud,web + shell1.mycloud.net all,cloud,shell + shell2.mycloud.net all,cloud,shell + $ python3 scripts/cdist inventory del-host -b localhost + $ python3 scripts/cdist inventory list -b + test.mycloud.net all,cloud,test,web + web1.mycloud.net all,cloud,web + web2.mycloud.net all,cloud,web + shell1.mycloud.net all,cloud,shell + shell2.mycloud.net all,cloud,shell + $ python3 scripts/cdist inventory list -b -t web + test.mycloud.net all,cloud,test,web + web1.mycloud.net all,cloud,web + web2.mycloud.net all,cloud,web + $ python3 scripts/cdist inventory list -b -t -a web test + test.mycloud.net all,cloud,test,web + $ python3 scripts/cdist inventory list -b -t -a web all + test.mycloud.net all,cloud,test,web + web1.mycloud.net all,cloud,web + web2.mycloud.net all,cloud,web + $ python3 scripts/cdist inventory list -b -t web all + test.mycloud.net all,cloud,test,web + web1.mycloud.net all,cloud,web + web2.mycloud.net all,cloud,web + shell1.mycloud.net all,cloud,shell + shell2.mycloud.net all,cloud,shell + $ cd cdist/inventory + $ ls -1 + shell1.mycloud.net + shell2.mycloud.net + test.mycloud.net + web1.mycloud.net + web2.mycloud.net + $ ls -l + total 20 + -rw-r--r-- 1 darko darko 16 Jun 24 12:43 shell1.mycloud.net + -rw-r--r-- 1 darko darko 16 Jun 24 12:43 shell2.mycloud.net + -rw-r--r-- 1 darko darko 19 Jun 24 12:43 test.mycloud.net + -rw-r--r-- 1 darko darko 14 Jun 24 12:43 web1.mycloud.net + -rw-r--r-- 1 darko darko 14 Jun 24 12:43 web2.mycloud.net + $ cat test.mycloud.net + test + all + web + cloud + $ cat web2.mycloud.net + all + web + cloud + +For more info about inventory commands and options see `cdist `_\ (1). + +Using external inventory +------------------------ + +cdist can be used with any external inventory where external inventory is +some storage or database from which you can get a list of hosts to configure. +cdist can then be fed with this list of hosts through stdin or file using +**-f** option. For example, if your host list is stored in sqlite3 database +hosts.db and you want to select hosts which purpose is **django** then you +can use it with cdist like: + +.. code-block:: sh + + $ sqlite3 hosts.db "select hostname from hosts where purpose = 'django';" | cdist config diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index 5889ded9..89820358 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -63,6 +63,10 @@ cdist/conf/ The distribution configuration directory. This contains types and explorers to be used. +cdist/inventory/ + The distribution inventory directory. + This path is relative to cdist installation directory. + confdir Cdist will use all available configuration directories and create a temporary confdir containing links to the real configuration directories. @@ -239,6 +243,9 @@ __target_fqdn This variable is derived from **__target_host** (using **socket.getfqdn()**). Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell. +__target_host_tags + Comma separated list of target host tags. + Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell. __type Path to the current type. Available for: type manifest, type gencode. @@ -274,6 +281,9 @@ CDIST_REMOTE_EXEC CDIST_REMOTE_COPY Use this command for remote copy (should behave like scp). +CDIST_INVENTORY_DIR + Use this directory as inventory directory. + CDIST_BETA Enable beta functionalities. diff --git a/docs/src/index.rst b/docs/src/index.rst index b33b707d..42c21199 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -24,6 +24,7 @@ Contents: cdist-explorer cdist-messaging cdist-parallelization + cdist-inventory cdist-reference cdist-best-practice cdist-stages diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 37ea4969..d6bd1c8f 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -11,21 +11,46 @@ SYNOPSIS :: - cdist [-h] [-q] [-v] [-V] {banner,config,shell,install} ... + cdist [-h] [-q] [-v] [-V] {banner,config,install,inventory,shell} ... cdist banner [-h] [-q] [-v] cdist config [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] - [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] - [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] - [host [host ...]] + [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] + [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] + [-f HOSTFILE] [-p] [-s] [-t] + [host [host ...]] cdist install [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] - [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] - [-f HOSTFILE] [-p] [-r REMOTE_OUT_PATH] [-s] - [host [host ...]] + [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] + [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] + [-f HOSTFILE] [-p] [-s] [-t] + [host [host ...]] + + cdist inventory [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] + {add-host,add-tag,del-host,del-tag,list} ... + + cdist inventory add-host [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] + [-f HOSTFILE] + [host [host ...]] + + cdist inventory add-tag [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] + [-f HOSTFILE] [-T TAGFILE] [-t TAGLIST] + [host [host ...]] + + cdist inventory del-host [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] [-a] + [-f HOSTFILE] + [host [host ...]] + + cdist inventory del-tag [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] [-a] + [-f HOSTFILE] [-T TAGFILE] [-t TAGLIST] + [host [host ...]] + + cdist inventory list [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] [-a] + [-f HOSTFILE] [-H] [-t] + [host [host ...]] cdist shell [-h] [-q] [-v] [-s SHELL] @@ -72,6 +97,15 @@ CONFIG/INSTALL -------------- Configure/install one or more hosts. +.. option:: -A, --all-tagged + + use all hosts present in tags db + +.. option:: -a, --all + + list hosts that have all specified tags, if -t/--tag + is specified + .. option:: -b, --beta Enable beta functionality. @@ -103,6 +137,16 @@ Configure/install one or more hosts. read hosts from stdin. For the file format see :strong:`HOSTFILE FORMAT` below. +.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR + + Use specified custom inventory directory. Inventory + directory is set up by the following rules: if this + argument is set then specified directory is used, if + CDIST_INVENTORY_DIR env var is set then its value is + used, if HOME env var is set then ~/.cdit/inventory is + used, otherwise distribution inventory directory is + used. + .. option:: -i MANIFEST, --initial-manifest MANIFEST Path to a cdist manifest or - to read from stdin @@ -141,6 +185,10 @@ Configure/install one or more hosts. Command to use for remote execution (should behave like ssh) +.. option:: -t, --tag + + host is specified by tag, not hostname/address; list + all hosts that contain any of specified tags HOSTFILE FORMAT ~~~~~~~~~~~~~~~ @@ -174,6 +222,246 @@ Resulting path is used to specify cache path subdirectory under which current host cache data are saved. +INVENTORY +--------- +Manage inventory database. +Currently in beta with all sub-commands. + + +INVENTORY ADD-HOST +------------------ +Add host(s) to inventory database. + +.. option:: host + + host(s) to add + +.. option:: -b, --beta + + Enable beta functionalities. Beta functionalities + include inventory command with all sub-commands and + all options; config sub-command options: -j/--jobs, + -t/--tag, -a/--all. + + Can also be enabled using CDIST_BETA env var. + +.. option:: -f HOSTFILE, --file HOSTFILE + + Read additional hosts to add from specified file or + from stdin if '-' (each host on separate line). If no + host or host file is specified then, by default, read + from stdin. Hostfile format is the same as config hostfile format. + +.. option:: -h, --help + + show this help message and exit + +.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR + + Use specified custom inventory directory. Inventory + directory is set up by the following rules: if this + argument is set then specified directory is used, if + CDIST_INVENTORY_DIR env var is set then its value is + used, if HOME env var is set then ~/.cdist/inventory is + used, otherwise distribution inventory directory is + used. + + +INVENTORY ADD-TAG +----------------- +Add tag(s) to inventory database. + +.. option:: host + + list of host(s) for which tags are added + +.. option:: -b, --beta + + Enable beta functionalities. Beta functionalities + include inventory command with all sub-commands and + all options; config sub-command options: -j/--jobs, + -t/--tag, -a/--all. + + Can also be enabled using CDIST_BETA env var. + +.. option:: -f HOSTFILE, --file HOSTFILE + + Read additional hosts to add tags from specified file + or from stdin if '-' (each host on separate line). If + no host or host file is specified then, by default, + read from stdin. If no tags/tagfile nor hosts/hostfile + are specified then tags are read from stdin and are + added to all hosts. Hostfile format is the same as config hostfile format. + +.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR + + Use specified custom inventory directory. Inventory + directory is set up by the following rules: if this + argument is set then specified directory is used, if + CDIST_INVENTORY_DIR env var is set then its value is + used, if HOME env var is set then ~/.cdist/inventory is + used, otherwise distribution inventory directory is + used. + +.. option:: -T TAGFILE, --tag-file TAGFILE + + Read additional tags to add from specified file or + from stdin if '-' (each tag on separate line). If no + tag or tag file is specified then, by default, read + from stdin. If no tags/tagfile nor hosts/hostfile are + specified then tags are read from stdin and are added + to all hosts. Tagfile format is the same as config hostfile format. + +.. option:: -t TAGLIST, --taglist TAGLIST + + Tag list to be added for specified host(s), comma + separated values + + +INVENTORY DEL-HOST +------------------ +Delete host(s) from inventory database. + +.. option:: host + + host(s) to delete + +.. option:: -a, --all + + Delete all hosts + +.. option:: -b, --beta + + Enable beta functionalities. Beta functionalities + include inventory command with all sub-commands and + all options; config sub-command options: -j/--jobs, + -t/--tag, -a/--all. + + Can also be enabled using CDIST_BETA env var. + +.. option:: -f HOSTFILE, --file HOSTFILE + + Read additional hosts to delete from specified file or + from stdin if '-' (each host on separate line). If no + host or host file is specified then, by default, read + from stdin. Hostfile format is the same as config hostfile format. + +.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR + + Use specified custom inventory directory. Inventory + directory is set up by the following rules: if this + argument is set then specified directory is used, if + CDIST_INVENTORY_DIR env var is set then its value is + used, if HOME env var is set then ~/.cdist/inventory is + used, otherwise distribution inventory directory is + used. + + +INVENTORY DEL-TAG +----------------- +Delete tag(s) from inventory database. + +.. option:: host + + list of host(s) for which tags are deleted + +.. option:: -a, --all + + Delete all tags for specified host(s) + +.. option:: -b, --beta + + Enable beta functionalities. Beta functionalities + include inventory command with all sub-commands and + all options; config sub-command options: -j/--jobs, + -t/--tag, -a/--all. + + Can also be enabled using CDIST_BETA env var. + +.. option:: -f HOSTFILE, --file HOSTFILE + + Read additional hosts to delete tags for from + specified file or from stdin if '-' (each host on + separate line). If no host or host file is specified + then, by default, read from stdin. If no tags/tagfile + nor hosts/hostfile are specified then tags are read + from stdin and are deleted from all hosts. Hostfile + format is the same as config hostfile format. + +.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR + + Use specified custom inventory directory. Inventory + directory is set up by the following rules: if this + argument is set then specified directory is used, if + CDIST_INVENTORY_DIR env var is set then its value is + used, if HOME env var is set then ~/.cdist/inventory is + used, otherwise distribution inventory directory is + used. + +.. option:: -T TAGFILE, --tag-file TAGFILE + + Read additional tags from specified file or from stdin + if '-' (each tag on separate line). If no tag or tag + file is specified then, by default, read from stdin. + If no tags/tagfile nor hosts/hostfile are specified + then tags are read from stdin and are added to all + hosts. Tagfile format is the same as config hostfile format. + +.. option:: -t TAGLIST, --taglist TAGLIST + + Tag list to be deleted for specified host(s), comma + separated values + + +INVENTORY LIST +-------------- +List inventory database. + +.. option:: host + + host(s) to list + +.. option:: -a, --all + + list hosts that have all specified tags, if -t/--tag + is specified + +.. option:: -b, --beta + + Enable beta functionalities. Beta functionalities + include inventory command with all sub-commands and + all options; config sub-command options: -j/--jobs, + -t/--tag, -a/--all. + + Can also be enabled using CDIST_BETA env var. + +.. option:: -f HOSTFILE, --file HOSTFILE + + Read additional hosts to list from specified file or + from stdin if '-' (each host on separate line). If no + host or host file is specified then, by default, list + all. Hostfile format is the same as config hostfile format. + +.. option:: -H, --host-only + + Suppress tags listing + +.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR + + Use specified custom inventory directory. Inventory + directory is set up by the following rules: if this + argument is set then specified directory is used, if + CDIST_INVENTORY_DIR env var is set then its value is + used, if HOME env var is set then ~/.cdist/inventory is + used, otherwise distribution inventory directory is + used. + +.. option:: -t, --tag + + host is specified by tag, not hostname/address; list + all hosts that contain any of specified tags + + SHELL ----- This command allows you to spawn a shell that enables access @@ -186,14 +474,21 @@ usage. Its primary use is for debugging type parameters. Select shell to use, defaults to current shell. Used shell should be POSIX compatible shell. + FILES ----- ~/.cdist Your personal cdist config directory. If exists it will be automatically used. +~/.cdist/inventory + The home inventory directory. If ~/.cdist exists it will be used as + default inventory directory. cdist/conf The distribution configuration directory. It contains official types and explorers. This path is relative to cdist installation directory. +cdist/inventory + The distribution inventory directory. + This path is relative to cdist installation directory. NOTES ----- @@ -243,6 +538,43 @@ EXAMPLES # Install ikq05.ethz.ch with debug enabled % cdist install -vvv ikq05.ethz.ch + # List inventory content + % cdist inventory list -b + + # List inventory for specified host localhost + % cdist inventory list -b localhost + + # List inventory for specified tag loadbalancer + % cdist inventory list -b -t loadbalancer + + # Add hosts to inventory + % cdist inventory add-host -b web1 web2 web3 + + # Delete hosts from file old-hosts from inventory + % cdist inventory del-host -b -f old-hosts + + # Add tags to specifed hosts + % cdist inventory add-tag -b -t europe,croatia,web,static web1 web2 + + # Add tag to all hosts in inventory + % cdist inventory add-tag -b -t vm + + # Delete all tags from specified host + % cdist inventory del-tag -b -a localhost + + # Delete tags read from stdin from hosts specified by file hosts + % cdist inventory del-tag -b -T - -f hosts + + # Configure hosts from inventory with any of specified tags + % cdist config -b -t web dynamic + + # Configure hosts from inventory with all specified tags + % cdist config -b -t -a web dynamic + + # Configure all hosts from inventory db + $ cdist config -b -A + + ENVIRONMENT ----------- TMPDIR, TEMP, TMP @@ -272,6 +604,9 @@ CDIST_REMOTE_EXEC CDIST_REMOTE_COPY Use this command for remote copy (should behave like scp). +CDIST_INVENTORY_DIR + Use this directory as inventory directory. + CDIST_BETA Enable beta functionality. diff --git a/scripts/cdist b/scripts/cdist index 81220ca3..d9dce35f 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -33,6 +33,7 @@ def commandline(): import cdist.config import cdist.install import cdist.shell + import cdist.inventory import shutil import os From c706b9eefba010e518dc1fdfbb1597545894a5a0 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 21 Jul 2017 10:19:02 +0300 Subject: [PATCH 0551/1332] check current timezone before doing anything --- .../conf/type/__timezone/explorer/timezone_is | 20 +++++++++++++++++++ cdist/conf/type/__timezone/gencode-remote | 9 +++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100755 cdist/conf/type/__timezone/explorer/timezone_is diff --git a/cdist/conf/type/__timezone/explorer/timezone_is b/cdist/conf/type/__timezone/explorer/timezone_is new file mode 100755 index 00000000..7e9de076 --- /dev/null +++ b/cdist/conf/type/__timezone/explorer/timezone_is @@ -0,0 +1,20 @@ +#!/bin/sh -e +# +# 2016 Ander Punnar (cdist at kvlt.ee) +# +# 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 . +# +cat /etc/timezone diff --git a/cdist/conf/type/__timezone/gencode-remote b/cdist/conf/type/__timezone/gencode-remote index d72da918..e512f861 100755 --- a/cdist/conf/type/__timezone/gencode-remote +++ b/cdist/conf/type/__timezone/gencode-remote @@ -20,11 +20,16 @@ # # This type allows to configure the desired localtime timezone. -timezone="$__object_id" +timezone_is=$(cat "$__object/explorer/timezone_is") +timezone_should="$__object_id" os=$(cat "$__global/explorer/os") +if [ "$timezone_is" = "$timezone_should" ]; then + exit 0 +fi + case "$os" in ubuntu|debian|devuan) - echo "echo \"$timezone\" > /etc/timezone" + echo "echo \"$timezone_should\" > /etc/timezone" ;; esac From 2c56622eebca26002f882bb2d17f20ccd27bc753 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 21 Jul 2017 10:22:54 +0300 Subject: [PATCH 0552/1332] check file first --- cdist/conf/type/__timezone/explorer/timezone_is | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__timezone/explorer/timezone_is b/cdist/conf/type/__timezone/explorer/timezone_is index 7e9de076..ec957139 100755 --- a/cdist/conf/type/__timezone/explorer/timezone_is +++ b/cdist/conf/type/__timezone/explorer/timezone_is @@ -17,4 +17,5 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -cat /etc/timezone + +[ -f /etc/timezone ] && cat /etc/timezone From 6bfe02094d960587d181d77437936189666d0248 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 21 Jul 2017 10:23:05 +0300 Subject: [PATCH 0553/1332] year is 2017 --- cdist/conf/type/__timezone/explorer/timezone_is | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__timezone/explorer/timezone_is b/cdist/conf/type/__timezone/explorer/timezone_is index ec957139..4e918121 100755 --- a/cdist/conf/type/__timezone/explorer/timezone_is +++ b/cdist/conf/type/__timezone/explorer/timezone_is @@ -1,6 +1,6 @@ #!/bin/sh -e # -# 2016 Ander Punnar (cdist at kvlt.ee) +# 2017 Ander Punnar (cdist at kvlt.ee) # # This file is part of cdist. # From 493150650c4c4751bc46cf459542ccc4c1339e07 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 21 Jul 2017 17:21:08 +0200 Subject: [PATCH 0554/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index b8c58adf..f4bfaffb 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Core: Add inventory functionality (Darko Poljak) * Core: Expose inventory host tags in __target_host_tags env var (Darko Poljak) + * Type __timezone: Check current timezone before doing anything (Ander Punnar) 4.5.0: 2017-07-20 * Types: Fix install types (Steven Armstrong) From 5ccfec9c18109c28b2386944f6d891128f05236c Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Fri, 21 Jul 2017 21:18:16 +0200 Subject: [PATCH 0555/1332] Updated to docker-compose version 1.14 --- cdist/conf/type/__docker_compose/parameter/default/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker_compose/parameter/default/version b/cdist/conf/type/__docker_compose/parameter/default/version index 0eed1a29..850e7424 100644 --- a/cdist/conf/type/__docker_compose/parameter/default/version +++ b/cdist/conf/type/__docker_compose/parameter/default/version @@ -1 +1 @@ -1.12.0 +1.14.0 From 4a54d1420ef7ea86e943ee3ae66071063da8b328 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 24 Jul 2017 19:12:43 +0200 Subject: [PATCH 0556/1332] Remove unwanted fixme --- cdist/exec/remote.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 9588db74..7a1fab3d 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -186,7 +186,6 @@ class Remote(object): cmd = self._exec.split() cmd.append(self.target_host[0]) - # FIXME: replace this by -o SendEnv name -o SendEnv name ... to ssh? # can't pass environment to remote side, so prepend command with # variable declarations From bb2cc68169d5107765ca4ea053f11624b3f0f876 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 24 Jul 2017 19:13:40 +0200 Subject: [PATCH 0557/1332] Fix broken text --- cdist/argparse.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 16b9d054..b065a179 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -152,9 +152,9 @@ def get_parsers(): parser['config_main'].add_argument( '-j', '--jobs', nargs='?', type=check_positive_int, - help=('Specify the maximum number of parallel jobs. Global' - 'explorers, object prepare and object run are supported' - '(currently in beta'), + help=('Specify the maximum number of parallel jobs. Global ' + 'explorers, object prepare and object run are supported ' + '(currently in beta)'), action='store', dest='jobs', const=multiprocessing.cpu_count()) parser['config_main'].add_argument( From 0af64c01bf438bcab808b93f973b0ef71b3c4989 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 25 Jul 2017 11:12:18 +0200 Subject: [PATCH 0558/1332] Add -p HOST_MAX argument. --- cdist/argparse.py | 19 ++++++++------ cdist/config.py | 55 +++++++++++++++++++++++++++++------------ docs/src/man1/cdist.rst | 17 +++++++------ 3 files changed, 61 insertions(+), 30 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index b065a179..d8b2c294 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -152,9 +152,10 @@ def get_parsers(): parser['config_main'].add_argument( '-j', '--jobs', nargs='?', type=check_positive_int, - help=('Specify the maximum number of parallel jobs. Global ' - 'explorers, object prepare and object run are supported ' - '(currently in beta)'), + help=('Operate in parallel in specified maximum number of jobs. ' + 'Global explorers, object prepare and object run are ' + 'supported. Without argument CPU count is used by default. ' + 'Currently in beta.'), action='store', dest='jobs', const=multiprocessing.cpu_count()) parser['config_main'].add_argument( @@ -204,13 +205,17 @@ def get_parsers(): 'default, read hosts from stdin.'), dest='hostfile', required=False) parser['config_args'].add_argument( - '-p', '--parallel', - help='operate on multiple hosts in parallel', - action='store_true', dest='parallel') + '-p', '--parallel', nargs='?', metavar='HOST_MAX', + type=check_positive_int, + help=('Operate on multiple hosts in parallel for specified maximum ' + 'hosts at a time. Without argument CPU count is used by ' + 'default.'), + action='store', dest='parallel', + const=multiprocessing.cpu_count()) parser['config_args'].add_argument( '-s', '--sequential', help='operate on multiple hosts sequentially (default)', - action='store_false', dest='parallel') + action='store_const', dest='parallel', const=0) parser['config_args'].add_argument( '-t', '--tag', help=('host is specified by tag, not hostname/address; ' diff --git a/cdist/config.py b/cdist/config.py index 2c9721f5..f153ced5 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -129,7 +129,6 @@ class Config(object): cls._check_and_prepare_args(args) - process = {} failed_hosts = [] time_start = time.time() @@ -153,6 +152,16 @@ class Config(object): else: it = itertools.chain(cls.hosts(args.host), cls.hosts(args.hostfile)) + + process_args = [] + # No new child process if only one host at a time. + if args.parallel == 1: + log.debug("Only 1 parallel process, doing it sequentially") + args.parallel = 0 + if args.parallel: + log.trace("Processing hosts in parallel") + else: + log.trace("Processing hosts sequentially") for entry in it: if isinstance(entry, tuple): # if configuring by specified tags @@ -178,27 +187,37 @@ class Config(object): hostcnt += 1 if args.parallel: - log.trace("Creating child process for %s", host) - process[host] = multiprocessing.Process( - target=cls.onehost, - args=(host, host_tags, host_base_path, hostdir, args, - True)) - process[host].start() + pargs = (host, host_tags, host_base_path, hostdir, args, True) + log.trace(("Args for multiprocessing operation " + "for host {}: {}".format(host, pargs))) + process_args.append(pargs) else: try: cls.onehost(host, host_tags, host_base_path, hostdir, args, parallel=False) except cdist.Error as e: failed_hosts.append(host) - + if args.parallel and len(process_args) == 1: + log.debug("Only 1 host for parallel processing, doing it " + "sequentially") + try: + cls.onehost(*process_args[0]) + except cdist.Error as e: + failed_hosts.append(host) # Catch errors in parallel mode when joining if args.parallel: - for host in process.keys(): - log.trace("Joining process %s", host) - process[host].join() + log.trace("Multiprocessing start method is {}".format( + multiprocessing.get_start_method())) + log.trace(("Starting multiprocessing Pool for {} " + "parallel host operation".format(args.parallel))) - if not process[host].exitcode == 0: - failed_hosts.append(host) + results = mp_pool_run(cls.onehost, process_args, jobs=args.parallel) + log.trace(("Multiprocessing for parallel host operation " + "finished")) + log.trace(("Multiprocessing for parallel host operation " + "results: {}", results)) + + failed_hosts = [host for host, result in results if not result] time_end = time.time() log.verbose("Total processing time for %s host(s): %s", hostcnt, @@ -236,7 +255,10 @@ class Config(object): @classmethod def onehost(cls, host, host_tags, host_base_path, host_dir_name, args, parallel): - """Configure ONE system""" + """Configure ONE system. + If operating in parallel then return tuple (host, True|False, ) + so that main process knows for which host function was successful. + """ log = logging.getLogger(host) @@ -273,8 +295,7 @@ class Config(object): except cdist.Error as e: log.error(e) if parallel: - # We are running in our own process here, need to sys.exit! - sys.exit(1) + return (host, False, ) else: raise @@ -285,6 +306,8 @@ class Config(object): # Pass back to controlling code in sequential mode else: raise + if parallel: + return (host, True, ) @staticmethod def create_base_root_path(out_path=None): diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index d6bd1c8f..829b3824 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -19,14 +19,14 @@ SYNOPSIS [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] - [-f HOSTFILE] [-p] [-s] [-t] + [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] [host [host ...]] cdist install [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] - [-f HOSTFILE] [-p] [-s] [-t] + [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] [host [host ...]] cdist inventory [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] @@ -153,9 +153,10 @@ Configure/install one or more hosts. .. option:: -j [JOBS], --jobs [JOBS] - Specify the maximum number of parallel jobs. Global - explorers, object prepare and object run are supported - (currently in beta). + Operate in parallel in specified maximum number of + jobs. Global explorers, object prepare and object run + are supported. Without argument CPU count is used by + default. Currently in beta. .. option:: -n, --dry-run @@ -165,9 +166,11 @@ Configure/install one or more hosts. Directory to save cdist output in -.. option:: -p, --parallel +.. option:: -p [HOST_MAX], --parallel [HOST_MAX] - Operate on multiple hosts in parallel + Operate on multiple hosts in parallel for specified + maximum hosts at a time. Without argument CPU count is + used by default. .. option:: -r REMOTE_OUT_PATH, --remote-out-dir REMOTE_OUT_PATH From 32838a096d444142e27e30dccc1b96f1e6e03004 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 25 Jul 2017 12:40:12 +0200 Subject: [PATCH 0559/1332] Refine inventory logging to adhere new cdist logging. --- cdist/inventory.py | 48 +++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/cdist/inventory.py b/cdist/inventory.py index ccb4428f..32fbabdb 100644 --- a/cdist/inventory.py +++ b/cdist/inventory.py @@ -86,7 +86,7 @@ class Inventory(object): self.init_db() def init_db(self): - self.log.debug("Init db: {}".format(self.db_basedir)) + self.log.trace("Init db: {}".format(self.db_basedir)) if not os.path.exists(self.db_basedir): os.makedirs(self.db_basedir, exist_ok=True) elif not os.path.isdir(self.db_basedir): @@ -168,14 +168,14 @@ class Inventory(object): @classmethod def commandline(cls, args): """Manipulate inventory db""" - log = logging.getLogger("cdist") + log = logging.getLogger("inventory") if 'taglist' in args: args.taglist = cls.strlist_to_list(args.taglist) determine_default_inventory_dir(args) - log.info("Using inventory: {}".format(args.inventory_dir)) - log.debug("Inventory args: {}".format(vars(args))) - log.debug("Inventory command: {}".format(args.subcommand)) + log.debug("Using inventory: {}".format(args.inventory_dir)) + log.trace("Inventory args: {}".format(vars(args))) + log.trace("Inventory command: {}".format(args.subcommand)) if args.subcommand == "list": c = InventoryList(hosts=args.host, istag=args.tag, @@ -225,22 +225,22 @@ class InventoryList(Inventory): def _do_list(self, it_tags, it_hosts, check_func): if (it_tags is not None): param_tags = set(it_tags) - self.log.debug("param_tags: {}".format(param_tags)) + self.log.trace("param_tags: {}".format(param_tags)) else: param_tags = set() for host in it_hosts: - self.log.debug("host: {}".format(host)) + self.log.trace("host: {}".format(host)) tags = self._get_host_tags(host) if tags is None: - self.log.info("Host \'{}\' not found, skipped".format(host)) + self.log.debug("Host \'{}\' not found, skipped".format(host)) continue - self.log.debug("tags: {}".format(tags)) + self.log.trace("tags: {}".format(tags)) if check_func(tags, param_tags): yield host, tags def entries(self): if not self.hosts and not self.hostfile: - self.log.info("Listing all hosts") + self.log.trace("Listing all hosts") it_hosts = self._all_hosts() it_tags = None check_func = check_always_true @@ -248,7 +248,7 @@ class InventoryList(Inventory): it = itertools.chain(self._input_values(self.hosts), self._input_values(self.hostfile)) if self.istag: - self.log.info("Listing by tag(s)") + self.log.trace("Listing by tag(s)") it_hosts = self._all_hosts() it_tags = it if self.has_all_tags: @@ -256,7 +256,7 @@ class InventoryList(Inventory): else: check_func = contains_any else: - self.log.info("Listing by host(s)") + self.log.trace("Listing by host(s)") it_hosts = it it_tags = None check_func = check_always_true @@ -295,11 +295,11 @@ class InventoryHost(Inventory): def _action(self, host): if self.action == "add": - self.log.info("Adding host \'{}\'".format(host)) + self.log.debug("Adding host \'{}\'".format(host)) elif self.action == "del": - self.log.info("Deleting host \'{}\'".format(host)) + self.log.debug("Deleting host \'{}\'".format(host)) hostpath = self._host_path(host) - self.log.debug("hostpath: {}".format(hostpath)) + self.log.trace("hostpath: {}".format(hostpath)) if self.action == "add" and not os.path.exists(hostpath): self._new_hostpath(hostpath) else: @@ -311,10 +311,10 @@ class InventoryHost(Inventory): def run(self): if self.action == "del" and self.all: - self.log.debug("Doing for all hosts") + self.log.trace("Doing for all hosts") it = self._all_hosts() else: - self.log.debug("Doing for specified hosts") + self.log.trace("Doing for specified hosts") it = itertools.chain(self._input_values(self.hosts), self._input_values(self.hostfile)) for host in it: @@ -358,30 +358,30 @@ class InventoryTag(Inventory): print("Host \'{}\' does not exist, skipping".format(host), file=sys.stderr) return - self.log.debug("existing host_tags: {}".format(host_tags)) + self.log.trace("existing host_tags: {}".format(host_tags)) if self.action == "del" and self.all: host_tags = set() else: for tag in self.input_tags: if self.action == "add": - self.log.info("Adding tag \'{}\' for host \'{}\'".format( + self.log.debug("Adding tag \'{}\' for host \'{}\'".format( tag, host)) host_tags.add(tag) elif self.action == "del": - self.log.info("Deleting tag \'{}\' for host \'{}\'".format( + self.log.debug("Deleting tag \'{}\' for host \'{}\'".format( tag, host)) if tag in host_tags: host_tags.remove(tag) - self.log.debug("new host tags: {}".format(host_tags)) + self.log.trace("new host tags: {}".format(host_tags)) if not self._write_host_tags(host, host_tags): - self.log.info("{} does not exist, skipped".format(host)) + self.log.trace("{} does not exist, skipped".format(host)) def run(self): if self.allhosts: - self.log.debug("Doing for all hosts") + self.log.trace("Doing for all hosts") it = self._all_hosts() else: - self.log.debug("Doing for specified hosts") + self.log.trace("Doing for specified hosts") it = itertools.chain(self._input_values(self.hosts), self._input_values(self.hostfile)) if not(self.action == "del" and self.all): From d30b1a2f54d12df4c9dd3265e61ae92355911882 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 25 Jul 2017 12:41:58 +0200 Subject: [PATCH 0560/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index f4bfaffb..d029b42b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Core: Add inventory functionality (Darko Poljak) * Core: Expose inventory host tags in __target_host_tags env var (Darko Poljak) * Type __timezone: Check current timezone before doing anything (Ander Punnar) + * Core: Add -p HOST_MAX argument (Darko Poljak) 4.5.0: 2017-07-20 * Types: Fix install types (Steven Armstrong) From 7c7a98d0836acff05472ab54b0c0a81783a73126 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 25 Jul 2017 12:43:54 +0200 Subject: [PATCH 0561/1332] pep8 --- cdist/config.py | 12 +++++++----- cdist/inventory.py | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index f153ced5..ca8dcfec 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -189,7 +189,7 @@ class Config(object): if args.parallel: pargs = (host, host_tags, host_base_path, hostdir, args, True) log.trace(("Args for multiprocessing operation " - "for host {}: {}".format(host, pargs))) + "for host {}: {}".format(host, pargs))) process_args.append(pargs) else: try: @@ -209,13 +209,15 @@ class Config(object): log.trace("Multiprocessing start method is {}".format( multiprocessing.get_start_method())) log.trace(("Starting multiprocessing Pool for {} " - "parallel host operation".format(args.parallel))) + "parallel host operation".format(args.parallel))) - results = mp_pool_run(cls.onehost, process_args, jobs=args.parallel) + results = mp_pool_run(cls.onehost, + process_args, + jobs=args.parallel) log.trace(("Multiprocessing for parallel host operation " - "finished")) + "finished")) log.trace(("Multiprocessing for parallel host operation " - "results: {}", results)) + "results: {}", results)) failed_hosts = [host for host, result in results if not result] diff --git a/cdist/inventory.py b/cdist/inventory.py index 32fbabdb..c9602e23 100644 --- a/cdist/inventory.py +++ b/cdist/inventory.py @@ -368,8 +368,8 @@ class InventoryTag(Inventory): tag, host)) host_tags.add(tag) elif self.action == "del": - self.log.debug("Deleting tag \'{}\' for host \'{}\'".format( - tag, host)) + self.log.debug("Deleting tag \'{}\' for host " + "\'{}\'".format(tag, host)) if tag in host_tags: host_tags.remove(tag) self.log.trace("new host tags: {}".format(host_tags)) From d1a044cc237d9b929c41b67deec0e6b8cd33760a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 26 Jul 2017 12:01:19 +0200 Subject: [PATCH 0562/1332] multiprocessing.Pool -> concurrent.futures.ProcessPoolExecutor --- cdist/config.py | 36 +++++++++++++++++++++++------------- cdist/mputil.py | 37 ++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index ca8dcfec..d6f8a482 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -124,6 +124,27 @@ class Config(object): def commandline(cls, args): """Configure remote system""" + # No new child process if only one host at a time. + if args.parallel == 1: + log.debug("Only 1 parallel process, doing it sequentially") + args.parallel = 0 + + if args.parallel or args.jobs: + # If parallel execution then also log process id + del logging.getLogger().handlers[:] + log_format = '%(levelname)s: [%(process)d]: %(message)s' + logging.basicConfig(format=log_format) + + if args.parallel: + import signal + + def sigterm_handler(signum, frame): + log.trace("signal %s, killing whole process group", signum) + os.killpg(os.getpgrp(), signal.SIGKILL) + + signal.signal(signal.SIGTERM, sigterm_handler) + signal.signal(signal.SIGHUP, sigterm_handler) + # FIXME: Refactor relict - remove later log = logging.getLogger("cdist") @@ -154,10 +175,6 @@ class Config(object): cls.hosts(args.hostfile)) process_args = [] - # No new child process if only one host at a time. - if args.parallel == 1: - log.debug("Only 1 parallel process, doing it sequentially") - args.parallel = 0 if args.parallel: log.trace("Processing hosts in parallel") else: @@ -216,8 +233,8 @@ class Config(object): jobs=args.parallel) log.trace(("Multiprocessing for parallel host operation " "finished")) - log.trace(("Multiprocessing for parallel host operation " - "results: {}", results)) + log.trace("Multiprocessing for parallel host operation " + "results: %s", results) failed_hosts = [host for host, result in results if not result] @@ -301,13 +318,6 @@ class Config(object): else: raise - except KeyboardInterrupt: - # Ignore in parallel mode, we are existing anyway - if parallel: - sys.exit(0) - # Pass back to controlling code in sequential mode - else: - raise if parallel: return (host, True, ) diff --git a/cdist/mputil.py b/cdist/mputil.py index e564d749..d823e192 100644 --- a/cdist/mputil.py +++ b/cdist/mputil.py @@ -21,14 +21,21 @@ import multiprocessing +import concurrent.futures as cf import itertools +import os +import signal +import logging + + +log = logging.getLogger("cdist-mputil") def mp_pool_run(func, args=None, kwds=None, jobs=multiprocessing.cpu_count()): - """ Run func using multiprocessing.Pool with jobs jobs and supplied - iterable of args and kwds with one entry for each parallel func - instance. - Return list of results. + """Run func using concurrent.futures.ProcessPoolExecutor with jobs jobs + and supplied iterables of args and kwds with one entry for each + parallel func instance. + Return list of results. """ if args and kwds: fargs = zip(args, kwds) @@ -39,10 +46,18 @@ def mp_pool_run(func, args=None, kwds=None, jobs=multiprocessing.cpu_count()): else: return [func(), ] - with multiprocessing.Pool(jobs) as pool: - results = [ - pool.apply_async(func, a, k) - for a, k in fargs - ] - retval = [r.get() for r in results] - return retval + retval = [] + with cf.ProcessPoolExecutor(jobs) as executor: + try: + results = [ + executor.submit(func, *a, **k) for a, k in fargs + ] + for f in cf.as_completed(results): + retval.append(f.result()) + return retval + except KeyboardInterrupt: + log.trace("KeyboardInterrupt, killing process group") + # When Ctrl+C in terminal then kill whole process group. + # Otherwise there remain processes in sleeping state. + os.killpg(os.getpgrp(), signal.SIGKILL) + raise From 23fbabe303ede09812fad7ea285a12aac518f7a6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 26 Jul 2017 17:39:07 +0200 Subject: [PATCH 0563/1332] Further improve parallel execution. --- cdist/config.py | 13 ++++--------- cdist/mputil.py | 12 +++++++----- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index d6f8a482..5fbb818e 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -29,7 +29,7 @@ import itertools import tempfile import socket import multiprocessing -from cdist.mputil import mp_pool_run +from cdist.mputil import mp_pool_run, mp_sig_handler import atexit import shutil @@ -138,12 +138,8 @@ class Config(object): if args.parallel: import signal - def sigterm_handler(signum, frame): - log.trace("signal %s, killing whole process group", signum) - os.killpg(os.getpgrp(), signal.SIGKILL) - - signal.signal(signal.SIGTERM, sigterm_handler) - signal.signal(signal.SIGHUP, sigterm_handler) + signal.signal(signal.SIGTERM, mp_sig_handler) + signal.signal(signal.SIGHUP, mp_sig_handler) # FIXME: Refactor relict - remove later log = logging.getLogger("cdist") @@ -221,8 +217,7 @@ class Config(object): cls.onehost(*process_args[0]) except cdist.Error as e: failed_hosts.append(host) - # Catch errors in parallel mode when joining - if args.parallel: + elif args.parallel: log.trace("Multiprocessing start method is {}".format( multiprocessing.get_start_method())) log.trace(("Starting multiprocessing Pool for {} " diff --git a/cdist/mputil.py b/cdist/mputil.py index d823e192..56fcfe39 100644 --- a/cdist/mputil.py +++ b/cdist/mputil.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2016 Darko Poljak (darko.poljak at gmail.com) +# 2016-2017 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -31,6 +31,11 @@ import logging log = logging.getLogger("cdist-mputil") +def mp_sig_handler(signum, frame): + log.trace("signal %s, SIGKILL whole process group", signum) + os.killpg(os.getpgrp(), signal.SIGKILL) + + def mp_pool_run(func, args=None, kwds=None, jobs=multiprocessing.cpu_count()): """Run func using concurrent.futures.ProcessPoolExecutor with jobs jobs and supplied iterables of args and kwds with one entry for each @@ -56,8 +61,5 @@ def mp_pool_run(func, args=None, kwds=None, jobs=multiprocessing.cpu_count()): retval.append(f.result()) return retval except KeyboardInterrupt: - log.trace("KeyboardInterrupt, killing process group") - # When Ctrl+C in terminal then kill whole process group. - # Otherwise there remain processes in sleeping state. - os.killpg(os.getpgrp(), signal.SIGKILL) + mp_sig_handler(signal.SIGINT, None) raise From b7b1101f112a100972130a286974acc684df83b9 Mon Sep 17 00:00:00 2001 From: Ander Punnar <4ND3R@users.noreply.github.com> Date: Thu, 27 Jul 2017 01:28:26 +0300 Subject: [PATCH 0564/1332] always exit 0 --- cdist/conf/type/__timezone/explorer/timezone_is | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__timezone/explorer/timezone_is b/cdist/conf/type/__timezone/explorer/timezone_is index 4e918121..a1aa813f 100755 --- a/cdist/conf/type/__timezone/explorer/timezone_is +++ b/cdist/conf/type/__timezone/explorer/timezone_is @@ -19,3 +19,5 @@ # [ -f /etc/timezone ] && cat /etc/timezone + +exit 0 From 0d734c872d443dd036098c1b5969f67f184d623d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 27 Jul 2017 09:36:00 +0200 Subject: [PATCH 0565/1332] Fix log var assignment. --- cdist/config.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 5fbb818e..e44dc7cb 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -124,6 +124,9 @@ class Config(object): def commandline(cls, args): """Configure remote system""" + # FIXME: Refactor relict - remove later + log = logging.getLogger("cdist") + # No new child process if only one host at a time. if args.parallel == 1: log.debug("Only 1 parallel process, doing it sequentially") @@ -134,6 +137,7 @@ class Config(object): del logging.getLogger().handlers[:] log_format = '%(levelname)s: [%(process)d]: %(message)s' logging.basicConfig(format=log_format) + log = logging.getLogger("cdist") if args.parallel: import signal @@ -141,9 +145,6 @@ class Config(object): signal.signal(signal.SIGTERM, mp_sig_handler) signal.signal(signal.SIGHUP, mp_sig_handler) - # FIXME: Refactor relict - remove later - log = logging.getLogger("cdist") - cls._check_and_prepare_args(args) failed_hosts = [] From 0a85d913cc4497606fbbad99e5db8222b2f70799 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 27 Jul 2017 09:49:06 +0200 Subject: [PATCH 0566/1332] Optimize dir transfer. --- cdist/exec/remote.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 7a1fab3d..8b10b324 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -139,12 +139,16 @@ class Remote(object): _wrap_addr(self.target_host[0]), destination)]) self._run_command(command) - def _transfer_dir_sequential(self, source, destination): + def _transfer_dir_commands(self, source, destination): for f in glob.glob1(source, '*'): command = self._copy.split() path = os.path.join(source, f) command.extend([path, '{0}:{1}'.format( _wrap_addr(self.target_host[0]), destination)]) + yield command + + def _transfer_dir_sequential(self, source, destination): + for command in self._transfer_dir_commands: self._run_command(command) def _transfer_dir_parallel(self, source, destination, jobs): @@ -155,14 +159,12 @@ class Remote(object): multiprocessing.get_start_method())) self.log.trace(("Starting multiprocessing Pool for parallel " "remote transfer")) - args = [] - for f in glob.glob1(source, '*'): - command = self._copy.split() - path = os.path.join(source, f) - command.extend([path, '{0}:{1}'.format( - _wrap_addr(self.target_host[0]), destination)]) - args.append((command, )) - mp_pool_run(self._run_command, args, jobs=jobs) + args = [(command, ) for command in self._transfer_dir_commands] + if len(args) == 1: + self.log.debug("Only one dir entry, transfering sequentially") + self._run_command(args[0]) + else: + mp_pool_run(self._run_command, args, jobs=jobs) self.log.trace(("Multiprocessing for parallel transfer " "finished")) From 1b0f560608d6da57da0f56b959a2db9d7b677de7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 27 Jul 2017 09:51:23 +0200 Subject: [PATCH 0567/1332] Add missing args to method call. --- cdist/exec/remote.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 8b10b324..10add276 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -148,7 +148,7 @@ class Remote(object): yield command def _transfer_dir_sequential(self, source, destination): - for command in self._transfer_dir_commands: + for command in self._transfer_dir_commands(source, destination): self._run_command(command) def _transfer_dir_parallel(self, source, destination, jobs): @@ -159,7 +159,10 @@ class Remote(object): multiprocessing.get_start_method())) self.log.trace(("Starting multiprocessing Pool for parallel " "remote transfer")) - args = [(command, ) for command in self._transfer_dir_commands] + args = [ + (command, ) + for command in self._transfer_dir_commands(source, destination) + ] if len(args) == 1: self.log.debug("Only one dir entry, transfering sequentially") self._run_command(args[0]) From 260303dd14e44992972f47952238d0743c11eddb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 3 Aug 2017 15:11:35 +0200 Subject: [PATCH 0568/1332] Fix gpasswd call in __user_groups: order incorrect From the manpage: -a, --add user Add the user to the named group. -d, --delete user Remove the user from the named group. --- cdist/conf/type/__user_groups/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__user_groups/gencode-remote b/cdist/conf/type/__user_groups/gencode-remote index 5518f333..a69d6997 100755 --- a/cdist/conf/type/__user_groups/gencode-remote +++ b/cdist/conf/type/__user_groups/gencode-remote @@ -59,8 +59,8 @@ for group in $changed_groups; do esac else case "$state_should" in - present) echo "gpasswd -a \"$group\" \"$user\"" ;; - absent) echo "gpasswd -d \"$group\" \"$user\"" ;; + present) echo "gpasswd -a \"$user\" \"$group\"" ;; + absent) echo "gpasswd -d \"$user\" \"$group\"" ;; esac fi done From 68cb13881f1df966f6086f5904934398731a5c55 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 4 Aug 2017 12:51:03 +0200 Subject: [PATCH 0569/1332] Add archiving support. --- cdist/argparse.py | 11 +- cdist/autil.py | 71 +++++++++ cdist/config.py | 3 +- cdist/exec/remote.py | 78 ++++++++-- cdist/test/autil/__init__.py | 57 +++++++ cdist/test/autil/fixtures/explorer/cpu_cores | 40 +++++ .../test/autil/fixtures/explorer/cpu_sockets | 40 +++++ cdist/test/autil/fixtures/explorer/disks | 2 + cdist/test/autil/fixtures/explorer/hostname | 25 +++ cdist/test/autil/fixtures/explorer/init | 35 +++++ cdist/test/autil/fixtures/explorer/interfaces | 51 +++++++ .../test/autil/fixtures/explorer/kernel_name | 1 + .../test/autil/fixtures/explorer/lsb_codename | 33 ++++ .../autil/fixtures/explorer/lsb_description | 33 ++++ cdist/test/autil/fixtures/explorer/lsb_id | 33 ++++ .../test/autil/fixtures/explorer/lsb_release | 33 ++++ cdist/test/autil/fixtures/explorer/machine | 27 ++++ .../test/autil/fixtures/explorer/machine_type | 66 ++++++++ cdist/test/autil/fixtures/explorer/memory | 36 +++++ cdist/test/autil/fixtures/explorer/os | 143 ++++++++++++++++++ cdist/test/autil/fixtures/explorer/os_version | 73 +++++++++ cdist/test/autil/fixtures/explorer/runlevel | 26 ++++ 22 files changed, 906 insertions(+), 11 deletions(-) create mode 100644 cdist/autil.py create mode 100644 cdist/test/autil/__init__.py create mode 100755 cdist/test/autil/fixtures/explorer/cpu_cores create mode 100755 cdist/test/autil/fixtures/explorer/cpu_sockets create mode 100644 cdist/test/autil/fixtures/explorer/disks create mode 100755 cdist/test/autil/fixtures/explorer/hostname create mode 100755 cdist/test/autil/fixtures/explorer/init create mode 100755 cdist/test/autil/fixtures/explorer/interfaces create mode 100644 cdist/test/autil/fixtures/explorer/kernel_name create mode 100755 cdist/test/autil/fixtures/explorer/lsb_codename create mode 100755 cdist/test/autil/fixtures/explorer/lsb_description create mode 100755 cdist/test/autil/fixtures/explorer/lsb_id create mode 100755 cdist/test/autil/fixtures/explorer/lsb_release create mode 100755 cdist/test/autil/fixtures/explorer/machine create mode 100755 cdist/test/autil/fixtures/explorer/machine_type create mode 100755 cdist/test/autil/fixtures/explorer/memory create mode 100755 cdist/test/autil/fixtures/explorer/os create mode 100755 cdist/test/autil/fixtures/explorer/os_version create mode 100755 cdist/test/autil/fixtures/explorer/runlevel diff --git a/cdist/argparse.py b/cdist/argparse.py index d8b2c294..4d9dc719 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -10,7 +10,7 @@ import collections BETA_COMMANDS = set(('install', 'inventory', )) # set of beta arguments for sub-commands BETA_ARGS = { - 'config': set(('jobs', 'tag', 'all_tagged_hosts', )), + 'config': set(('jobs', 'tag', 'all_tagged_hosts', 'use_archiving', )), } EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/" # Parser others can reuse @@ -164,6 +164,15 @@ def get_parsers(): parser['config_main'].add_argument( '-o', '--out-dir', help='directory to save cdist output in', dest="out_path") + parser['config_main'].add_argument( + '-R', '--use-archiving', nargs='?', + choices=('tar', 'tgz', 'tbz2', 'txz',), + help=('Operate by using archiving with compression where ' + 'apropriate. Supported values are: tar - tar archive, ' + 'tgz - gzip tar archive (the default), ' + 'tbz2 - bzip2 tar archive and txz - lzma tar archive.'), + action='store', dest='use_archiving', + const='tgz') # remote-copy and remote-exec defaults are environment variables # if set; if not then None - these will be futher handled after diff --git a/cdist/autil.py b/cdist/autil.py new file mode 100644 index 00000000..d16d147e --- /dev/null +++ b/cdist/autil.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# +# 2017 Darko Poljak (darko.poljak 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 . +# +# + + +import cdist +import tarfile +import os +import glob +import tempfile + + +_ARCHIVING_MODES = { + 'tar': '', + 'tgz': 'gz', + 'tbz2': 'bz2', + 'txz': 'xz', +} + + +_UNARCHIVE_OPT = { + 'tar': None, + 'tgz': '-z', + 'tbz2': '-j', + 'txz': '-J', +} + + +# Archiving will be enabled if directory contains more than FILES_LIMIT files. +FILES_LIMIT = 1 + + +def get_extract_option(mode): + return _UNARCHIVE_OPT[mode] + + +def tar(source, mode="tgz"): + if mode not in _ARCHIVING_MODES: + raise cdist.Error("Unsupported archiving mode {}.".format(mode)) + + files = glob.glob1(source, '*') + fcnt = len(files) + if fcnt <= FILES_LIMIT: + return None, fcnt + + tarmode = 'w:{}'.format(_ARCHIVING_MODES[mode]) + _, tarpath = tempfile.mkstemp(suffix='.' + mode) + with tarfile.open(tarpath, tarmode, dereference=True) as tar: + if os.path.isdir(source): + for f in files: + tar.add(os.path.join(source, f), arcname=f) + else: + tar.add(source) + return tarpath, fcnt diff --git a/cdist/config.py b/cdist/config.py index e44dc7cb..aab298f7 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -302,7 +302,8 @@ class Config(object): remote_exec=remote_exec, remote_copy=remote_copy, base_path=args.remote_out_path, - quiet_mode=args.quiet) + quiet_mode=args.quiet, + archiving_mode=args.use_archiving) c = cls(local, remote, dry_run=args.dry_run, jobs=args.jobs) c.run() diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 10add276..10b43e15 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -63,7 +63,8 @@ class Remote(object): remote_exec, remote_copy, base_path=None, - quiet_mode=None): + quiet_mode=None, + archiving_mode=None): self.target_host = target_host self._exec = remote_exec self._copy = remote_copy @@ -73,6 +74,7 @@ class Remote(object): else: self.base_path = "/var/lib/cdist" self.quiet_mode = quiet_mode + self.archiving_mode = archiving_mode self.conf_path = os.path.join(self.base_path, "conf") self.object_path = os.path.join(self.base_path, "object") @@ -111,6 +113,11 @@ class Remote(object): self.run(["chmod", "0700", self.base_path]) self.mkdir(self.conf_path) + def rmfile(self, path): + """Remove file on the remote side.""" + self.log.trace("Remote rm: %s", path) + self.run(["rm", "-f", path]) + def rmdir(self, path): """Remove directory on the remote side.""" self.log.trace("Remote rmdir: %s", path) @@ -121,23 +128,76 @@ class Remote(object): self.log.trace("Remote mkdir: %s", path) self.run(["mkdir", "-p", path]) + def extract_archive(self, path, mode): + """Extract archive path on the remote side.""" + import cdist.autil as autil + + self.log.trace("Remote extract archive: %s", path) + command = ["tar", "-x", "-m", "-C", ] + directory = os.path.dirname(path) + command.append(directory) + xopt = autil.get_extract_option(mode) + if xopt: + command.append(xopt) + command.append("-f") + command.append(path) + self.run(command) + + def _transfer_file(self, source, destination): + command = self._copy.split() + command.extend([source, '{0}:{1}'.format( + _wrap_addr(self.target_host[0]), destination)]) + self._run_command(command) + def transfer(self, source, destination, jobs=None): """Transfer a file or directory to the remote side.""" self.log.trace("Remote transfer: %s -> %s", source, destination) # self.rmdir(destination) if os.path.isdir(source): self.mkdir(destination) - if jobs: - self._transfer_dir_parallel(source, destination, jobs) - else: - self._transfer_dir_sequential(source, destination) + used_archiving = False + if self.archiving_mode: + self.log.trace("Remote transfer in archiving mode") + import cdist.autil as autil + + # create archive + tarpath, fcnt = autil.tar(source, self.archiving_mode) + if tarpath is None: + self.log.trace(("Files count {} is lower than {} limit, " + "skipping archiving").format( + fcnt, autil.FILES_LIMIT)) + else: + self.log.trace(("Archiving mode, tarpath: %s, file count: " + "%s"), tarpath, fcnt) + # get archive name + tarname = os.path.basename(tarpath) + self.log.trace("Archiving mode tarname: %s", tarname) + # archive path at the remote + desttarpath = os.path.join(destination, tarname) + self.log.trace( + "Archiving mode desttarpath: %s", desttarpath) + # transfer archive to the remote side + self.log.trace("Archiving mode: transfering") + self._transfer_file(tarpath, desttarpath) + # extract archive at the remote + self.log.trace("Archiving mode: extracting") + self.extract_archive(desttarpath, self.archiving_mode) + # remove remote archive + self.log.trace("Archiving mode: removing remote archive") + self.rmfile(desttarpath) + # remove local archive + self.log.trace("Archiving mode: removing local archive") + os.remove(tarpath) + used_archiving = True + if not used_archiving: + if jobs: + self._transfer_dir_parallel(source, destination, jobs) + else: + self._transfer_dir_sequential(source, destination) elif jobs: raise cdist.Error("Source {} is not a directory".format(source)) else: - command = self._copy.split() - command.extend([source, '{0}:{1}'.format( - _wrap_addr(self.target_host[0]), destination)]) - self._run_command(command) + self._transfer_file(source, destination) def _transfer_dir_commands(self, source, destination): for f in glob.glob1(source, '*'): diff --git a/cdist/test/autil/__init__.py b/cdist/test/autil/__init__.py new file mode 100644 index 00000000..28989058 --- /dev/null +++ b/cdist/test/autil/__init__.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +# 2017 Darko Poljak (darko.poljak 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 . +# +# + +from cdist import test +import cdist.autil as autil +import os +import os.path as op +import tarfile + + +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +explorers_path = op.join(fixtures, 'explorer') + + +class AUtilTestCase(test.CdistTestCase): + def test_tar(self): + test_modes = { + 'tar': 'r:', + 'tgz': 'r:gz', + 'tbz2': 'r:bz2', + 'txz': 'r:xz', + } + source = explorers_path + for mode in test_modes: + tarpath = autil.tar(source, mode) + self.assertIsNotNone(tarpath) + fcnt = 0 + with tarfile.open(tarpath, test_modes[mode]) as tar: + for tarinfo in tar: + fcnt += 1 + os.remove(tarpath) + self.assertGreater(fcnt, 0) + + +if __name__ == "__main__": + import unittest + + unittest.main() diff --git a/cdist/test/autil/fixtures/explorer/cpu_cores b/cdist/test/autil/fixtures/explorer/cpu_cores new file mode 100755 index 00000000..7f7a955e --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/cpu_cores @@ -0,0 +1,40 @@ +#!/bin/sh +# +# 2014 Daniel Heule (hda at sfs.biz) +# 2014 Thomas Oettli (otho at sfs.biz) +# +# 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 . +# +# + +# FIXME: other system types (not linux ...) + +os=$("$__explorer/os") +case "$os" in + "macosx") + echo "$(sysctl -n hw.physicalcpu)" + ;; + + *) + if [ -r /proc/cpuinfo ]; then + cores="$(grep "core id" /proc/cpuinfo | sort | uniq | wc -l)" + if [ ${cores} -eq 0 ]; then + cores="1" + fi + echo "$cores" + fi + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/cpu_sockets b/cdist/test/autil/fixtures/explorer/cpu_sockets new file mode 100755 index 00000000..8a8194df --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/cpu_sockets @@ -0,0 +1,40 @@ +#!/bin/sh +# +# 2014 Daniel Heule (hda at sfs.biz) +# 2014 Thomas Oettli (otho at sfs.biz) +# +# 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 . +# +# + +# FIXME: other system types (not linux ...) + +os=$("$__explorer/os") +case "$os" in + "macosx") + echo "$(system_profiler SPHardwareDataType | grep "Number of Processors" | awk -F': ' '{print $2}')" + ;; + + *) + if [ -r /proc/cpuinfo ]; then + sockets="$(grep "physical id" /proc/cpuinfo | sort | uniq | wc -l)" + if [ ${sockets} -eq 0 ]; then + sockets="$(cat /proc/cpuinfo | grep "processor" | wc -l)" + fi + echo "${sockets}" + fi + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/disks b/cdist/test/autil/fixtures/explorer/disks new file mode 100644 index 00000000..52fef81e --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/disks @@ -0,0 +1,2 @@ +cd /dev +echo sd? hd? vd? diff --git a/cdist/test/autil/fixtures/explorer/hostname b/cdist/test/autil/fixtures/explorer/hostname new file mode 100755 index 00000000..7715c6b0 --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/hostname @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2010-2014 Nico Schottelius (nico-cdist at schottelius.org) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 command -v uname >/dev/null; then + uname -n +fi diff --git a/cdist/test/autil/fixtures/explorer/init b/cdist/test/autil/fixtures/explorer/init new file mode 100755 index 00000000..2693a0d3 --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/init @@ -0,0 +1,35 @@ +#!/bin/sh +# +# 2016 Daniel Heule (hda at sfs.biz) +# +# 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 . +# +# +# Returns the process name of pid 1 ( normaly the init system ) +# for example at linux this value is "init" or "systemd" in most cases +# + +uname_s="$(uname -s)" + +case "$uname_s" in + Linux|FreeBSD) + ps -o comm= -p 1 || true + ;; + *) + # return a empty string as unknown value + echo "" + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/interfaces b/cdist/test/autil/fixtures/explorer/interfaces new file mode 100755 index 00000000..c1f2a57a --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/interfaces @@ -0,0 +1,51 @@ +#!/bin/sh +# +# 2012 Sébastien Gross +# +# 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 . +# +# +# List all network interfaces in explorer/ifaces. One interface per line. +# +# If your OS is not supported please provide a ifconfig output +# + +# Use ip, if available +if command -v ip >/dev/null; then + ip -o link show | sed -n 's/^[0-9]\+: \(.\+\): <.*/\1/p' + exit 0 +fi + +if ! command -v ifconfig >/dev/null; then + # no ifconfig, nothing we could do + exit 0 +fi + +uname_s="$(uname -s)" +REGEXP='s/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' + +case "$uname_s" in + Darwin) + ifconfig -a | sed -n -E "$REGEXP" + ;; + Linux|*BSD) + ifconfig -a | sed -n -r "$REGEXP" + ;; + *) + echo "Unsupported ifconfig output for $uname_s" >&2 + exit 1 + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/kernel_name b/cdist/test/autil/fixtures/explorer/kernel_name new file mode 100644 index 00000000..98ebac2a --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/kernel_name @@ -0,0 +1 @@ +uname -s diff --git a/cdist/test/autil/fixtures/explorer/lsb_codename b/cdist/test/autil/fixtures/explorer/lsb_codename new file mode 100755 index 00000000..eebd3e0f --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/lsb_codename @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# +# + +set +e +case "$($__explorer/os)" in + openwrt) + (. /etc/openwrt_release && echo "$DISTRIB_CODENAME") + ;; + *) + lsb_release=$(command -v lsb_release) + if [ -x "$lsb_release" ]; then + $lsb_release --short --codename + fi + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/lsb_description b/cdist/test/autil/fixtures/explorer/lsb_description new file mode 100755 index 00000000..23f45421 --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/lsb_description @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# +# + +set +e +case "$($__explorer/os)" in + openwrt) + (. /etc/openwrt_release && echo "$DISTRIB_DESCRIPTION") + ;; + *) + lsb_release=$(command -v lsb_release) + if [ -x "$lsb_release" ]; then + $lsb_release --short --description + fi + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/lsb_id b/cdist/test/autil/fixtures/explorer/lsb_id new file mode 100755 index 00000000..9754eb63 --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/lsb_id @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# +# + +set +e +case "$($__explorer/os)" in + openwrt) + (. /etc/openwrt_release && echo "$DISTRIB_ID") + ;; + *) + lsb_release=$(command -v lsb_release) + if [ -x "$lsb_release" ]; then + $lsb_release --short --id + fi + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/lsb_release b/cdist/test/autil/fixtures/explorer/lsb_release new file mode 100755 index 00000000..35b5547c --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/lsb_release @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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 . +# +# + +set +e +case "$($__explorer/os)" in + openwrt) + (. /etc/openwrt_release && echo "$DISTRIB_RELEASE") + ;; + *) + lsb_release=$(command -v lsb_release) + if [ -x "$lsb_release" ]; then + $lsb_release --short --release + fi + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/machine b/cdist/test/autil/fixtures/explorer/machine new file mode 100755 index 00000000..d4a0e106 --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/machine @@ -0,0 +1,27 @@ +#!/bin/sh +# +# 2010-2011 Andi Brönnimann (andi-cdist at v-net.ch) +# +# 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 . +# +# +# All os variables are lower case +# +# + +if command -v uname 2>&1 >/dev/null; then + uname -m +fi diff --git a/cdist/test/autil/fixtures/explorer/machine_type b/cdist/test/autil/fixtures/explorer/machine_type new file mode 100755 index 00000000..eb3c9d36 --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/machine_type @@ -0,0 +1,66 @@ +#!/bin/sh +# +# 2014 Daniel Heule (hda at sfs.biz) +# 2014 Thomas Oettli (otho at sfs.biz) +# +# 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 . +# +# + +# FIXME: other system types (not linux ...) + +if [ -d "/proc/vz" -a ! -d "/proc/bc" ]; then + echo openvz + exit +fi + +if [ -e "/proc/1/environ" ] && + cat "/proc/1/environ" | tr '\000' '\n' | grep -Eiq '^container='; then + echo lxc + exit +fi + +if [ -r /proc/cpuinfo ]; then + # this should only exist on virtual guest machines, + # tested on vmware, xen, kvm + 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 + if [ -r /sys/class/dmi/id/product_name ]; then + if grep -q -i 'vmware' /sys/class/dmi/id/product_name; then + echo "virtual_by_vmware" + exit + elif grep -q -i 'bochs' /sys/class/dmi/id/product_name; then + echo "virtual_by_kvm" + exit + elif grep -q -i 'virtualbox' /sys/class/dmi/id/product_name; then + echo "virtual_by_virtualbox" + exit + fi + fi + fi + echo "virtual_by_unknown" + else + echo "physical" + fi +else + echo "unknown" +fi diff --git a/cdist/test/autil/fixtures/explorer/memory b/cdist/test/autil/fixtures/explorer/memory new file mode 100755 index 00000000..05db865f --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/memory @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2014 Daniel Heule (hda at sfs.biz) +# 2014 Thomas Oettli (otho at sfs.biz) +# +# 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 . +# +# + +# FIXME: other system types (not linux ...) + +os=$("$__explorer/os") +case "$os" in + "macosx") + echo "$(sysctl -n hw.memsize)/1024" | bc + ;; + + *) + if [ -r /proc/meminfo ]; then + grep "MemTotal:" /proc/meminfo | awk '{print $2}' + fi + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/os b/cdist/test/autil/fixtures/explorer/os new file mode 100755 index 00000000..094685ea --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/os @@ -0,0 +1,143 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# +# 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 . +# +# +# All os variables are lower case. Keep this file in alphabetical +# order by os variable except in cases where order otherwise matters, +# in which case keep the primary os and its derivatives together in +# a block (see Debian and Redhat examples below). +# + +if grep -q ^Amazon /etc/system-release 2>/dev/null; then + echo amazon + exit 0 +fi + +if [ -f /etc/arch-release ]; then + echo archlinux + exit 0 +fi + +if [ -f /etc/cdist-preos ]; then + echo cdist-preos + exit 0 +fi + +if [ -d /gnu/store ]; then + echo guixsd + exit 0 +fi + +### Debian and derivatives +if grep -q ^DISTRIB_ID=Ubuntu /etc/lsb-release 2>/dev/null; then + echo ubuntu + exit 0 +fi + +if [ -f /etc/debian_version ]; then + echo debian + exit 0 +fi + +if [ -f /etc/devuan_version ]; then + echo devuan + exit 0 +fi +### + +if [ -f /etc/gentoo-release ]; then + echo gentoo + exit 0 +fi + +if [ -f /etc/openwrt_version ]; then + echo openwrt + exit 0 +fi + +if [ -f /etc/owl-release ]; then + echo owl + exit 0 +fi + +### Redhat and derivatives +if grep -q ^Scientific /etc/redhat-release 2>/dev/null; then + echo scientific + exit 0 +fi + +if grep -q ^CentOS /etc/redhat-release 2>/dev/null; then + echo centos + exit 0 +fi + +if grep -q ^Fedora /etc/redhat-release 2>/dev/null; then + echo fedora + exit 0 +fi + +if grep -q ^Mitel /etc/redhat-release 2>/dev/null; then + echo mitel + exit 0 +fi + +if [ -f /etc/redhat-release ]; then + echo redhat + exit 0 +fi +### + +if [ -f /etc/SuSE-release ]; then + echo suse + exit 0 +fi + +if [ -f /etc/slackware-version ]; then + echo slackware + exit 0 +fi + +uname_s="$(uname -s)" + +# Assume there is no tr on the client -> do lower case ourselves +case "$uname_s" in + Darwin) + echo macosx + exit 0 + ;; + NetBSD) + echo netbsd + exit 0 + ;; + FreeBSD) + echo freebsd + exit 0 + ;; + OpenBSD) + echo openbsd + exit 0 + ;; + SunOS) + echo solaris + exit 0 + ;; +esac + +echo "Unknown OS" >&2 +exit 1 diff --git a/cdist/test/autil/fixtures/explorer/os_version b/cdist/test/autil/fixtures/explorer/os_version new file mode 100755 index 00000000..380782cc --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/os_version @@ -0,0 +1,73 @@ +#!/bin/sh +# +# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# +# 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 . +# +# +# All os variables are lower case +# +# + +case "$($__explorer/os)" in + amazon) + cat /etc/system-release + ;; + archlinux) + # empty, but well... + cat /etc/arch-release + ;; + debian) + cat /etc/debian_version + ;; + devuan) + cat /etc/devuan_version + ;; + fedora) + cat /etc/fedora-release + ;; + gentoo) + cat /etc/gentoo-release + ;; + macosx) + sw_vers -productVersion + ;; + *bsd|solaris) + uname -r + ;; + openwrt) + cat /etc/openwrt_version + ;; + owl) + cat /etc/owl-release + ;; + redhat|centos|mitel|scientific) + cat /etc/redhat-release + ;; + slackware) + cat /etc/slackware-version + ;; + suse) + if [ -f /etc/os-release ]; then + cat /etc/os-release + else + cat /etc/SuSE-release + fi + ;; + ubuntu) + lsb_release -sr + ;; +esac diff --git a/cdist/test/autil/fixtures/explorer/runlevel b/cdist/test/autil/fixtures/explorer/runlevel new file mode 100755 index 00000000..02d3a245 --- /dev/null +++ b/cdist/test/autil/fixtures/explorer/runlevel @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# +# 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 . +# +# + +set +e +executable=$(command -v runlevel) +if [ -x "$executable" ]; then + "$executable" | awk '{ print $2 }' +fi From ca1cc0f64ad18878a265ed7bec162a49ae63b267 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 10 Aug 2017 19:08:44 +0200 Subject: [PATCH 0570/1332] object_id = '/' is invalid --- cdist/core/cdist_object.py | 12 +++++++----- cdist/test/cdist_object/__init__.py | 7 +++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 2d92aa41..8c7ce635 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -21,9 +21,7 @@ # # -import fnmatch import os -import collections import cdist import cdist.core @@ -142,9 +140,13 @@ class CdistObject(object): if '//' in self.object_id: raise IllegalObjectIdError( self.object_id, 'object_id may not contain //') - if self.object_id == '.': - raise IllegalObjectIdError( - self.object_id, 'object_id may not be a .') + + _invalid_object_ids = ('.', '/', ) + for ioid in _invalid_object_ids: + if self.object_id == ioid: + raise IllegalObjectIdError( + self.object_id, + 'object_id may not be a {}'.format(ioid)) # If no object_id and type is not singleton => error out if not self.object_id and not self.cdist_type.is_singleton: diff --git a/cdist/test/cdist_object/__init__.py b/cdist/test/cdist_object/__init__.py index d03c0642..a9c20cd3 100644 --- a/cdist/test/cdist_object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -147,6 +147,13 @@ class ObjectIdTestCase(test.CdistTestCase): core.CdistObject(cdist_type, self.object_base_path, OBJECT_MARKER_NAME, illegal_object_id) + def test_object_id_equals_slash(self): + cdist_type = core.CdistType(type_base_path, '__third') + illegal_object_id = '/' + with self.assertRaises(core.IllegalObjectIdError): + core.CdistObject(cdist_type, self.object_base_path, + OBJECT_MARKER_NAME, illegal_object_id) + def test_object_id_on_singleton_type(self): cdist_type = core.CdistType(type_base_path, '__test_singleton') illegal_object_id = 'object_id' From be86a89f305bd859e58f8cfdbe3b379316cee392 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 10 Aug 2017 22:00:42 +0200 Subject: [PATCH 0571/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index d029b42b..2c368a3d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Core: Expose inventory host tags in __target_host_tags env var (Darko Poljak) * Type __timezone: Check current timezone before doing anything (Ander Punnar) * Core: Add -p HOST_MAX argument (Darko Poljak) + * Core: Add archiving support for transferring directory - new -R beta option (Darko Poljak) 4.5.0: 2017-07-20 * Types: Fix install types (Steven Armstrong) From d5d7f0dd374e58d4a9063e7a0506df3526e831a5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 10 Aug 2017 23:43:38 +0200 Subject: [PATCH 0572/1332] Update changelog: Fix ssh connection multiplexing race condition --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 2c368a3d..a5534991 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: * Type __timezone: Check current timezone before doing anything (Ander Punnar) * Core: Add -p HOST_MAX argument (Darko Poljak) * Core: Add archiving support for transferring directory - new -R beta option (Darko Poljak) + * Core: Fix ssh connection multiplexing race condition (Darko Poljak) 4.5.0: 2017-07-20 * Types: Fix install types (Steven Armstrong) From 59782ad64e02d840a03e3dbdf0e5d8230c27ace1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 11 Aug 2017 01:20:45 +0200 Subject: [PATCH 0573/1332] Fix unit test. --- cdist/test/autil/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/test/autil/__init__.py b/cdist/test/autil/__init__.py index 28989058..a78feaad 100644 --- a/cdist/test/autil/__init__.py +++ b/cdist/test/autil/__init__.py @@ -41,7 +41,7 @@ class AUtilTestCase(test.CdistTestCase): } source = explorers_path for mode in test_modes: - tarpath = autil.tar(source, mode) + tarpath, fcnt = autil.tar(source, mode) self.assertIsNotNone(tarpath) fcnt = 0 with tarfile.open(tarpath, test_modes[mode]) as tar: From 1fa37566cb8f982259bc21324daae089b4671ca0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 11 Aug 2017 14:10:29 +0200 Subject: [PATCH 0574/1332] Document config/install -R option. --- docs/src/man1/cdist.rst | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 829b3824..931b4a1f 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -17,16 +17,18 @@ SYNOPSIS cdist config [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] - [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] - [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] - [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] + [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] + [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] + [-I INVENTORY_DIR] [-A] [-a] [-f HOSTFILE] [-p [HOST_MAX]] + [-s] [-t] [host [host ...]] cdist install [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] - [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] - [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] - [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] + [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] + [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] + [-I INVENTORY_DIR] [-A] [-a] [-f HOSTFILE] [-p [HOST_MAX]] + [-s] [-t] [host [host ...]] cdist inventory [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] @@ -172,6 +174,14 @@ Configure/install one or more hosts. maximum hosts at a time. Without argument CPU count is used by default. +.. option:: -R [{tar,tgz,tbz2,txz}], --use-archiving [{tar,tgz,tbz2,txz}] + + Operate by using archiving with compression where + apropriate. Supported values are: tar - tar archive, + tgz - gzip tar archive (the default), tbz2 - bzip2 tar + archive and txz - lzma tar archive. + + .. option:: -r REMOTE_OUT_PATH, --remote-out-dir REMOTE_OUT_PATH Directory to save cdist output in on the target host From 314a931b84d5b94df818226a8343453e1d34b9c2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 12 Aug 2017 21:40:23 +0200 Subject: [PATCH 0575/1332] Respect cdist log level in emulator. --- cdist/core/manifest.py | 4 ++-- cdist/emulator.py | 7 ++++--- cdist/test/manifest/__init__.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 6f941550..0a26601a 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -113,8 +113,8 @@ class Manifest(object): '__target_host_tags': self.local.target_host_tags, } - if self.log.getEffectiveLevel() == logging.DEBUG: - self.env.update({'__cdist_debug': "yes"}) + self.env.update( + {'__cdist_loglevel': str(self.log.getEffectiveLevel())}) def _open_logger(self): self.log = logging.getLogger(self.target_host[0]) diff --git a/cdist/emulator.py b/cdist/emulator.py index 7c9dfcca..66736643 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -104,10 +104,11 @@ class Emulator(object): def __init_log(self): """Setup logging facility""" - if '__cdist_debug' in self.env: - logging.root.setLevel(logging.DEBUG) + if '__cdist_loglevel' in self.env: + level = int(self.env['__cdist_loglevel']) else: - logging.root.setLevel(logging.INFO) + level = logging.OFF + logging.root.setLevel(level) self.log = logging.getLogger(self.target_host[0]) diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index e0da2d9f..95bf2768 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -136,7 +136,7 @@ class ManifestTestCase(test.CdistTestCase): current_level = self.log.getEffectiveLevel() self.log.setLevel(logging.DEBUG) manifest = cdist.core.manifest.Manifest(self.target_host, self.local) - self.assertTrue("__cdist_debug" in manifest.env) + self.assertTrue("__cdist_loglevel" in manifest.env) self.log.setLevel(current_level) From 87fe52ea61ce693ccb6d894b22b37cff0fd0f7eb Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 12 Aug 2017 23:02:31 +0200 Subject: [PATCH 0576/1332] Default logging level is WARNING. --- cdist/emulator.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 66736643..eff2f221 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -105,9 +105,12 @@ class Emulator(object): """Setup logging facility""" if '__cdist_loglevel' in self.env: - level = int(self.env['__cdist_loglevel']) + try: + level = int(self.env['__cdist_loglevel']) + except: + level = logging.WARNING else: - level = logging.OFF + level = logging.WARNING logging.root.setLevel(level) self.log = logging.getLogger(self.target_host[0]) From 75fe3272b306235c02d7a19f9b5ba70fbb7838e0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 11 Aug 2017 15:04:26 +0200 Subject: [PATCH 0577/1332] Add file locking for -j parallel execution. --- cdist/config.py | 4 +-- cdist/core/manifest.py | 4 +-- cdist/emulator.py | 34 ++++++++++++------- cdist/flock.py | 58 +++++++++++++++++++++++++++++++++ cdist/test/manifest/__init__.py | 2 +- 5 files changed, 85 insertions(+), 17 deletions(-) create mode 100644 cdist/flock.py diff --git a/cdist/config.py b/cdist/config.py index b7ca1f84..cdff47eb 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -39,11 +39,9 @@ import cdist.hostsource import cdist.exec.local import cdist.exec.remote -from cdist import inventory - import cdist.util.ipaddr as ipaddr -from cdist import core +from cdist import core, inventory from cdist.util.remoteutil import inspect_ssh_mux_opts diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 6f941550..0a26601a 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -113,8 +113,8 @@ class Manifest(object): '__target_host_tags': self.local.target_host_tags, } - if self.log.getEffectiveLevel() == logging.DEBUG: - self.env.update({'__cdist_debug': "yes"}) + self.env.update( + {'__cdist_loglevel': str(self.log.getEffectiveLevel())}) def _open_logger(self): self.log = logging.getLogger(self.target_host[0]) diff --git a/cdist/emulator.py b/cdist/emulator.py index 7c9dfcca..abc37282 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -28,6 +28,7 @@ import sys import cdist from cdist import core +from cdist import flock class MissingRequiredEnvironmentVariableError(cdist.Error): @@ -94,20 +95,25 @@ class Emulator(object): """Emulate type commands (i.e. __file and co)""" self.commandline() - self.setup_object() - self.save_stdin() - self.record_requirements() - self.record_auto_requirements() - self.log.trace("Finished %s %s" % ( - self.cdist_object.path, self.parameters)) + self.init_object() + + # locking for parallel execution + with flock.Flock(self.flock_path) as lock: + self.setup_object() + self.save_stdin() + self.record_requirements() + self.record_auto_requirements() + self.log.trace("Finished %s %s" % ( + self.cdist_object.path, self.parameters)) def __init_log(self): """Setup logging facility""" - if '__cdist_debug' in self.env: - logging.root.setLevel(logging.DEBUG) + if '__cdist_loglevel' in self.env: + level = int(self.env['__cdist_loglevel']) else: - logging.root.setLevel(logging.INFO) + level = logging.OFF + logging.root.setLevel(level) self.log = logging.getLogger(self.target_host[0]) @@ -150,8 +156,8 @@ class Emulator(object): self.args = parser.parse_args(self.argv[1:]) self.log.trace('Args: %s' % self.args) - def setup_object(self): - # Setup object - and ensure it is not in args + def init_object(self): + # Initialize object - and ensure it is not in args if self.cdist_type.is_singleton: self.object_id = '' else: @@ -162,7 +168,13 @@ class Emulator(object): self.cdist_object = core.CdistObject( self.cdist_type, self.object_base_path, self.object_marker, self.object_id) + lockfname = ('.' + self.cdist_type.name + + self.object_id + '_' + + self.object_marker + '.lock') + lockfname = lockfname.replace(os.sep, '_') + self.flock_path = os.path.join(self.object_base_path, lockfname) + def setup_object(self): # Create object with given parameters self.parameters = {} for key, value in vars(self.args).items(): diff --git a/cdist/flock.py b/cdist/flock.py new file mode 100644 index 00000000..d8bac916 --- /dev/null +++ b/cdist/flock.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# +# 2017 Darko Poljak (darko.poljak 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 . +# +# + +import fcntl +import logging +import os + + +log = logging.getLogger('cdist-flock') + + +class Flock(): + def __init__(self, path): + self.path = path + self.lockfd = None + + def flock(self): + log.debug('Acquiring lock on %s', self.path) + self.lockfd = open(self.path, 'w+') + fcntl.flock(self.lockfd, fcntl.LOCK_EX) + log.debug('Acquired lock on %s', self.path) + + def funlock(self): + log.debug('Releasing lock on %s', self.path) + fcntl.flock(self.lockfd, fcntl.LOCK_UN) + self.lockfd.close() + self.lockfd = None + try: + os.remove(self.path) + except FileNotFoundError: + pass + log.debug('Released lock on %s', self.path) + + def __enter__(self): + self.flock() + return self + + def __exit__(self, *args): + self.funlock() + return False diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index e0da2d9f..95bf2768 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -136,7 +136,7 @@ class ManifestTestCase(test.CdistTestCase): current_level = self.log.getEffectiveLevel() self.log.setLevel(logging.DEBUG) manifest = cdist.core.manifest.Manifest(self.target_host, self.local) - self.assertTrue("__cdist_debug" in manifest.env) + self.assertTrue("__cdist_loglevel" in manifest.env) self.log.setLevel(current_level) From 7aa7a8db6d2302ef0c04b3c2375303fa7086ef16 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 13 Aug 2017 12:30:07 +0200 Subject: [PATCH 0578/1332] Update changelog: add file locking for -j parallel execution --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index a5534991..3d642332 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Core: Add -p HOST_MAX argument (Darko Poljak) * Core: Add archiving support for transferring directory - new -R beta option (Darko Poljak) * Core: Fix ssh connection multiplexing race condition (Darko Poljak) + * Core: Fix emulator race conditions with -j option (Darko Poljak) 4.5.0: 2017-07-20 * Types: Fix install types (Steven Armstrong) From 7b0b3d9415323534a85c284a3714358979cc5a3f Mon Sep 17 00:00:00 2001 From: Philippe Gregoire Date: Mon, 14 Aug 2017 14:25:19 -0400 Subject: [PATCH 0579/1332] Fix remote cmds cleanup When --remote-copy and --remote-exec are provided, args.remote_cmds_cleanup_pattern is not set. This patches fixes the evaluation of args.remote_cmds_cleanup_pattern and prevents cdist from throwing an exception when --remote-copy and --remote-exec are used. --- cdist/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index cdff47eb..4cba4948 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -270,7 +270,7 @@ class Config(object): remote_copy = args.remote_copy_pattern.format(control_path) else: remote_copy = args.remote_copy - if args.remote_cmds_cleanup_pattern: + if 'remote_cmds_cleanup_pattern' in args: remote_cmds_cleanup = args.remote_cmds_cleanup_pattern.format( control_path) else: From 61b52ac8065efe3366f8d345d1cc6f5c22c2c043 Mon Sep 17 00:00:00 2001 From: Philippe Gregoire Date: Mon, 14 Aug 2017 16:13:57 -0400 Subject: [PATCH 0580/1332] Set default remote_cmds_cleanup_pattern Fixes an exception when --remote-copy and --remote-exec are used. --- cdist/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index 4cba4948..14533237 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -80,6 +80,7 @@ class Config(object): @staticmethod def construct_remote_exec_copy_patterns(args): # default remote cmd patterns + args.remote_cmds_cleanup_pattern = "" args.remote_exec_pattern = None args.remote_copy_pattern = None @@ -270,7 +271,7 @@ class Config(object): remote_copy = args.remote_copy_pattern.format(control_path) else: remote_copy = args.remote_copy - if 'remote_cmds_cleanup_pattern' in args: + if args.remote_cmds_cleanup_pattern: remote_cmds_cleanup = args.remote_cmds_cleanup_pattern.format( control_path) else: From 982bb286f49e8941934654f7487ae9d24d467771 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 17 Aug 2017 08:24:58 +0200 Subject: [PATCH 0581/1332] Cleanup options' help and cdist man page. --- cdist/argparse.py | 89 +++++++++++++++++-------------- docs/src/man1/cdist.rst | 112 ++++++++++++++-------------------------- 2 files changed, 89 insertions(+), 112 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 4d9dc719..9afc5a82 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -27,6 +27,17 @@ _verbosity_level = { 3: logging.DEBUG, 4: logging.TRACE, } + + +# Generate verbosity level constants: +# VERBOSE_OFF, VERBOSE_ERROR, VERBOSE_WARNING, VERBOSE_INFO, VERBOSE_VERBOSE, +# VERBOSE_DEBUG, VERBOSE_TRACE. +this_globals = globals() +for level in _verbosity_level: + const = 'VERBOSE_' + logging.getLevelName(_verbosity_level[level]) + this_globals[const] = level + + # All verbosity levels above 4 are TRACE. _verbosity_level = collections.defaultdict( lambda: logging.TRACE, _verbosity_level) @@ -87,7 +98,7 @@ def get_parsers(): parser['loglevel'] = argparse.ArgumentParser(add_help=False) parser['loglevel'].add_argument( '-q', '--quiet', - help='Quiet mode: disables logging, including WARNING and ERROR', + help='Quiet mode: disables logging, including WARNING and ERROR.', action='store_true', default=False) parser['loglevel'].add_argument( '-v', '--verbose', @@ -102,16 +113,15 @@ def get_parsers(): parser['beta'] = argparse.ArgumentParser(add_help=False) parser['beta'].add_argument( '-b', '--beta', - help=('Enable beta functionality. ' - 'Can also be enabled using CDIST_BETA env var.'), + help=('Enable beta functionality. '), action='store_true', dest='beta', - default='CDIST_BETA' in os.environ) + default=False) # Main subcommand parser parser['main'] = argparse.ArgumentParser( description='cdist ' + cdist.VERSION, parents=[parser['loglevel']]) parser['main'].add_argument( - '-V', '--version', help='Show version', action='version', + '-V', '--version', help='Show version.', action='version', version='%(prog)s ' + cdist.VERSION) parser['sub'] = parser['main'].add_subparsers( title="Commands", dest="command") @@ -136,18 +146,17 @@ def get_parsers(): parser['config_main'] = argparse.ArgumentParser(add_help=False) parser['config_main'].add_argument( '-C', '--cache-path-pattern', - help=('Specify custom cache path pattern. It can also be set ' - 'by CDIST_CACHE_PATH_PATTERN environment variable. If ' + help=('Specify custom cache path pattern. If ' 'it is not set then default hostdir is used.'), dest='cache_path_pattern', - default=os.environ.get('CDIST_CACHE_PATH_PATTERN')) + default=None) parser['config_main'].add_argument( '-c', '--conf-dir', help=('Add configuration directory (can be repeated, ' - 'last one wins)'), action='append') + 'last one wins).'), action='append') parser['config_main'].add_argument( '-i', '--initial-manifest', - help='path to a cdist manifest or \'-\' to read from stdin.', + help='Path to a cdist manifest or \'-\' to read from stdin.', dest='manifest', required=False) parser['config_main'].add_argument( '-j', '--jobs', nargs='?', @@ -160,17 +169,18 @@ def get_parsers(): const=multiprocessing.cpu_count()) parser['config_main'].add_argument( '-n', '--dry-run', - help='do not execute code', action='store_true') + help='Do not execute code.', action='store_true') parser['config_main'].add_argument( '-o', '--out-dir', - help='directory to save cdist output in', dest="out_path") + help='Directory to save cdist output in.', dest="out_path") parser['config_main'].add_argument( '-R', '--use-archiving', nargs='?', choices=('tar', 'tgz', 'tbz2', 'txz',), help=('Operate by using archiving with compression where ' 'apropriate. Supported values are: tar - tar archive, ' 'tgz - gzip tar archive (the default), ' - 'tbz2 - bzip2 tar archive and txz - lzma tar archive.'), + 'tbz2 - bzip2 tar archive and txz - lzma tar archive. ' + 'Currently in beta.'), action='store', dest='use_archiving', const='tgz') @@ -179,33 +189,33 @@ def get_parsers(): # parsing to determine implementation default parser['config_main'].add_argument( '-r', '--remote-out-dir', - help='Directory to save cdist output in on the target host', + help='Directory to save cdist output in on the target host.', dest="remote_out_path") parser['config_main'].add_argument( '--remote-copy', - help='Command to use for remote copy (should behave like scp)', + help='Command to use for remote copy (should behave like scp).', action='store', dest='remote_copy', - default=os.environ.get('CDIST_REMOTE_COPY')) + default=None) parser['config_main'].add_argument( '--remote-exec', help=('Command to use for remote execution ' - '(should behave like ssh)'), + '(should behave like ssh).'), action='store', dest='remote_exec', - default=os.environ.get('CDIST_REMOTE_EXEC')) + default=None) # Config parser['config_args'] = argparse.ArgumentParser(add_help=False) parser['config_args'].add_argument( '-A', '--all-tagged', - help=('use all hosts present in tags db'), + help=('Use all hosts present in tags db. Currently in beta.'), action="store_true", dest="all_tagged_hosts", default=False) parser['config_args'].add_argument( '-a', '--all', - help=('list hosts that have all specified tags, ' - 'if -t/--tag is specified'), + help=('List hosts that have all specified tags, ' + 'if -t/--tag is specified.'), action="store_true", dest="has_all_tags", default=False) parser['config_args'].add_argument( - 'host', nargs='*', help='host(s) to operate on') + 'host', nargs='*', help='Host(s) to operate on.') parser['config_args'].add_argument( '-f', '--file', help=('Read specified file for a list of additional hosts to ' @@ -223,12 +233,13 @@ def get_parsers(): const=multiprocessing.cpu_count()) parser['config_args'].add_argument( '-s', '--sequential', - help='operate on multiple hosts sequentially (default)', + help='Operate on multiple hosts sequentially (default).', action='store_const', dest='parallel', const=0) parser['config_args'].add_argument( '-t', '--tag', - help=('host is specified by tag, not hostname/address; ' - 'list all hosts that contain any of specified tags'), + help=('Host is specified by tag, not hostname/address; ' + 'list all hosts that contain any of specified tags. ' + 'Currently in beta.'), dest='tag', required=False, action="store_true", default=False) parser['config'] = parser['sub'].add_parser( 'config', parents=[parser['loglevel'], parser['beta'], @@ -253,7 +264,7 @@ def get_parsers(): 'add-host', parents=[parser['loglevel'], parser['beta'], parser['inventory_common']]) parser['add-host'].add_argument( - 'host', nargs='*', help='host(s) to add') + 'host', nargs='*', help='Host(s) to add.') parser['add-host'].add_argument( '-f', '--file', help=('Read additional hosts to add from specified file ' @@ -267,7 +278,7 @@ def get_parsers(): parser['inventory_common']]) parser['add-tag'].add_argument( 'host', nargs='*', - help='list of host(s) for which tags are added') + help='List of host(s) for which tags are added.') parser['add-tag'].add_argument( '-f', '--file', help=('Read additional hosts to add tags from specified file ' @@ -289,16 +300,16 @@ def get_parsers(): parser['add-tag'].add_argument( '-t', '--taglist', help=("Tag list to be added for specified host(s), comma separated" - " values"), + " values."), dest="taglist", required=False) parser['del-host'] = parser['invsub'].add_parser( 'del-host', parents=[parser['loglevel'], parser['beta'], parser['inventory_common']]) parser['del-host'].add_argument( - 'host', nargs='*', help='host(s) to delete') + 'host', nargs='*', help='Host(s) to delete.') parser['del-host'].add_argument( - '-a', '--all', help=('Delete all hosts'), + '-a', '--all', help=('Delete all hosts.'), dest='all', required=False, action="store_true", default=False) parser['del-host'].add_argument( '-f', '--file', @@ -313,10 +324,10 @@ def get_parsers(): parser['inventory_common']]) parser['del-tag'].add_argument( 'host', nargs='*', - help='list of host(s) for which tags are deleted') + help='List of host(s) for which tags are deleted.') parser['del-tag'].add_argument( '-a', '--all', - help=('Delete all tags for specified host(s)'), + help=('Delete all tags for specified host(s).'), dest='all', required=False, action="store_true", default=False) parser['del-tag'].add_argument( '-f', '--file', @@ -339,18 +350,18 @@ def get_parsers(): parser['del-tag'].add_argument( '-t', '--taglist', help=("Tag list to be deleted for specified host(s), " - "comma separated values"), + "comma separated values."), dest="taglist", required=False) parser['list'] = parser['invsub'].add_parser( 'list', parents=[parser['loglevel'], parser['beta'], parser['inventory_common']]) parser['list'].add_argument( - 'host', nargs='*', help='host(s) to list') + 'host', nargs='*', help='Host(s) to list.') parser['list'].add_argument( '-a', '--all', - help=('list hosts that have all specified tags, ' - 'if -t/--tag is specified'), + help=('List hosts that have all specified tags, ' + 'if -t/--tag is specified.'), action="store_true", dest="has_all_tags", default=False) parser['list'].add_argument( '-f', '--file', @@ -359,12 +370,12 @@ def get_parsers(): 'If no host or host file is specified then, by default, ' 'list all.'), dest='hostfile', required=False) parser['list'].add_argument( - '-H', '--host-only', help=('Suppress tags listing'), + '-H', '--host-only', help=('Suppress tags listing.'), action="store_true", dest="list_only_host", default=False) parser['list'].add_argument( '-t', '--tag', - help=('host is specified by tag, not hostname/address; ' - 'list all hosts that contain any of specified tags'), + help=('Host is specified by tag, not hostname/address; ' + 'list all hosts that contain any of specified tags.'), action="store_true", default=False) parser['inventory'].set_defaults( diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 931b4a1f..c494ff57 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -71,11 +71,11 @@ All commands accept the following options: .. option:: -h, --help - Show the help screen + Show the help screen. .. option:: -q, --quiet - Quiet mode: disables logging, including WARNING and ERROR + Quiet mode: disables logging, including WARNING and ERROR. .. option:: -v, --verbose @@ -86,7 +86,7 @@ All commands accept the following options: .. option:: -V, --version - Show version and exit + Show version and exit. BANNER @@ -98,26 +98,24 @@ cdist posters - a must have for every office. CONFIG/INSTALL -------------- Configure/install one or more hosts. +Install command is currently in beta. .. option:: -A, --all-tagged - use all hosts present in tags db + Use all hosts present in tags db. Currently in beta. .. option:: -a, --all - list hosts that have all specified tags, if -t/--tag - is specified + List hosts that have all specified tags, if -t/--tag + is specified. .. option:: -b, --beta Enable beta functionality. - - Can also be enabled using CDIST_BETA env var. .. option:: -C CACHE_PATH_PATTERN, --cache-path-pattern CACHE_PATH_PATTERN - Sepcify custom cache path pattern. It can also be set by - CDIST_CACHE_PATH_PATTERN environment variable. If it is not set then + Sepcify custom cache path pattern. If it is not set then default hostdir is used. For more info on format see :strong:`CACHE PATH PATTERN FORMAT` below. @@ -125,11 +123,7 @@ Configure/install one or more hosts. Add a configuration directory. Can be specified multiple times. If configuration directories contain conflicting types, explorers or - manifests, then the last one found is used. Additionally this can also - be configured by setting the CDIST_PATH environment variable to a colon - delimited list of config directories. Directories given with the - --conf-dir argument have higher precedence over those set through the - environment variable. + manifests, then the last one found is used. .. option:: -f HOSTFILE, --file HOSTFILE @@ -151,7 +145,7 @@ Configure/install one or more hosts. .. option:: -i MANIFEST, --initial-manifest MANIFEST - Path to a cdist manifest or - to read from stdin + Path to a cdist manifest or - to read from stdin. .. option:: -j [JOBS], --jobs [JOBS] @@ -162,11 +156,11 @@ Configure/install one or more hosts. .. option:: -n, --dry-run - Do not execute code + Do not execute code. .. option:: -o OUT_PATH, --out-dir OUT_PATH - Directory to save cdist output in + Directory to save cdist output in. .. option:: -p [HOST_MAX], --parallel [HOST_MAX] @@ -179,29 +173,29 @@ Configure/install one or more hosts. Operate by using archiving with compression where apropriate. Supported values are: tar - tar archive, tgz - gzip tar archive (the default), tbz2 - bzip2 tar - archive and txz - lzma tar archive. - + archive and txz - lzma tar archive. Currently in beta. .. option:: -r REMOTE_OUT_PATH, --remote-out-dir REMOTE_OUT_PATH - Directory to save cdist output in on the target host + Directory to save cdist output in on the target host. .. option:: -s, --sequential - Operate on multiple hosts sequentially (default) + Operate on multiple hosts sequentially (default). .. option:: --remote-copy REMOTE_COPY - Command to use for remote copy (should behave like scp) + Command to use for remote copy (should behave like scp). .. option:: --remote-exec REMOTE_EXEC - Command to use for remote execution (should behave like ssh) + Command to use for remote execution (should behave like ssh). .. option:: -t, --tag - host is specified by tag, not hostname/address; list - all hosts that contain any of specified tags + Host is specified by tag, not hostname/address; list + all hosts that contain any of specified tags. + Currently in beta. HOSTFILE FORMAT ~~~~~~~~~~~~~~~ @@ -247,16 +241,11 @@ Add host(s) to inventory database. .. option:: host - host(s) to add + Host(s) to add. .. option:: -b, --beta - Enable beta functionalities. Beta functionalities - include inventory command with all sub-commands and - all options; config sub-command options: -j/--jobs, - -t/--tag, -a/--all. - - Can also be enabled using CDIST_BETA env var. + Enable beta functionality. .. option:: -f HOSTFILE, --file HOSTFILE @@ -265,9 +254,6 @@ Add host(s) to inventory database. host or host file is specified then, by default, read from stdin. Hostfile format is the same as config hostfile format. -.. option:: -h, --help - - show this help message and exit .. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR @@ -286,16 +272,11 @@ Add tag(s) to inventory database. .. option:: host - list of host(s) for which tags are added + List of host(s) for which tags are added. .. option:: -b, --beta - Enable beta functionalities. Beta functionalities - include inventory command with all sub-commands and - all options; config sub-command options: -j/--jobs, - -t/--tag, -a/--all. - - Can also be enabled using CDIST_BETA env var. + Enable beta functionality. .. option:: -f HOSTFILE, --file HOSTFILE @@ -328,7 +309,7 @@ Add tag(s) to inventory database. .. option:: -t TAGLIST, --taglist TAGLIST Tag list to be added for specified host(s), comma - separated values + separated values. INVENTORY DEL-HOST @@ -337,20 +318,15 @@ Delete host(s) from inventory database. .. option:: host - host(s) to delete + Host(s) to delete. .. option:: -a, --all - Delete all hosts + Delete all hosts. .. option:: -b, --beta - Enable beta functionalities. Beta functionalities - include inventory command with all sub-commands and - all options; config sub-command options: -j/--jobs, - -t/--tag, -a/--all. - - Can also be enabled using CDIST_BETA env var. + Enable beta functionality. .. option:: -f HOSTFILE, --file HOSTFILE @@ -376,20 +352,15 @@ Delete tag(s) from inventory database. .. option:: host - list of host(s) for which tags are deleted + List of host(s) for which tags are deleted. .. option:: -a, --all - Delete all tags for specified host(s) + Delete all tags for specified host(s). .. option:: -b, --beta - Enable beta functionalities. Beta functionalities - include inventory command with all sub-commands and - all options; config sub-command options: -j/--jobs, - -t/--tag, -a/--all. - - Can also be enabled using CDIST_BETA env var. + Enable beta functionality. .. option:: -f HOSTFILE, --file HOSTFILE @@ -423,7 +394,7 @@ Delete tag(s) from inventory database. .. option:: -t TAGLIST, --taglist TAGLIST Tag list to be deleted for specified host(s), comma - separated values + separated values. INVENTORY LIST @@ -432,21 +403,16 @@ List inventory database. .. option:: host - host(s) to list + Host(s) to list. .. option:: -a, --all - list hosts that have all specified tags, if -t/--tag - is specified + List hosts that have all specified tags, if -t/--tag + is specified. .. option:: -b, --beta - Enable beta functionalities. Beta functionalities - include inventory command with all sub-commands and - all options; config sub-command options: -j/--jobs, - -t/--tag, -a/--all. - - Can also be enabled using CDIST_BETA env var. + Enable beta functionality. .. option:: -f HOSTFILE, --file HOSTFILE @@ -457,7 +423,7 @@ List inventory database. .. option:: -H, --host-only - Suppress tags listing + Suppress tags listing. .. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR @@ -471,8 +437,8 @@ List inventory database. .. option:: -t, --tag - host is specified by tag, not hostname/address; list - all hosts that contain any of specified tags + Host is specified by tag, not hostname/address; list + all hosts that contain any of specified tags. SHELL From 8a23227ec9acfc59a138d7fdb2167bf4147e403e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 17 Aug 2017 12:28:46 +0200 Subject: [PATCH 0582/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 3d642332..ab60f1ea 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Core: Add archiving support for transferring directory - new -R beta option (Darko Poljak) * Core: Fix ssh connection multiplexing race condition (Darko Poljak) * Core: Fix emulator race conditions with -j option (Darko Poljak) + * Documentation: Cleanup (Darko Poljak) 4.5.0: 2017-07-20 * Types: Fix install types (Steven Armstrong) From ceb97fd0ee18f2a31354819bcaf190f23a9b0efa Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 19 Aug 2017 19:12:30 +0200 Subject: [PATCH 0583/1332] Fix for mistake in 982bb286f49e8941934654f7487ae9d24d467771. --- cdist/argparse.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 9afc5a82..849b19d2 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -115,7 +115,7 @@ def get_parsers(): '-b', '--beta', help=('Enable beta functionality. '), action='store_true', dest='beta', - default=False) + default='CDIST_BETA' in os.environ) # Main subcommand parser parser['main'] = argparse.ArgumentParser( @@ -149,7 +149,7 @@ def get_parsers(): help=('Specify custom cache path pattern. If ' 'it is not set then default hostdir is used.'), dest='cache_path_pattern', - default=None) + default=os.environ.get('CDIST_CACHE_PATH_PATTERN')) parser['config_main'].add_argument( '-c', '--conf-dir', help=('Add configuration directory (can be repeated, ' @@ -195,13 +195,13 @@ def get_parsers(): '--remote-copy', help='Command to use for remote copy (should behave like scp).', action='store', dest='remote_copy', - default=None) + default=os.environ.get('CDIST_REMOTE_COPY')) parser['config_main'].add_argument( '--remote-exec', help=('Command to use for remote execution ' '(should behave like ssh).'), action='store', dest='remote_exec', - default=None) + default=os.environ.get('CDIST_REMOTE_EXEC')) # Config parser['config_args'] = argparse.ArgumentParser(add_help=False) From 69c6de9f9c7a5f6107a70f83004d17cb7771ca5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sat, 19 Aug 2017 16:41:50 -0400 Subject: [PATCH 0584/1332] explorer/os: get ID from /etc/os-release /etc/os-release was introduced by systemd[1] and is now more and more common; even on systems without systemd (e.g. lede). In addition to detecting the OS based on specific attributes, this file provides the ID marker to describe the OS. This commit adds support for OS detection via /etc/os-release. According to [2], it is already lowercase. [1] http://0pointer.de/blog/projects/os-release [2] https://www.freedesktop.org/software/systemd/man/os-release.html --- cdist/conf/explorer/os | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index 094685ea..e0125c1b 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -1,6 +1,7 @@ #!/bin/sh # # 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# Copyright 2017, Philippe Gregoire # # This file is part of cdist. # @@ -139,5 +140,12 @@ case "$uname_s" in ;; esac +if [ -f /etc/os-release ]; then + # already lowercase, according to: + # https://www.freedesktop.org/software/systemd/man/os-release.html + grep '^ID=' /etc/os-release | sed -e 's|^ID=||' + exit 0 +fi + echo "Unknown OS" >&2 exit 1 From e88e9c357f77b1fbd92dcdcea70bd7e99aa7f328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sat, 19 Aug 2017 16:49:19 -0400 Subject: [PATCH 0585/1332] fix formatting --- cdist/conf/explorer/os | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index e0125c1b..77c8a76a 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -141,10 +141,10 @@ case "$uname_s" in esac if [ -f /etc/os-release ]; then - # already lowercase, according to: - # https://www.freedesktop.org/software/systemd/man/os-release.html - grep '^ID=' /etc/os-release | sed -e 's|^ID=||' - exit 0 + # already lowercase, according to: + # https://www.freedesktop.org/software/systemd/man/os-release.html + grep '^ID=' /etc/os-release | sed -e 's|^ID=||' + exit 0 fi echo "Unknown OS" >&2 From 2b9bf3de248de66f8159e7f971a1d5299975d7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sat, 19 Aug 2017 18:19:17 -0400 Subject: [PATCH 0586/1332] replace grep+sed by awk --- cdist/conf/explorer/os | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index 77c8a76a..d1f3ccb4 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -143,7 +143,7 @@ esac if [ -f /etc/os-release ]; then # already lowercase, according to: # https://www.freedesktop.org/software/systemd/man/os-release.html - grep '^ID=' /etc/os-release | sed -e 's|^ID=||' + awk -F= '/^ID=/ {print $2;}' /etc/os-release exit 0 fi From 5646a66f6c6b5f5dd66f69d63709825af9e99a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sun, 20 Aug 2017 11:06:07 -0400 Subject: [PATCH 0587/1332] explorer/init/Linux: replace ps by pgrep BusyBox's version of ps does not support the -o option. On Linux systems, use pgrep -P0 -l to get the name of pid 1. --- cdist/conf/explorer/init | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/conf/explorer/init b/cdist/conf/explorer/init index 2693a0d3..54784a2e 100755 --- a/cdist/conf/explorer/init +++ b/cdist/conf/explorer/init @@ -1,6 +1,7 @@ #!/bin/sh # # 2016 Daniel Heule (hda at sfs.biz) +# Copyright 2017, Philippe Gregoire # # This file is part of cdist. # @@ -25,7 +26,10 @@ uname_s="$(uname -s)" case "$uname_s" in - Linux|FreeBSD) + Linux) + pgrep -P0 -l | awk '/^1[ \t]/ {print $2;}' + ;; + FreeBSD) ps -o comm= -p 1 || true ;; *) From ebe0c0d66df5b2a10bedb0b4ccbaa5975da96b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sun, 20 Aug 2017 11:12:30 -0400 Subject: [PATCH 0588/1332] make sure we continue on errors --- cdist/conf/explorer/init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/explorer/init b/cdist/conf/explorer/init index 54784a2e..43a66a50 100755 --- a/cdist/conf/explorer/init +++ b/cdist/conf/explorer/init @@ -27,7 +27,7 @@ uname_s="$(uname -s)" case "$uname_s" in Linux) - pgrep -P0 -l | awk '/^1[ \t]/ {print $2;}' + (pgrep -P0 -l | awk '/^1[ \t]/ {print $2;}') || true ;; FreeBSD) ps -o comm= -p 1 || true From a915baa73b1022f50c29996fcdaa32e033e7919c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sun, 20 Aug 2017 12:10:54 -0400 Subject: [PATCH 0589/1332] __user: explore with /etc files getent(1) is a utility available where Name Service Switch (NSS) is available. Many modern operating systems support it, but that may not be the case of all (e.g. embedded systems). This commit modifies the __user type explorers to check the traditional files instead of relying solely on the availability of getent(1). - Makes the group explorer use /etc/group - Makes the passwd explorer use /etc/passwd - Makes the shadow explorer use /etc/shadow Implementation note "getent shadow" does not support querying an entry using a uid since it does not store that information. Since the shadow explorer uses __object_id, the passwd explorer does not check if __object_id matches an entry by uid. This behavior ensures consistent, transparent behavior of the type. The group explorer, on the other hand, handles group names and uids; like always. --- cdist/conf/type/__user/explorer/group | 6 +++++- cdist/conf/type/__user/explorer/passwd | 7 +++++-- cdist/conf/type/__user/explorer/shadow | 7 +++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__user/explorer/group b/cdist/conf/type/__user/explorer/group index 98ce39c6..b95f3d01 100755 --- a/cdist/conf/type/__user/explorer/group +++ b/cdist/conf/type/__user/explorer/group @@ -23,6 +23,10 @@ if [ -f "$__object/parameter/gid" ]; then gid=$(cat "$__object/parameter/gid") - getent group "$gid" || true + if [ -x /usr/bin/getent ] || [ -x /bin/getent ]; then + getent group "$gid" || true + elif [ -f /etc/group ]; then + grep -E "^(${gid}|([^:]:){2}${gid}):" /etc/group || true + fi fi diff --git a/cdist/conf/type/__user/explorer/passwd b/cdist/conf/type/__user/explorer/passwd index fdbfb193..592d04c4 100755 --- a/cdist/conf/type/__user/explorer/passwd +++ b/cdist/conf/type/__user/explorer/passwd @@ -23,5 +23,8 @@ name=$__object_id -getent passwd "$name" || true - +if [ -x /usr/bin/getent ] || [ -x /bin/getent ]; then + getent passwd "$name" || true +elif [ -f /etc/passwd ]; then + grep "^${name}:" /etc/passwd || true +fi diff --git a/cdist/conf/type/__user/explorer/shadow b/cdist/conf/type/__user/explorer/shadow index 1a8fd809..b2d1d121 100755 --- a/cdist/conf/type/__user/explorer/shadow +++ b/cdist/conf/type/__user/explorer/shadow @@ -31,5 +31,8 @@ case "$os" in esac -getent "$database" "$name" || true - +if [ -x /usr/bin/getent ] || [ -x /bin/getent ]; then + getent "$database" "$name" || true +elif [ -f /etc/shadow ]; then + grep "^${name}:" /etc/shadow || true +fi From 722389f838447aa118225b54feda88f8aee4f79a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 20 Aug 2017 20:39:49 +0200 Subject: [PATCH 0590/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ab60f1ea..51340bc3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Core: Fix ssh connection multiplexing race condition (Darko Poljak) * Core: Fix emulator race conditions with -j option (Darko Poljak) * Documentation: Cleanup (Darko Poljak) + * Explorer os: Get ID from /etc/os-release (Philippe Gregoire) 4.5.0: 2017-07-20 * Types: Fix install types (Steven Armstrong) From 997fdd8ac4e6066dbaa0926d58c3a33d2feeead9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sun, 20 Aug 2017 15:13:01 -0400 Subject: [PATCH 0591/1332] fix typo in group entry extraction --- cdist/conf/type/__user/explorer/group | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__user/explorer/group b/cdist/conf/type/__user/explorer/group index b95f3d01..5b9ab5c4 100755 --- a/cdist/conf/type/__user/explorer/group +++ b/cdist/conf/type/__user/explorer/group @@ -26,7 +26,7 @@ if [ -f "$__object/parameter/gid" ]; then if [ -x /usr/bin/getent ] || [ -x /bin/getent ]; then getent group "$gid" || true elif [ -f /etc/group ]; then - grep -E "^(${gid}|([^:]:){2}${gid}):" /etc/group || true + grep -E "^(${gid}|([^:]+:){2}${gid}):" /etc/group || true fi fi From 31e5c97c551ac3a877163aea34d48182941fb212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Mon, 21 Aug 2017 10:51:48 -0400 Subject: [PATCH 0592/1332] use command(1) to get executable's path --- cdist/conf/type/__user/explorer/group | 5 +++-- cdist/conf/type/__user/explorer/passwd | 5 +++-- cdist/conf/type/__user/explorer/shadow | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__user/explorer/group b/cdist/conf/type/__user/explorer/group index 5b9ab5c4..2aae2973 100755 --- a/cdist/conf/type/__user/explorer/group +++ b/cdist/conf/type/__user/explorer/group @@ -23,8 +23,9 @@ if [ -f "$__object/parameter/gid" ]; then gid=$(cat "$__object/parameter/gid") - if [ -x /usr/bin/getent ] || [ -x /bin/getent ]; then - getent group "$gid" || true + getent=$(command -v getent) + if [ X != X"${getent}" ]; then + "${getent}" group "$gid" || true elif [ -f /etc/group ]; then grep -E "^(${gid}|([^:]+:){2}${gid}):" /etc/group || true fi diff --git a/cdist/conf/type/__user/explorer/passwd b/cdist/conf/type/__user/explorer/passwd index 592d04c4..677e3ff0 100755 --- a/cdist/conf/type/__user/explorer/passwd +++ b/cdist/conf/type/__user/explorer/passwd @@ -23,8 +23,9 @@ name=$__object_id -if [ -x /usr/bin/getent ] || [ -x /bin/getent ]; then - getent passwd "$name" || true +getent=$(command -v getent) +if [ X != X"${getent}" ]; then + "${getent}" passwd "$name" || true elif [ -f /etc/passwd ]; then grep "^${name}:" /etc/passwd || true fi diff --git a/cdist/conf/type/__user/explorer/shadow b/cdist/conf/type/__user/explorer/shadow index b2d1d121..1e6658d4 100755 --- a/cdist/conf/type/__user/explorer/shadow +++ b/cdist/conf/type/__user/explorer/shadow @@ -31,8 +31,9 @@ case "$os" in esac -if [ -x /usr/bin/getent ] || [ -x /bin/getent ]; then - getent "$database" "$name" || true +getent=$(command -v getent) +if [ X != X"${getent}" ]; then + "${getent}" "$database" "$name" || true elif [ -f /etc/shadow ]; then grep "^${name}:" /etc/shadow || true fi From f368539447fb67a0c9dd7a79df58d05278832234 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 22 Aug 2017 10:58:30 +0200 Subject: [PATCH 0593/1332] Some pylint cleaning. --- cdist/banner.py | 2 -- cdist/config.py | 11 +++++------ cdist/core/code.py | 2 -- cdist/emulator.py | 4 ++-- cdist/exec/local.py | 2 -- cdist/exec/remote.py | 2 -- cdist/exec/util.py | 1 - cdist/message.py | 2 -- cdist/shell.py | 1 - scripts/cdist | 4 +--- 10 files changed, 8 insertions(+), 23 deletions(-) diff --git a/cdist/banner.py b/cdist/banner.py index edfa72e8..da4dea5d 100644 --- a/cdist/banner.py +++ b/cdist/banner.py @@ -20,8 +20,6 @@ # import logging -import sys - import cdist log = logging.getLogger(__name__) diff --git a/cdist/config.py b/cdist/config.py index 14533237..3e786272 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -27,7 +27,6 @@ import sys import time import itertools import tempfile -import socket import multiprocessing from cdist.mputil import mp_pool_run, mp_sig_handler import atexit @@ -49,14 +48,17 @@ class Config(object): """Cdist main class to hold arbitrary data""" def __init__(self, local, remote, dry_run=False, jobs=None, - cleanup_cmds=[]): + cleanup_cmds=None): self.local = local self.remote = remote self._open_logger() self.dry_run = dry_run self.jobs = jobs - self.cleanup_cmds = cleanup_cmds + if cleanup_cmds: + self.cleanup_cmds = cleanup_cmds + else: + self.cleanup_cmds = [] self.explorer = core.Explorer(self.local.target_host, self.local, self.remote, jobs=self.jobs) @@ -111,7 +113,6 @@ class Config(object): if not (args.hostfile or args.host): args.hostfile = '-' - initial_manifest_tempfile = None if args.manifest == '-': # read initial manifest from stdin try: @@ -623,8 +624,6 @@ class Config(object): raise cdist.Error(("Attempting to run an already finished " "object: %s"), cdist_object) - cdist_type = cdist_object.cdist_type - # Generate self.log.debug("Generating code for %s" % (cdist_object.name)) cdist_object.code_local = self.code.run_gencode_local(cdist_object) diff --git a/cdist/core/code.py b/cdist/core/code.py index 173d192d..94ede0f9 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -23,8 +23,6 @@ import os -import cdist - ''' common: diff --git a/cdist/emulator.py b/cdist/emulator.py index bba46260..f1419ceb 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -98,7 +98,7 @@ class Emulator(object): self.init_object() # locking for parallel execution - with flock.Flock(self.flock_path) as lock: + with flock.Flock(self.flock_path): self.setup_object() self.save_stdin() self.record_requirements() @@ -112,7 +112,7 @@ class Emulator(object): if '__cdist_loglevel' in self.env: try: level = int(self.env['__cdist_loglevel']) - except: + except ValueError: level = logging.WARNING else: level = logging.WARNING diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 23ad4ce9..7726c604 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -21,7 +21,6 @@ # # -import io import os import sys import re @@ -348,7 +347,6 @@ class Local(object): continue for entry in os.listdir(current_dir): - rel_entry_path = os.path.join(sub_dir, entry) src = os.path.abspath(os.path.join(conf_dir, sub_dir, entry)) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 10b43e15..85cd193d 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -20,9 +20,7 @@ # # -import io import os -import sys import glob import subprocess import logging diff --git a/cdist/exec/util.py b/cdist/exec/util.py index 9ed7103b..b71b9bcc 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -20,7 +20,6 @@ # import subprocess -import sys from tempfile import TemporaryFile import cdist diff --git a/cdist/message.py b/cdist/message.py index 98a6e8cf..450fc3c3 100644 --- a/cdist/message.py +++ b/cdist/message.py @@ -24,8 +24,6 @@ import os import shutil import tempfile -import cdist - log = logging.getLogger(__name__) diff --git a/cdist/shell.py b/cdist/shell.py index 44cdd49d..a9457aaf 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -21,7 +21,6 @@ import logging import os -import subprocess import tempfile # initialise cdist diff --git a/scripts/cdist b/scripts/cdist index d9dce35f..384610b1 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -21,7 +21,6 @@ # # -import collections import logging @@ -34,8 +33,6 @@ def commandline(): import cdist.install import cdist.shell import cdist.inventory - import shutil - import os parser = cdist.argparse.get_parsers() args = parser['main'].parse_args(sys.argv[1:]) @@ -64,6 +61,7 @@ def commandline(): cdist.argparse.check_beta(vars(args)) args.func(args) + if __name__ == "__main__": import sys From 4851c0517f2fadbd294c9319e9d36947acb61e76 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 24 Aug 2017 14:43:26 +0200 Subject: [PATCH 0594/1332] inherit log level from cdist install during nested cdist config Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/gencode-local | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 6682ce0a..29d9c121 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -23,8 +23,20 @@ remote_exec="$__type/files/remote/exec" remote_copy="$__type/files/remote/copy" cdist_args="" -[ "$__verbose" = "yes" ] && cdist_args="-vv" -[ "$__debug" = "yes" ] && cdist_args="-d" +case "$__cdist_loglevel" in + 20) + cdist_args="-v" + ;; + 15) + cdist_args="-vv" + ;; + 10) + cdist_args="-vvv" + ;; + 5) + cdist_args="-vvvv" + ;; +esac cat << DONE cdist config \ From d9cf1590b89cd2219ebbff350ca5fa16497c7301 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 25 Aug 2017 10:50:11 +0200 Subject: [PATCH 0595/1332] Fix spelling. --- cdist/argparse.py | 2 +- docs/src/man1/cdist.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 849b19d2..4501774c 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -177,7 +177,7 @@ def get_parsers(): '-R', '--use-archiving', nargs='?', choices=('tar', 'tgz', 'tbz2', 'txz',), help=('Operate by using archiving with compression where ' - 'apropriate. Supported values are: tar - tar archive, ' + 'appropriate. Supported values are: tar - tar archive, ' 'tgz - gzip tar archive (the default), ' 'tbz2 - bzip2 tar archive and txz - lzma tar archive. ' 'Currently in beta.'), diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index c494ff57..79485594 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -171,7 +171,7 @@ Install command is currently in beta. .. option:: -R [{tar,tgz,tbz2,txz}], --use-archiving [{tar,tgz,tbz2,txz}] Operate by using archiving with compression where - apropriate. Supported values are: tar - tar archive, + appropriate. Supported values are: tar - tar archive, tgz - gzip tar archive (the default), tbz2 - bzip2 tar archive and txz - lzma tar archive. Currently in beta. From ebdab4c43ad12084e1c1e0679ea3fa7bc29a887e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 25 Aug 2017 10:51:09 +0200 Subject: [PATCH 0596/1332] Release 4.6.0 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 51340bc3..aac2142e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.6.0: 2017-08-25 * Core: Add inventory functionality (Darko Poljak) * Core: Expose inventory host tags in __target_host_tags env var (Darko Poljak) * Type __timezone: Check current timezone before doing anything (Ander Punnar) From 9f2a2169fa79bf90438ab969be08f6fe5140007e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 25 Aug 2017 11:34:43 +0200 Subject: [PATCH 0597/1332] Update changelog --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index aac2142e..07201e0a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,10 @@ Changelog --------- +next: + * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) + * Explorer init: Use pgrep instead of ps for Linux (Philippe Gregoire) + 4.6.0: 2017-08-25 * Core: Add inventory functionality (Darko Poljak) * Core: Expose inventory host tags in __target_host_tags env var (Darko Poljak) From 6f04c9bfce56189a1cf72b50bcf19239f4a0e9e1 Mon Sep 17 00:00:00 2001 From: Mark Verboom Date: Fri, 25 Aug 2017 14:31:32 +0200 Subject: [PATCH 0598/1332] Explorer pipes output of apt-key list, which always generates: Warning: apt-key output should not be parsed (stdout is not a terminal) on stderr. Redirect stderr of apt-key to /dev/null to prevent output in cdist run. --- cdist/conf/type/__apt_key_uri/explorer/state | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_key_uri/explorer/state b/cdist/conf/type/__apt_key_uri/explorer/state index 15d6e653..6f607607 100755 --- a/cdist/conf/type/__apt_key_uri/explorer/state +++ b/cdist/conf/type/__apt_key_uri/explorer/state @@ -27,6 +27,6 @@ else name="$__object_id" fi -apt-key list | grep -Fqe "$name" \ +apt-key list 2> /dev/null | grep -Fqe "$name" \ && echo present \ || echo absent From 7584e3c46512c0214974c266a3d0d8dff05add89 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 25 Aug 2017 19:15:34 +0200 Subject: [PATCH 0599/1332] Update changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 07201e0a..bbc884e8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) * Explorer init: Use pgrep instead of ps for Linux (Philippe Gregoire) + * Type __apt_key_uri: Redirect stderr of apt-key to /dev/null (Mark Verboom) 4.6.0: 2017-08-25 * Core: Add inventory functionality (Darko Poljak) From 56adfd4dee7b956826cca030f2617ad844f6f04f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sat, 26 Aug 2017 09:36:59 -0400 Subject: [PATCH 0600/1332] __package_pkg_openbsd: support using /etc/installurl In 6.1, OpenBSD introduced installurl(5), which contains the URL the sets where installed from during install or upgrade. The content of this file is used by pkg_add(1) if PKG_PATH is not defined. This commit changes the behavior of __package_pkg_openbsd to omit setting PKG_PATH to a hard-coded value if --pkg_path is not provided. This, in turn, makes pkg_add(1) use installurl(5). --- .../explorer/has_installurl | 36 +++++++++++++++++++ .../type/__package_pkg_openbsd/gencode-remote | 10 ++++-- 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100755 cdist/conf/type/__package_pkg_openbsd/explorer/has_installurl diff --git a/cdist/conf/type/__package_pkg_openbsd/explorer/has_installurl b/cdist/conf/type/__package_pkg_openbsd/explorer/has_installurl new file mode 100755 index 00000000..68337cbb --- /dev/null +++ b/cdist/conf/type/__package_pkg_openbsd/explorer/has_installurl @@ -0,0 +1,36 @@ +#!/bin/sh +# +# Copyright 2017, Philippe Gregoire +# +# 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 . +# + +# +# Retrieve the installurl(5), as introduced in OpenBSD 6.1 +# +# As of 6.1, the file is supposed to contained a single line +# with the URL used to install from during install or upgrade. +# +# Allow for expansion and take the first non-commented (#) line. +# + +if [ -f /etc/installurl ]; then + printf 'yes' +else + printf 'no' +fi + +exit 0 diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index a10e2e86..e86cb160 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -63,7 +63,11 @@ pkg_version="$(cat "$__object/explorer/pkg_version")" if [ -f "$__object/parameter/pkg_path" ]; then pkg_path="$(cat "$__object/parameter/pkg_path")" else - pkg_path="ftp://ftp.openbsd.org/pub/OpenBSD/$os_version/packages/$machine/" + has_installurl=$(cat "${__object}/explorer/has_installurl") + if [ Xyes != X"${has_installurl}" ]; then + # there is no default PKG_PATH, try to provide one + pkg_path="ftp://ftp.openbsd.org/pub/OpenBSD/$os_version/packages/$machine/" + fi fi if [ "$pkg_version" ]; then @@ -78,7 +82,9 @@ case "$state_should" in present) # use this because pkg_add doesn't properly handle errors cat << eof -export PKG_PATH="$pkg_path" +if [ X != X"${pkg_path}" ]; then + PKG_PATH="${pkg_path}"; export PKG_PATH +fi status=\$(pkg_add "$pkgopts" "$pkgid" 2>&1) pkg_info | grep "^${name}.*${version}.*${flavor}" > /dev/null 2>&1 From d4f34a3f406f8ff51783abd97f6236ccefbc4f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sat, 26 Aug 2017 10:59:04 -0400 Subject: [PATCH 0601/1332] __package_pkg_openbsd: support the empty flavor Adds support for specifying an empty flavor by passing --flavor "". --- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index a10e2e86..2a5bf89a 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -52,6 +52,8 @@ elif [ -n "$version" ]; then pkgid="$name-$version" elif [ -n "$flavor" ]; then pkgid="$name--$flavor" +elif [ -f "$__object/parameter/flavor" ]; then + pkgid="$name--" else pkgid="$name" fi From f4c4ba7267f2ea1be8a826524d875c27330915ff Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 27 Aug 2017 14:23:56 +0200 Subject: [PATCH 0602/1332] Update changelog. --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index bbc884e8..478c1d58 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,8 @@ next: * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) * Explorer init: Use pgrep instead of ps for Linux (Philippe Gregoire) * Type __apt_key_uri: Redirect stderr of apt-key to /dev/null (Mark Verboom) + * Type __package_pkg_openbsd: Support the empty flavor (Philippe Gregoire) + * Type __package_pkg_openbsd: Support using /etc/installurl (Philippe Gregoire) 4.6.0: 2017-08-25 * Core: Add inventory functionality (Darko Poljak) From 0e3c7545cc2d082c2f7a1b381058c46e0d064fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Sun, 27 Aug 2017 08:56:34 -0400 Subject: [PATCH 0603/1332] __user_groups: Support OpenBSD OpenBSD's usermod(8) interface is similary to NetBSD's. This commit makes __user_groups support it explicitly. https://man.openbsd.org/usermod.8 http://netbsd.gw.com/cgi-bin/man-cgi?usermod++NetBSD-current --- cdist/conf/type/__user_groups/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__user_groups/gencode-remote b/cdist/conf/type/__user_groups/gencode-remote index a69d6997..8120761a 100755 --- a/cdist/conf/type/__user_groups/gencode-remote +++ b/cdist/conf/type/__user_groups/gencode-remote @@ -42,10 +42,10 @@ if [ -z "$changed_groups" ]; then fi for group in $changed_groups; do - if [ "$os" = "netbsd" ]; then + if [ "$os" = "netbsd" ] || [ "$os" = "openbsd" ]; then case "$state_should" in present) echo "usermod -G \"$group\" \"$user\"" ;; - absent) echo 'NetBSD does not have a command to remove a user from a group' >&2 ; exit 1 ;; + absent) echo 'NetBSD and OpenBSD do not have a command to remove a user from a group' >&2 ; exit 1 ;; esac elif [ "$os" = "freebsd" ]; then case "$state_should" in From 74f0664333337593c229591565e33aa3131e9150 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 27 Aug 2017 15:25:14 +0200 Subject: [PATCH 0604/1332] Update changelog. --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 478c1d58..8ca5c08f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: * Type __apt_key_uri: Redirect stderr of apt-key to /dev/null (Mark Verboom) * Type __package_pkg_openbsd: Support the empty flavor (Philippe Gregoire) * Type __package_pkg_openbsd: Support using /etc/installurl (Philippe Gregoire) + * Type __user_groups: Support OpenBSD (Philippe Gregoire) 4.6.0: 2017-08-25 * Core: Add inventory functionality (Darko Poljak) From e9f8cb6f499cf6a622503475657caa0703c301f4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 28 Aug 2017 18:01:00 +0200 Subject: [PATCH 0605/1332] Install using distutils from cloned repo. --- Makefile | 2 +- docs/src/cdist-install.rst | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 417140c5..e33be3f2 100644 --- a/Makefile +++ b/Makefile @@ -198,7 +198,7 @@ archlinux-release: $(ARCHLINUX_FILE) # Release # -$(PYTHON_VERSION): .git/refs/heads/master +$(PYTHON_VERSION) version: .git/refs/heads/master $(helper) version # Code that is better handled in a shell script diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst index 1e1e8245..f9feef36 100644 --- a/docs/src/cdist-install.rst +++ b/docs/src/cdist-install.rst @@ -40,6 +40,20 @@ To install cdist, execute the following commands: cd cdist export PATH=$PATH:$(pwd -P)/bin +To install cdist with distutils from cloned repository, first you have to +create version.py: + +.. code-block:: sh + + make version + +Then, as usual, you execute the following command: + +.. code-block:: sh + + python setup.py install + + Available versions in git ^^^^^^^^^^^^^^^^^^^^^^^^^ From 04c8415060ddb164fa37ab053abc8e678803d8a8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 Aug 2017 21:49:47 +0200 Subject: [PATCH 0606/1332] use __remote_{exec,copy} instead of plain ssh/scp in remote exec scripts Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/files/remote/copy | 8 +++----- cdist/conf/type/__install_config/files/remote/exec | 10 ++++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/cdist/conf/type/__install_config/files/remote/copy b/cdist/conf/type/__install_config/files/remote/copy index df6a3f06..176b92bf 100755 --- a/cdist/conf/type/__install_config/files/remote/copy +++ b/cdist/conf/type/__install_config/files/remote/copy @@ -1,6 +1,6 @@ -#!/bin/sh +#!/bin/sh -e # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -32,8 +32,6 @@ log() { chroot="$1"; shift target_host="$__target_host" -scp="scp -o User=root -q" - # postfix target_host with chroot location code="$(echo "$@" | sed "s|$target_host:|$target_host:$chroot|g")" @@ -43,6 +41,6 @@ log "@: $@" log "code: $code" # copy files into chroot -$scp $code +$__remote_copy $code log "-----" diff --git a/cdist/conf/type/__install_config/files/remote/exec b/cdist/conf/type/__install_config/files/remote/exec index 17375693..e90eb415 100755 --- a/cdist/conf/type/__install_config/files/remote/exec +++ b/cdist/conf/type/__install_config/files/remote/exec @@ -1,6 +1,6 @@ -#!/bin/sh +#!/bin/sh -e # -# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -34,11 +34,9 @@ target_host="$__target_host" # In exec mode the first argument is the __target_host which we already got from env. Get rid of it. shift -ssh="ssh -o User=root -q $target_host" - # escape ' with '"'"' code="$(echo "$@" | sed -e "s/'/'\"'\"'/g")" -code="$ssh chroot $chroot sh -c '$code'" +code="chroot $chroot sh -e -c '$code'" log "target_host: $target_host" log "chroot: $chroot" @@ -46,6 +44,6 @@ log "@: $@" log "code: $code" # Run the code -$code +$__remote_exec $target_host $code log "-----" From 01140016279379234e87b2addf62a76807950d07 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 Aug 2017 22:31:30 +0200 Subject: [PATCH 0607/1332] remember default __remote_{copy,exec} so we can use it ourself in custom __remote_{copy,exec} scripts Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/files/remote/copy | 2 +- cdist/conf/type/__install_config/files/remote/exec | 2 +- cdist/conf/type/__install_config/gencode-local | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_config/files/remote/copy b/cdist/conf/type/__install_config/files/remote/copy index 176b92bf..15c901f9 100755 --- a/cdist/conf/type/__install_config/files/remote/copy +++ b/cdist/conf/type/__install_config/files/remote/copy @@ -41,6 +41,6 @@ log "@: $@" log "code: $code" # copy files into chroot -$__remote_copy $code +$__default_remote_copy $code log "-----" diff --git a/cdist/conf/type/__install_config/files/remote/exec b/cdist/conf/type/__install_config/files/remote/exec index e90eb415..5b25e41e 100755 --- a/cdist/conf/type/__install_config/files/remote/exec +++ b/cdist/conf/type/__install_config/files/remote/exec @@ -44,6 +44,6 @@ log "@: $@" log "code: $code" # Run the code -$__remote_exec $target_host $code +$__default_remote_exec $target_host $code log "-----" diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 29d9c121..d7e98734 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -39,6 +39,8 @@ case "$__cdist_loglevel" in esac cat << DONE +export __default_remote_exec="$__remote_exec" +export __default_remote_copy="$__remote_copy" cdist config \ $cdist_args \ --remote-exec="$remote_exec $chroot" \ From 3c3b29f7106a5a277d074fccffc6c2ed4852ed85 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 Aug 2017 22:50:47 +0200 Subject: [PATCH 0608/1332] allow hostnamectl to fail silently Signed-off-by: Steven Armstrong --- cdist/conf/type/__hostname/gencode-remote | 35 ++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index bf09ba0c..f5b09da2 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh -e # -# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014-2017 Steven Armstrong (steven-cdist at armstrong.cc) # 2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. @@ -56,20 +56,23 @@ esac # echo changed >> "$__messages_out" +# Use the good old way to set the hostname even on machines running systemd. +case "$os" in + archlinux|debian|ubuntu|devuan|centos) + echo "printf '%s\n' '$name_should' > /etc/hostname" + echo "hostname -F /etc/hostname" + ;; + openbsd) + echo "hostname '$name_should'" + ;; + suse) + echo "hostname '$name_should'" + echo "printf '%s\n' '$name_should' > /etc/HOSTNAME" + ;; +esac + if [ "$has_hostnamectl" ]; then - echo "hostnamectl set-hostname '$name_should'" -else - case "$os" in - archlinux|debian|ubuntu|devuan) - echo "hostname '$name_should'" - echo "printf '%s\n' '$name_should' > /etc/hostname" - ;; - centos|openbsd) - echo "hostname '$name_should'" - ;; - suse) - echo "hostname '$name_should'" - echo "printf '%s\n' '$name_should' > /etc/HOSTNAME" - ;; - esac + # Allow hostnamectl set-hostname to fail silently. + # Who the fuck invented a tool that needs dbus to set the hostname anyway ... + echo "hostnamectl set-hostname '$name_should' || true" fi From de9254d4c0c3d4258b55ce4714d86702ecfdfe05 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 29 Aug 2017 22:50:57 +0200 Subject: [PATCH 0609/1332] changelog++ Signed-off-by: Steven Armstrong --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 8ca5c08f..b1c7a100 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,8 @@ next: * Type __package_pkg_openbsd: Support the empty flavor (Philippe Gregoire) * Type __package_pkg_openbsd: Support using /etc/installurl (Philippe Gregoire) * Type __user_groups: Support OpenBSD (Philippe Gregoire) + * Type __hostname: Allow hostnamectl to fail silently (Steven Armstrong) + * Type __install_config: Use default default __remote_{copy,exec} in custom __remote_{copy,exec} scripts (Steven Armstrong) 4.6.0: 2017-08-25 * Core: Add inventory functionality (Darko Poljak) From eae399b025bc03fc3ee30961850ce37abc85ed23 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Aug 2017 09:27:06 +0200 Subject: [PATCH 0610/1332] Fix removing ssh key that is last one in the file. --- cdist/conf/type/__ssh_authorized_key/explorer/entry | 2 +- docs/changelog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__ssh_authorized_key/explorer/entry b/cdist/conf/type/__ssh_authorized_key/explorer/entry index 78031ab5..40ee0cb9 100755 --- a/cdist/conf/type/__ssh_authorized_key/explorer/entry +++ b/cdist/conf/type/__ssh_authorized_key/explorer/entry @@ -23,4 +23,4 @@ type_and_key="$(cat "$__object/parameter/key" | tr ' ' '\n' | awk '/^(ssh|ecdsa) file="$(cat $__object/parameter/file)" # get any entries that match the type and key -grep ".*$type_and_key[ \n]" "$file" || true +grep ".*$type_and_key\([ \n]\|$\)" "$file" || true diff --git a/docs/changelog b/docs/changelog index b1c7a100..2d954c29 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Type __user_groups: Support OpenBSD (Philippe Gregoire) * Type __hostname: Allow hostnamectl to fail silently (Steven Armstrong) * Type __install_config: Use default default __remote_{copy,exec} in custom __remote_{copy,exec} scripts (Steven Armstrong) + * Type __ssh_authorized_key: Fix removing ssh key that is last one in the file (Darko Poljak) 4.6.0: 2017-08-25 * Core: Add inventory functionality (Darko Poljak) From 4b2f23db62663d60d3204a238e0a6c5310700f26 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Aug 2017 22:41:48 +0200 Subject: [PATCH 0611/1332] Release 4.6.1 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 2d954c29..7777a946 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) * Explorer init: Use pgrep instead of ps for Linux (Philippe Gregoire) * Type __apt_key_uri: Redirect stderr of apt-key to /dev/null (Mark Verboom) From bdee7273af7d4960ca85511bb460737fc504cad8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Aug 2017 23:02:17 +0200 Subject: [PATCH 0612/1332] Configfile (#559) Add cdist configuration/config file support. --- cdist/argparse.py | 49 +- cdist/config.py | 26 +- cdist/configuration.py | 421 ++++++++ cdist/exec/local.py | 28 +- cdist/exec/remote.py | 12 +- cdist/inventory.py | 67 +- cdist/test/configuration/__init__.py | 1076 +++++++++++++++++++ cdist/test/configuration/fixtures/.nonempty | 0 cdist/test/exec/local.py | 6 + docs/src/man1/cdist.rst | 223 ++-- scripts/cdist | 28 +- 11 files changed, 1800 insertions(+), 136 deletions(-) create mode 100644 cdist/configuration.py create mode 100644 cdist/test/configuration/__init__.py create mode 100644 cdist/test/configuration/fixtures/.nonempty diff --git a/cdist/argparse.py b/cdist/argparse.py index 4501774c..f0ea802a 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -1,9 +1,9 @@ import argparse import cdist import multiprocessing -import os import logging import collections +import cdist.configuration # set of beta sub-commands @@ -115,7 +115,7 @@ def get_parsers(): '-b', '--beta', help=('Enable beta functionality. '), action='store_true', dest='beta', - default='CDIST_BETA' in os.environ) + default=False) # Main subcommand parser parser['main'] = argparse.ArgumentParser( @@ -136,12 +136,18 @@ def get_parsers(): '-I', '--inventory', help=('Use specified custom inventory directory. ' 'Inventory directory is set up by the following rules: ' - 'if this argument is set then specified directory is used, ' - 'if CDIST_INVENTORY_DIR env var is set then its value is ' - 'used, if HOME env var is set then ~/.cdist/inventory is ' + 'if cdist configuration resolves this value then specified ' + 'directory is used, ' + 'if HOME env var is set then ~/.cdist/inventory is ' 'used, otherwise distribution inventory directory is used.'), dest="inventory_dir", required=False) + parser['common'] = argparse.ArgumentParser(add_help=False) + parser['common'].add_argument( + '-g', '--config-file', + help=('Use specified custom configuration file.'), + dest="config_file", required=False) + # Config parser['config_main'] = argparse.ArgumentParser(add_help=False) parser['config_main'].add_argument( @@ -149,7 +155,7 @@ def get_parsers(): help=('Specify custom cache path pattern. If ' 'it is not set then default hostdir is used.'), dest='cache_path_pattern', - default=os.environ.get('CDIST_CACHE_PATH_PATTERN')) + default=None) parser['config_main'].add_argument( '-c', '--conf-dir', help=('Add configuration directory (can be repeated, ' @@ -195,13 +201,13 @@ def get_parsers(): '--remote-copy', help='Command to use for remote copy (should behave like scp).', action='store', dest='remote_copy', - default=os.environ.get('CDIST_REMOTE_COPY')) + default=None) parser['config_main'].add_argument( '--remote-exec', help=('Command to use for remote execution ' '(should behave like ssh).'), action='store', dest='remote_exec', - default=os.environ.get('CDIST_REMOTE_EXEC')) + default=None) # Config parser['config_args'] = argparse.ArgumentParser(add_help=False) @@ -243,6 +249,7 @@ def get_parsers(): dest='tag', required=False, action="store_true", default=False) parser['config'] = parser['sub'].add_parser( 'config', parents=[parser['loglevel'], parser['beta'], + parser['common'], parser['config_main'], parser['inventory_common'], parser['config_args']]) @@ -256,12 +263,14 @@ def get_parsers(): # Inventory parser['inventory'] = parser['sub'].add_parser( 'inventory', parents=[parser['loglevel'], parser['beta'], + parser['common'], parser['inventory_common']]) parser['invsub'] = parser['inventory'].add_subparsers( title="Inventory commands", dest="subcommand") parser['add-host'] = parser['invsub'].add_parser( 'add-host', parents=[parser['loglevel'], parser['beta'], + parser['common'], parser['inventory_common']]) parser['add-host'].add_argument( 'host', nargs='*', help='Host(s) to add.') @@ -275,6 +284,7 @@ def get_parsers(): parser['add-tag'] = parser['invsub'].add_parser( 'add-tag', parents=[parser['loglevel'], parser['beta'], + parser['common'], parser['inventory_common']]) parser['add-tag'].add_argument( 'host', nargs='*', @@ -305,6 +315,7 @@ def get_parsers(): parser['del-host'] = parser['invsub'].add_parser( 'del-host', parents=[parser['loglevel'], parser['beta'], + parser['common'], parser['inventory_common']]) parser['del-host'].add_argument( 'host', nargs='*', help='Host(s) to delete.') @@ -321,6 +332,7 @@ def get_parsers(): parser['del-tag'] = parser['invsub'].add_parser( 'del-tag', parents=[parser['loglevel'], parser['beta'], + parser['common'], parser['inventory_common']]) parser['del-tag'].add_argument( 'host', nargs='*', @@ -355,6 +367,7 @@ def get_parsers(): parser['list'] = parser['invsub'].add_parser( 'list', parents=[parser['loglevel'], parser['beta'], + parser['common'], parser['inventory_common']]) parser['list'].add_argument( 'host', nargs='*', help='Host(s) to list.') @@ -401,3 +414,23 @@ def handle_loglevel(args): args.verbose = _verbosity_level_off logging.root.setLevel(_verbosity_level[args.verbose]) + + +def parse_and_configure(argv): + parser = get_parsers() + parser_args = parser['main'].parse_args(argv) + cfg = cdist.configuration.Configuration(parser_args) + args = cfg.get_args() + # Loglevels are handled globally in here + handle_loglevel(args) + + log = logging.getLogger("cdist") + + log.verbose("version %s" % cdist.VERSION) + log.trace('command line args: {}'.format(cfg.command_line_args)) + log.trace('configuration: {}'.format(cfg.get_config())) + log.trace('configured args: {}'.format(args)) + + check_beta(vars(args)) + + return parser, cfg diff --git a/cdist/config.py b/cdist/config.py index 3e786272..779365f3 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -31,15 +31,12 @@ import multiprocessing from cdist.mputil import mp_pool_run, mp_sig_handler import atexit import shutil - import cdist import cdist.hostsource - import cdist.exec.local import cdist.exec.remote - import cdist.util.ipaddr as ipaddr - +import cdist.configuration from cdist import core, inventory from cdist.util.remoteutil import inspect_ssh_mux_opts @@ -162,8 +159,11 @@ class Config(object): hostcnt = 0 + cfg = cdist.configuration.Configuration(args) + configuration = cfg.get_config(section='GLOBAL') + if args.tag or args.all_tagged_hosts: - inventory.determine_default_inventory_dir(args) + inventory.determine_default_inventory_dir(args, configuration) if args.all_tagged_hosts: inv_list = inventory.InventoryList( hosts=None, istag=True, hostfile=None, @@ -191,7 +191,7 @@ class Config(object): else: # if configuring by host then check inventory for tags host = entry - inventory.determine_default_inventory_dir(args) + inventory.determine_default_inventory_dir(args, configuration) inv_list = inventory.InventoryList( hosts=(host,), db_basedir=args.inventory_dir) inv = tuple(inv_list.entries()) @@ -208,14 +208,16 @@ class Config(object): hostcnt += 1 if args.parallel: - pargs = (host, host_tags, host_base_path, hostdir, args, True) + pargs = (host, host_tags, host_base_path, hostdir, args, True, + configuration) log.trace(("Args for multiprocessing operation " "for host {}: {}".format(host, pargs))) process_args.append(pargs) else: try: cls.onehost(host, host_tags, host_base_path, hostdir, - args, parallel=False) + args, parallel=False, + configuration=configuration) except cdist.Error as e: failed_hosts.append(host) if args.parallel and len(process_args) == 1: @@ -281,7 +283,7 @@ class Config(object): @classmethod def onehost(cls, host, host_tags, host_base_path, host_dir_name, args, - parallel): + parallel, configuration): """Configure ONE system. If operating in parallel then return tuple (host, True|False, ) so that main process knows for which host function was successful. @@ -308,7 +310,8 @@ class Config(object): initial_manifest=args.manifest, add_conf_dirs=args.conf_dir, cache_path_pattern=args.cache_path_pattern, - quiet_mode=args.quiet) + quiet_mode=args.quiet, + configuration=configuration) remote = cdist.exec.remote.Remote( target_host=target_host, @@ -316,7 +319,8 @@ class Config(object): remote_copy=remote_copy, base_path=args.remote_out_path, quiet_mode=args.quiet, - archiving_mode=args.use_archiving) + archiving_mode=args.use_archiving, + configuration=configuration) cleanup_cmds = [] if cleanup_cmd: diff --git a/cdist/configuration.py b/cdist/configuration.py new file mode 100644 index 00000000..fa9671d0 --- /dev/null +++ b/cdist/configuration.py @@ -0,0 +1,421 @@ +# -*- coding: utf-8 -*- +# +# 2017 Darko Poljak (darko.poljak 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 . +# +# + + +import configparser +import os +import cdist +import cdist.argparse +import re +import multiprocessing + + +class Singleton(type): + instance = None + + def __call__(cls, *args, **kwargs): + if not cls.instance: + cls.instance = super(Singleton, cls).__call__(*args, **kwargs) + return cls.instance + + +_VERBOSITY_VALUES = ( + 'ERROR', 'WARNING', 'INFO', 'VERBOSE', 'DEBUG', 'TRACE', 'OFF', +) +_ARCHIVING_VALUES = ( + 'tar', 'tgz', 'tbz2', 'txz', 'none', +) + + +class OptionBase: + def __init__(self, name): + self.name = name + + def converter(self, *args, **kwargs): + raise NotImplementedError('Subclass should implement this method') + + def translate(self, val): + return val + + def update_value(self, currval, newval, update_appends=False): + '''Update current option value currval with new option value newval. + If update_appends is True and if currval and newval are lists then + resulting list contains all values in currval plus all values in + newval. Otherwise, newval is returned. + ''' + if (isinstance(currval, list) and isinstance(newval, list) and + update_appends): + rv = [] + if currval: + rv.extend(currval) + if newval: + rv.extend(newval) + if not rv: + rv = None + return rv + else: + return newval + + +class StringOption(OptionBase): + def __init__(self, name): + super().__init__(name) + + def converter(self): + def string_converter(val): + return self.translate(str(val)) + return string_converter + + def translate(self, val): + if val: + return val + else: + return None + + +class BooleanOption(OptionBase): + BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES + + def __init__(self, name): + super().__init__(name) + + def converter(self): + def boolean_converter(val): + v = val.lower() + if v not in self.BOOLEAN_STATES: + raise ValueError('Invalid {} boolean value: {}'.format( + self.name, val)) + return self.translate(v) + return boolean_converter + + def translate(self, val): + return self.BOOLEAN_STATES[val] + + +class IntOption(OptionBase): + def __init__(self, name): + super().__init__(name) + + def converter(self): + def int_converter(val): + return self.translate(int(val)) + return int_converter + + +class LowerBoundIntOption(IntOption): + def __init__(self, name, lower_bound): + super().__init__(name) + self.lower_bound = lower_bound + + def converter(self): + def lower_bound_converter(val): + converted = super(LowerBoundIntOption, self).converter()(val) + if converted < self.lower_bound: + raise ValueError("Invalid {} value: {} < {}".format( + self.name, val, self.lower_bound)) + return converted + return lower_bound_converter + + +class SpecialCasesLowerBoundIntOption(LowerBoundIntOption): + def __init__(self, name, lower_bound, special_cases_mapping): + super().__init__(name, lower_bound) + self.special_cases_mapping = special_cases_mapping + + def translate(self, val): + if val in self.special_cases_mapping: + return self.special_cases_mapping[val] + else: + return val + + +class JobsOption(SpecialCasesLowerBoundIntOption): + def __init__(self, name): + super().__init__(name, -1, {-1: multiprocessing.cpu_count()}) + + +class SelectOption(OptionBase): + def __init__(self, name, valid_values): + super().__init__(name) + self.valid_values = valid_values + + def converter(self): + def select_converter(val): + if val in self.valid_values: + return self.translate(val) + else: + raise ValueError("Invalid {} value: {}.".format( + self.name, val)) + return select_converter + + +class VerbosityOption(SelectOption): + def __init__(self): + super().__init__('verbosity', _VERBOSITY_VALUES) + + def translate(self, val): + name = 'VERBOSE_' + val + verbose = getattr(cdist.argparse, name) + return verbose + + +class DelimitedValuesOption(OptionBase): + def __init__(self, name, delimiter): + super().__init__(name) + self.delimiter = delimiter + + def converter(self): + def delimited_values_converter(val): + vals = re.split(r'(?. +# +# + +import configparser +import os +import multiprocessing +import cdist.configuration as cc +import os.path as op +import argparse +from cdist import test +import cdist.argparse as cap + + +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') + + +class ConfigurationOptionsTestCase(test.CdistTestCase): + + def test_OptionBase(self): + option = cc.OptionBase('test') + test_cases = ( + ([], [], True, None, ), + (['spam', 'eggs', ], [], True, ['spam', 'eggs', ], ), + ([], ['spam', 'eggs', ], True, ['spam', 'eggs', ], ), + ( + ['spam', 'eggs', ], + ['ham', 'spamspam', ], + True, + ['spam', 'eggs', 'ham', 'spamspam', ], + ), + (['spam', 'eggs', ], 'spam:eggs', True, 'spam:eggs', ), + ('spam:eggs', ['spam', 'eggs', ], True, ['spam', 'eggs', ], ), + ('spam', 'eggs', True, 'eggs', ), + + (['spam', 'eggs', ], 'spam:eggs', True, 'spam:eggs', ), + + ('spam:eggs', ['spam', 'eggs', ], False, ['spam', 'eggs', ], ), + ('spam', 'eggs', False, 'eggs', ), + ( + ['spam', 'eggs', ], + ['ham', 'spamspam', ], + False, + ['ham', 'spamspam', ], + ), + ) + for currval, newval, update_appends, expected in test_cases: + self.assertEqual(option.update_value(currval, newval, + update_appends=update_appends), + expected) + + def test_StringOption(self): + option = cc.StringOption('test') + self.assertIsNone(option.translate('')) + self.assertEqual(option.translate('spam'), 'spam') + converter = option.converter() + self.assertEqual(converter('spam'), 'spam') + self.assertIsNone(converter('')) + + def test_BooleanOption(self): + option = cc.BooleanOption('test') + for x in cc.BooleanOption.BOOLEAN_STATES: + self.assertEqual(option.translate(x), + cc.BooleanOption.BOOLEAN_STATES[x]) + converter = option.converter() + self.assertRaises(ValueError, converter, 'of') + for x in cc.BooleanOption.BOOLEAN_STATES: + self.assertEqual(converter(x), cc.BooleanOption.BOOLEAN_STATES[x]) + + def test_IntOption(self): + option = cc.IntOption('test') + converter = option.converter() + self.assertRaises(ValueError, converter, 'x') + for x in range(-5, 10): + self.assertEqual(converter(str(x)), x) + + def test_LowerBoundIntOption(self): + option = cc.LowerBoundIntOption('test', -1) + converter = option.converter() + self.assertRaises(ValueError, converter, -2) + for x in range(-1, 10): + self.assertEqual(converter(str(x)), x) + + def test_SpecialCasesLowerBoundIntOption(self): + special_cases = { + -1: 8, + -2: 10, + } + option = cc.SpecialCasesLowerBoundIntOption('test', -1, special_cases) + for x in special_cases: + self.assertEqual(option.translate(x), special_cases[x]) + + def test_SelectOption(self): + valid_values = ('spam', 'eggs', 'ham', ) + option = cc.SelectOption('test', valid_values) + converter = option.converter() + self.assertRaises(ValueError, converter, 'spamspam') + for x in valid_values: + self.assertEqual(converter(x), x) + + def test_DelimitedValuesOption(self): + option = cc.DelimitedValuesOption('test', ':') + converter = option.converter() + value = 'spam:eggs::ham' + self.assertEqual(converter(value), ['spam', 'eggs', 'ham', ]) + self.assertIsNone(converter('')) + + +class ConfigurationTestCase(test.CdistTestCase): + + def setUp(self): + # Create test config file. + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'off', + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': '', + 'cache_path_pattern': '', + 'conf_dir': '', + 'init_manifest': '', + 'out_path': '', + 'remote_out_path': '', + 'remote_copy': '', + 'remote_exec': '', + 'jobs': '0', + 'parallel': '-1', + 'verbosity': 'INFO', + 'archiving': 'none', + } + config_custom = configparser.ConfigParser() + config_custom['GLOBAL'] = { + 'parallel': '4', + 'archiving': 'txz', + } + + config_custom2 = configparser.ConfigParser() + config_custom2['GLOBAL'] = { + 'parallel': '16', + 'archiving': 'tbz2', + 'remote_copy': 'myscp', + } + + self.expected_config_dict = { + 'GLOBAL': { + 'beta': False, + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': None, + 'cache_path_pattern': None, + 'conf_dir': None, + 'init_manifest': None, + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': None, + 'remote_exec': None, + 'jobs': 0, + 'parallel': multiprocessing.cpu_count(), + 'verbosity': cap.VERBOSE_INFO, + 'archiving': None, + }, + } + + self.config_file = os.path.join(fixtures, 'cdist.cfg') + with open(self.config_file, 'w') as f: + config.write(f) + + self.custom_config_file = os.path.join(fixtures, 'cdist_custom.cfg') + with open(self.custom_config_file, 'w') as f: + config_custom.write(f) + + self.custom_config_file2 = os.path.join(fixtures, 'cdist_custom2.cfg') + with open(self.custom_config_file2, 'w') as f: + config_custom2.write(f) + + config['TEST'] = {} + self.invalid_config_file1 = os.path.join(fixtures, + 'cdist_invalid1.cfg') + with open(self.invalid_config_file1, 'w') as f: + config.write(f) + + del config['TEST'] + config['GLOBAL']['test'] = 'test' + self.invalid_config_file2 = os.path.join(fixtures, + 'cdist_invalid2.cfg') + with open(self.invalid_config_file2, 'w') as f: + config.write(f) + + del config['GLOBAL']['test'] + config['GLOBAL']['archiving'] = 'zip' + self.invalid_config_file3 = os.path.join(fixtures, + 'cdist_invalid3.cfg') + with open(self.invalid_config_file3, 'w') as f: + config.write(f) + + self.maxDiff = None + + def tearDown(self): + os.remove(self.config_file) + os.remove(self.custom_config_file) + os.remove(self.custom_config_file2) + os.remove(self.invalid_config_file1) + os.remove(self.invalid_config_file2) + os.remove(self.invalid_config_file3) + + # remove files from tests + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + local_config_file = os.path.join(fixtures, 'cdist-local.cfg') + custom_config_file = os.path.join(fixtures, 'cdist-custom.cfg') + if os.path.exists(global_config_file): + os.remove(global_config_file) + if os.path.exists(local_config_file): + os.remove(local_config_file) + if os.path.exists(custom_config_file): + os.remove(custom_config_file) + + def test_singleton(self): + x = cc.Configuration(None) + args = argparse.Namespace() + args.a = 'a' + y = cc.Configuration() + self.assertIs(x, y) + + def test_read_config_file(self): + config = cc.Configuration(None, env={}, config_files=()) + d = config._read_config_file(self.config_file) + self.assertEqual(d, self.expected_config_dict) + + for x in range(1, 4): + config_file = getattr(self, 'invalid_config_file' + str(x)) + with self.assertRaises(ValueError): + config._read_config_file(config_file) + + def test_read_env_var_config(self): + config = cc.Configuration(None, env={}, config_files=()) + env = { + 'a': 'a', + 'CDIST_BETA': '1', + 'CDIST_PATH': '/usr/local/cdist:~/.cdist', + } + expected = { + 'beta': True, + 'conf_dir': ['/usr/local/cdist', '~/.cdist', ], + } + section = 'GLOBAL' + d = config._read_env_var_config(env, section) + self.assertEqual(d, expected) + + del env['CDIST_BETA'] + del expected['beta'] + d = config._read_env_var_config(env, section) + self.assertEqual(d, expected) + + def test_read_args_config(self): + config = cc.Configuration(None, env={}, config_files=()) + args = argparse.Namespace() + args.beta = False + args.conf_dir = ['/usr/local/cdist1', ] + args.verbose = 3 + args.tag = 'test' + + expected = { + 'beta': False, + 'conf_dir': ['/usr/local/cdist1', ], + 'verbosity': 3, + } + args_dict = vars(args) + d = config._read_args_config(args_dict) + self.assertEqual(d, expected) + self.assertNotEqual(d, args_dict) + + def test_update_config_dict(self): + config = { + 'GLOBAL': { + 'conf_dir': ['/usr/local/cdist', ], + 'parallel': -1, + }, + } + newconfig = { + 'GLOBAL': { + 'conf_dir': ['~/.cdist', ], + 'parallel': 2, + 'local_shell': '/usr/local/bin/sh', + }, + } + expected = { + 'GLOBAL': { + 'conf_dir': ['/usr/local/cdist', '~/.cdist', ], + 'parallel': 2, + 'local_shell': '/usr/local/bin/sh', + }, + } + configuration = cc.Configuration(None, env={}, config_files=()) + configuration._update_config_dict(config, newconfig, + update_appends=True) + self.assertEqual(config, expected) + expected = { + 'GLOBAL': { + 'conf_dir': ['~/.cdist', ], + 'parallel': 2, + 'local_shell': '/usr/local/bin/sh', + }, + } + configuration._update_config_dict(config, newconfig, + update_appends=False) + self.assertEqual(config, expected) + + def test_update_config_dict_section(self): + config = { + 'GLOBAL': { + 'conf_dir': ['/usr/local/cdist', ], + 'parallel': -1, + }, + } + newconfig = { + 'conf_dir': ['~/.cdist', ], + 'parallel': 2, + 'local_shell': '/usr/local/bin/sh', + } + expected = { + 'GLOBAL': { + 'conf_dir': ['/usr/local/cdist', '~/.cdist', ], + 'parallel': 2, + 'local_shell': '/usr/local/bin/sh', + }, + } + configuration = cc.Configuration(None, env={}, config_files=()) + configuration._update_config_dict_section('GLOBAL', config, newconfig, + update_appends=True) + self.assertEqual(config, expected) + expected = { + 'GLOBAL': { + 'conf_dir': ['~/.cdist', ], + 'parallel': 2, + 'local_shell': '/usr/local/bin/sh', + }, + } + configuration._update_config_dict_section('GLOBAL', config, newconfig, + update_appends=False) + self.assertEqual(config, expected) + + def test_configuration1(self): + env = { + 'PATH': '/usr/local/bin:/usr/bin:/bin', + 'TEST': 'test', + } + args = argparse.Namespace() + expected_config_dict = { + 'GLOBAL': { + }, + } + + # bypass singleton so we can test further + cc.Configuration.instance = None + configuration = cc.Configuration(args, env=env) + self.assertIsNotNone(configuration.args) + self.assertIsNotNone(configuration.env) + self.assertIsNotNone(configuration.config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration2(self): + env = { + 'PATH': '/usr/local/bin:/usr/bin:/bin', + 'TEST': 'test', + } + args = argparse.Namespace() + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'off', + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': '', + 'cache_path_pattern': '', + 'conf_dir': '', + 'init_manifest': '', + 'out_path': '', + 'remote_out_path': '', + 'remote_copy': '', + 'remote_exec': '', + 'jobs': '0', + 'parallel': '-1', + 'verbosity': 'INFO', + 'archiving': 'none', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'beta': False, + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': None, + 'cache_path_pattern': None, + 'conf_dir': None, + 'init_manifest': None, + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': None, + 'remote_exec': None, + 'jobs': 0, + 'parallel': multiprocessing.cpu_count(), + 'verbosity': cap.VERBOSE_INFO, + 'archiving': None, + }, + } + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + configuration = cc.Configuration(args, env=env, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration3(self): + env = { + 'PATH': '/usr/local/bin:/usr/bin:/bin', + 'TEST': 'test', + } + args = argparse.Namespace() + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'off', + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': '', + 'cache_path_pattern': '', + 'conf_dir': '', + 'init_manifest': '', + 'out_path': '', + 'remote_out_path': '', + 'remote_copy': '', + 'remote_exec': '', + 'jobs': '0', + 'parallel': '-1', + 'verbosity': 'INFO', + 'archiving': 'none', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'on', + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'conf_dir': '/opt/cdist', + 'remote_copy': 'myscp', + 'remote_exec': 'myexec', + 'parallel': '-1', + 'archiving': 'tar', + } + + local_config_file = os.path.join(fixtures, 'cdist-local.cfg') + with open(local_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'beta': True, + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'cache_path_pattern': None, + 'conf_dir': ['/opt/cdist', ], + 'init_manifest': None, + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': 'myscp', + 'remote_exec': 'myexec', + 'jobs': 0, + 'parallel': multiprocessing.cpu_count(), + 'verbosity': cap.VERBOSE_INFO, + 'archiving': 'tar', + }, + } + config_files = (global_config_file, local_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + configuration = cc.Configuration(args, env=env, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration4(self): + env = { + 'PATH': '/usr/local/bin:/usr/bin:/bin', + 'TEST': 'test', + 'CDIST_PATH': '/opt/cdist/conf:/usr/local/share/cdist/conf', + 'REMOTE_COPY': 'scp', + 'REMOTE_EXEC': 'ssh', + 'CDIST_BETA': '1', + 'CDIST_LOCAL_SHELL': '/usr/bin/sh', + 'CDIST_REMOTE_SHELL': '/usr/bin/sh', + } + args = argparse.Namespace() + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'off', + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': '', + 'cache_path_pattern': '', + 'conf_dir': '', + 'init_manifest': '', + 'out_path': '', + 'remote_out_path': '', + 'remote_copy': '', + 'remote_exec': '', + 'jobs': '0', + 'parallel': '-1', + 'verbosity': 'INFO', + 'archiving': 'none', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'beta': True, + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': None, + 'cache_path_pattern': None, + 'conf_dir': [ + '/opt/cdist/conf', + '/usr/local/share/cdist/conf', + ], + 'init_manifest': None, + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': None, + 'remote_exec': None, + 'jobs': 0, + 'parallel': multiprocessing.cpu_count(), + 'verbosity': cap.VERBOSE_INFO, + 'archiving': None, + }, + } + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + configuration = cc.Configuration(args, env=env, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration5(self): + env = { + 'PATH': '/usr/local/bin:/usr/bin:/bin', + 'TEST': 'test', + 'CDIST_PATH': '/opt/cdist/conf:/usr/local/share/cdist/conf', + 'REMOTE_COPY': 'scp', + 'REMOTE_EXEC': 'ssh', + 'CDIST_BETA': '1', + 'CDIST_LOCAL_SHELL': '/usr/bin/sh', + 'CDIST_REMOTE_SHELL': '/usr/bin/sh', + } + args = argparse.Namespace() + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'off', + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': '', + 'cache_path_pattern': '', + 'conf_dir': '', + 'init_manifest': '', + 'out_path': '', + 'remote_out_path': '', + 'remote_copy': '', + 'remote_exec': '', + 'jobs': '0', + 'parallel': '-1', + 'verbosity': 'INFO', + 'archiving': 'none', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'on', + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'conf_dir': '/opt/cdist', + 'remote_copy': 'myscp', + 'remote_exec': 'myexec', + 'parallel': '-1', + 'archiving': 'tar', + } + + local_config_file = os.path.join(fixtures, 'cdist-local.cfg') + with open(local_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'beta': True, + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'cache_path_pattern': None, + 'conf_dir': [ + '/opt/cdist/conf', + '/usr/local/share/cdist/conf', + ], + 'init_manifest': None, + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': 'myscp', + 'remote_exec': 'myexec', + 'jobs': 0, + 'parallel': multiprocessing.cpu_count(), + 'verbosity': cap.VERBOSE_INFO, + 'archiving': 'tar', + }, + } + config_files = (global_config_file, local_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + configuration = cc.Configuration(args, env=env, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration6(self): + env = { + 'PATH': '/usr/local/bin:/usr/bin:/bin', + 'TEST': 'test', + 'CDIST_PATH': '/opt/cdist/conf:/usr/local/share/cdist/conf', + 'REMOTE_COPY': 'scp', + 'REMOTE_EXEC': 'ssh', + 'CDIST_BETA': '1', + 'CDIST_LOCAL_SHELL': '/usr/bin/sh', + 'CDIST_REMOTE_SHELL': '/usr/bin/sh', + } + args = argparse.Namespace() + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'off', + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': '', + 'cache_path_pattern': '', + 'conf_dir': '', + 'init_manifest': '', + 'out_path': '', + 'remote_out_path': '', + 'remote_copy': '', + 'remote_exec': '', + 'jobs': '0', + 'parallel': '-1', + 'verbosity': 'INFO', + 'archiving': 'none', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'on', + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'conf_dir': '/opt/cdist', + 'remote_copy': 'myscp', + 'remote_exec': 'myexec', + 'parallel': '-1', + 'archiving': 'tar', + } + + local_config_file = os.path.join(fixtures, 'cdist-local.cfg') + with open(local_config_file, 'w') as f: + config.write(f) + + args.inventory_dir = '/opt/sysadmin/cdist/inventory' + args.conf_dir = ['/opt/sysadmin/cdist/conf', ] + args.manifest = '/opt/sysadmin/cdist/conf/manifest/init' + args.jobs = 10 + + expected_config_dict = { + 'GLOBAL': { + 'beta': True, + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/opt/sysadmin/cdist/inventory', + 'cache_path_pattern': None, + 'conf_dir': [ + '/opt/cdist/conf', + '/usr/local/share/cdist/conf', + '/opt/sysadmin/cdist/conf', + ], + 'init_manifest': '/opt/sysadmin/cdist/conf/manifest/init', + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': 'myscp', + 'remote_exec': 'myexec', + 'jobs': 10, + 'parallel': multiprocessing.cpu_count(), + 'verbosity': cap.VERBOSE_INFO, + 'archiving': 'tar', + }, + } + config_files = (global_config_file, local_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + configuration = cc.Configuration(args, env=env, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration7(self): + env = { + 'PATH': '/usr/local/bin:/usr/bin:/bin', + 'TEST': 'test', + 'CDIST_PATH': '/opt/cdist/conf:/usr/local/share/cdist/conf', + 'REMOTE_COPY': 'scp', + 'REMOTE_EXEC': 'ssh', + 'CDIST_BETA': '1', + 'CDIST_LOCAL_SHELL': '/usr/bin/sh', + 'CDIST_REMOTE_SHELL': '/usr/bin/sh', + } + args = argparse.Namespace() + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'off', + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': '', + 'cache_path_pattern': '', + 'conf_dir': '', + 'init_manifest': '', + 'out_path': '', + 'remote_out_path': '', + 'remote_copy': '', + 'remote_exec': '', + 'jobs': '0', + 'parallel': '-1', + 'verbosity': 'INFO', + 'archiving': 'none', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'on', + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'conf_dir': '/opt/cdist', + 'remote_copy': 'myscp', + 'remote_exec': 'myexec', + 'parallel': '-1', + 'archiving': 'tar', + } + + local_config_file = os.path.join(fixtures, 'cdist-local.cfg') + with open(local_config_file, 'w') as f: + config.write(f) + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'conf_dir': '/opt/conf/cdist', + 'remote_copy': 'scpcustom', + 'remote_exec': 'sshcustom', + 'parallel': '15', + 'archiving': 'txz', + } + + custom_config_file = os.path.join(fixtures, 'cdist-custom.cfg') + with open(custom_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'beta': True, + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'cache_path_pattern': None, + 'conf_dir': [ + '/opt/conf/cdist', + ], + 'init_manifest': None, + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': 'scpcustom', + 'remote_exec': 'sshcustom', + 'jobs': 0, + 'parallel': 15, + 'verbosity': cap.VERBOSE_INFO, + 'archiving': 'txz', + }, + } + + config_files = (global_config_file, local_config_file, ) + + args.config_file = custom_config_file + + # bypass singleton so we can test further + cc.Configuration.instance = None + + configuration = cc.Configuration(args, env=env, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration8(self): + env = { + 'PATH': '/usr/local/bin:/usr/bin:/bin', + 'TEST': 'test', + 'CDIST_PATH': '/opt/cdist/conf:/usr/local/share/cdist/conf', + 'REMOTE_COPY': 'scp', + 'REMOTE_EXEC': 'ssh', + 'CDIST_BETA': '1', + 'CDIST_LOCAL_SHELL': '/usr/bin/sh', + 'CDIST_REMOTE_SHELL': '/usr/bin/sh', + } + args = argparse.Namespace() + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'off', + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': '', + 'cache_path_pattern': '', + 'conf_dir': '', + 'init_manifest': '', + 'out_path': '', + 'remote_out_path': '', + 'remote_copy': '', + 'remote_exec': '', + 'jobs': '0', + 'parallel': '-1', + 'verbosity': 'INFO', + 'archiving': 'none', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'on', + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'conf_dir': '/opt/cdist', + 'remote_copy': 'myscp', + 'remote_exec': 'myexec', + 'parallel': '-1', + 'archiving': 'tar', + } + + local_config_file = os.path.join(fixtures, 'cdist-local.cfg') + with open(local_config_file, 'w') as f: + config.write(f) + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'conf_dir': '/opt/conf/cdist', + 'remote_copy': 'scpcustom', + 'remote_exec': 'sshcustom', + 'parallel': '15', + 'archiving': 'txz', + } + + custom_config_file = os.path.join(fixtures, 'cdist-custom.cfg') + with open(custom_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'beta': True, + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'cache_path_pattern': None, + 'conf_dir': [ + '/opt/conf/cdist', + ], + 'init_manifest': None, + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': 'scpcustom', + 'remote_exec': 'sshcustom', + 'jobs': 0, + 'parallel': 15, + 'verbosity': cap.VERBOSE_INFO, + 'archiving': 'txz', + }, + } + + config_files = (global_config_file, local_config_file, ) + + os.environ['CDIST_CONFIG_FILE'] = custom_config_file + + # bypass singleton so we can test further + cc.Configuration.instance = None + + configuration = cc.Configuration(args, env=env, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration_get_args(self): + env = { + 'PATH': '/usr/local/bin:/usr/bin:/bin', + 'TEST': 'test', + 'CDIST_PATH': '/opt/cdist/conf:/usr/local/share/cdist/conf', + 'REMOTE_COPY': 'scp', + 'REMOTE_EXEC': 'ssh', + 'CDIST_BETA': '1', + 'CDIST_LOCAL_SHELL': '/usr/bin/sh', + 'CDIST_REMOTE_SHELL': '/usr/bin/sh', + } + args = argparse.Namespace() + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'off', + 'local_shell': '/bin/sh', + 'remote_shell': '/bin/sh', + 'inventory_dir': '', + 'cache_path_pattern': '', + 'conf_dir': '', + 'init_manifest': '', + 'out_path': '', + 'remote_out_path': '', + 'remote_copy': '', + 'remote_exec': '', + 'jobs': '0', + 'parallel': '-1', + 'verbosity': 'INFO', + 'archiving': 'none', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'beta': 'on', + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'conf_dir': '/opt/cdist', + 'remote_copy': 'myscp', + 'remote_exec': 'myexec', + 'parallel': '-1', + 'archiving': 'tar', + } + + local_config_file = os.path.join(fixtures, 'cdist-local.cfg') + with open(local_config_file, 'w') as f: + config.write(f) + + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'conf_dir': '/opt/conf/cdist', + 'remote_copy': 'scpcustom', + 'remote_exec': 'sshcustom', + 'parallel': '15', + 'archiving': 'txz', + } + + custom_config_file = os.path.join(fixtures, 'cdist-custom.cfg') + with open(custom_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'beta': True, + 'local_shell': '/usr/bin/sh', + 'remote_shell': '/usr/bin/sh', + 'inventory_dir': '/var/db/cdist/inventory', + 'cache_path_pattern': None, + 'conf_dir': [ + '/opt/conf/cdist', + ], + 'init_manifest': None, + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': 'scpcustom', + 'remote_exec': 'sshcustom', + 'jobs': 0, + 'parallel': 15, + 'verbosity': cap.VERBOSE_INFO, + 'archiving': 'txz', + }, + } + + config_files = (global_config_file, local_config_file, ) + + os.environ['CDIST_CONFIG_FILE'] = custom_config_file + + # bypass singleton so we can test further + cc.Configuration.instance = None + + configuration = cc.Configuration(args, env=env, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + args = configuration.get_args() + dargs = vars(args) + expected_args = { + 'beta': True, + 'inventory_dir': '/var/db/cdist/inventory', + 'cache_path_pattern': None, + 'conf_dir': [ + '/opt/conf/cdist', + ], + 'manifest': None, + 'out_path': None, + 'remote_out_path': None, + 'remote_copy': 'scpcustom', + 'remote_exec': 'sshcustom', + 'jobs': 0, + 'parallel': 15, + 'verbose': cap.VERBOSE_INFO, + 'use_archiving': 'txz', + } + + self.assertEqual(dargs, expected_args) + + +if __name__ == "__main__": + import unittest + + unittest.main() diff --git a/cdist/test/configuration/fixtures/.nonempty b/cdist/test/configuration/fixtures/.nonempty new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index 6336947c..1b298143 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -28,8 +28,10 @@ import string import random import time import datetime +import argparse import cdist +import cdist.configuration as cc from cdist import test from cdist.exec import local @@ -165,6 +167,9 @@ class LocalTestCase(test.CdistTestCase): os.environ['CDIST_PATH'] = conf_dir + configuration = cc.Configuration(argparse.Namespace(), + env=os.environ) + link_test_local = local.Local( target_host=( 'localhost', @@ -174,6 +179,7 @@ class LocalTestCase(test.CdistTestCase): base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, + configuration=configuration ) link_test_local._create_conf_path_and_link_conf_dirs() diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 79485594..6ffa0f98 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -15,43 +15,45 @@ SYNOPSIS cdist banner [-h] [-q] [-v] - cdist config [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] - [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] - [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] - [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] - [-I INVENTORY_DIR] [-A] [-a] [-f HOSTFILE] [-p [HOST_MAX]] - [-s] [-t] + cdist config [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] + [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] + [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] + [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] + [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] [host [host ...]] - cdist install [-h] [-q] [-v] [-b] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] - [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] - [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] - [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] - [-I INVENTORY_DIR] [-A] [-a] [-f HOSTFILE] [-p [HOST_MAX]] - [-s] [-t] + cdist install [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] + [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] + [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] + [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] + [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] [host [host ...]] - cdist inventory [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] + cdist inventory [-h] [-q] [-v] [-b] [-g CONFIG_FILE] [-I INVENTORY_DIR] {add-host,add-tag,del-host,del-tag,list} ... - cdist inventory add-host [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] - [-f HOSTFILE] + cdist inventory add-host [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + [-I INVENTORY_DIR] [-f HOSTFILE] [host [host ...]] - cdist inventory add-tag [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] - [-f HOSTFILE] [-T TAGFILE] [-t TAGLIST] + cdist inventory add-tag [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + [-I INVENTORY_DIR] [-f HOSTFILE] [-T TAGFILE] + [-t TAGLIST] [host [host ...]] - cdist inventory del-host [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] [-a] - [-f HOSTFILE] + cdist inventory del-host [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + [-I INVENTORY_DIR] [-a] [-f HOSTFILE] [host [host ...]] - cdist inventory del-tag [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] [-a] - [-f HOSTFILE] [-T TAGFILE] [-t TAGLIST] + cdist inventory del-tag [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + [-I INVENTORY_DIR] [-a] [-f HOSTFILE] + [-T TAGFILE] [-t TAGLIST] [host [host ...]] - cdist inventory list [-h] [-q] [-v] [-b] [-I INVENTORY_DIR] [-a] - [-f HOSTFILE] [-H] [-t] + cdist inventory list [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + [-I INVENTORY_DIR] [-a] [-f HOSTFILE] [-H] [-t] [host [host ...]] cdist shell [-h] [-q] [-v] [-s SHELL] @@ -112,7 +114,7 @@ Install command is currently in beta. .. option:: -b, --beta Enable beta functionality. - + .. option:: -C CACHE_PATH_PATTERN, --cache-path-pattern CACHE_PATH_PATTERN Sepcify custom cache path pattern. If it is not set then @@ -133,15 +135,18 @@ Install command is currently in beta. read hosts from stdin. For the file format see :strong:`HOSTFILE FORMAT` below. +.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE + + Use specified custom configuration file. + .. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR Use specified custom inventory directory. Inventory - directory is set up by the following rules: if this - argument is set then specified directory is used, if - CDIST_INVENTORY_DIR env var is set then its value is - used, if HOME env var is set then ~/.cdit/inventory is - used, otherwise distribution inventory directory is - used. + directory is set up by the following rules: if cdist + configuration resolves this value then specified + directory is used, if HOME env var is set then + ~/.cdit/inventory is used, otherwise distribution + inventory directory is used. .. option:: -i MANIFEST, --initial-manifest MANIFEST @@ -254,16 +259,18 @@ Add host(s) to inventory database. host or host file is specified then, by default, read from stdin. Hostfile format is the same as config hostfile format. +.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE + + Use specified custom configuration file. .. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR Use specified custom inventory directory. Inventory - directory is set up by the following rules: if this - argument is set then specified directory is used, if - CDIST_INVENTORY_DIR env var is set then its value is - used, if HOME env var is set then ~/.cdist/inventory is - used, otherwise distribution inventory directory is - used. + directory is set up by the following rules: if cdist + configuration resolves this value then specified + directory is used, if HOME env var is set then + ~/.cdit/inventory is used, otherwise distribution + inventory directory is used. INVENTORY ADD-TAG @@ -287,15 +294,18 @@ Add tag(s) to inventory database. are specified then tags are read from stdin and are added to all hosts. Hostfile format is the same as config hostfile format. +.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE + + Use specified custom configuration file. + .. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR Use specified custom inventory directory. Inventory - directory is set up by the following rules: if this - argument is set then specified directory is used, if - CDIST_INVENTORY_DIR env var is set then its value is - used, if HOME env var is set then ~/.cdist/inventory is - used, otherwise distribution inventory directory is - used. + directory is set up by the following rules: if cdist + configuration resolves this value then specified + directory is used, if HOME env var is set then + ~/.cdit/inventory is used, otherwise distribution + inventory directory is used. .. option:: -T TAGFILE, --tag-file TAGFILE @@ -335,15 +345,18 @@ Delete host(s) from inventory database. host or host file is specified then, by default, read from stdin. Hostfile format is the same as config hostfile format. +.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE + + Use specified custom configuration file. + .. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR Use specified custom inventory directory. Inventory - directory is set up by the following rules: if this - argument is set then specified directory is used, if - CDIST_INVENTORY_DIR env var is set then its value is - used, if HOME env var is set then ~/.cdist/inventory is - used, otherwise distribution inventory directory is - used. + directory is set up by the following rules: if cdist + configuration resolves this value then specified + directory is used, if HOME env var is set then + ~/.cdit/inventory is used, otherwise distribution + inventory directory is used. INVENTORY DEL-TAG @@ -372,15 +385,18 @@ Delete tag(s) from inventory database. from stdin and are deleted from all hosts. Hostfile format is the same as config hostfile format. +.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE + + Use specified custom configuration file. + .. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR Use specified custom inventory directory. Inventory - directory is set up by the following rules: if this - argument is set then specified directory is used, if - CDIST_INVENTORY_DIR env var is set then its value is - used, if HOME env var is set then ~/.cdist/inventory is - used, otherwise distribution inventory directory is - used. + directory is set up by the following rules: if cdist + configuration resolves this value then specified + directory is used, if HOME env var is set then + ~/.cdit/inventory is used, otherwise distribution + inventory directory is used. .. option:: -T TAGFILE, --tag-file TAGFILE @@ -421,6 +437,10 @@ List inventory database. host or host file is specified then, by default, list all. Hostfile format is the same as config hostfile format. +.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE + + Use specified custom configuration file. + .. option:: -H, --host-only Suppress tags listing. @@ -428,12 +448,11 @@ List inventory database. .. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR Use specified custom inventory directory. Inventory - directory is set up by the following rules: if this - argument is set then specified directory is used, if - CDIST_INVENTORY_DIR env var is set then its value is - used, if HOME env var is set then ~/.cdist/inventory is - used, otherwise distribution inventory directory is - used. + directory is set up by the following rules: if cdist + configuration resolves this value then specified + directory is used, if HOME env var is set then + ~/.cdit/inventory is used, otherwise distribution + inventory directory is used. .. option:: -t, --tag @@ -454,6 +473,82 @@ usage. Its primary use is for debugging type parameters. be POSIX compatible shell. +CONFIGURATION FILE +------------------ +cdist obtains configuration data from the following sources in the following +order: + + #. command-line options + #. configuration file specified at command-line + #. configuration file specified in CDIST_CONFIG_FILE environment variable + #. environment variables + #. user's configuration file (first one found of ~/.cdist.cfg, + $XDG_CONFIG_HOME/cdist/cdist.cfg, in specified order) + #. system-wide configuration file (/etc/cdist.cfg) + +if one exists. + +cdist configuration file is in the INI file format. Currently it supports +only [GLOBAL] section. +The possible keywords and their meanings are as follows: + +:strong:`archiving` + Use specified archiving. Valid values include: + 'none', 'tar', 'tgz', 'tbz2' and 'txz'. + +:strong:`beta` + Enable beta functionality. It recognizes boolean values from + 'yes'/'no', 'on'/'off', 'true'/'false' and '1'/'0' + +:strong:`cache_path_pattern` + Specify cache path pattern. + +:strong:`conf_dir` + Comma separated list of configuration directories. + If also specified at command line then values from command line are + appended to this value. + +:strong:`init_manifest` + Specify default initial manifest. + +:strong:`inventory_dir` + Specify inventory directory. + +:strong:`jobs` + Specify number of jobs for parallel processing. If -1 then the default, + number of CPU's in the system is used. If 0 then parallel processing in + jobs is disabled. If set to positive number then specified maximum + number of processes will be used. + +:strong:`local_shell` + Shell command used for local execution. + +:strong:`out_path` + Directory to save cdist output in. + +:strong:`parallel` + Process hosts in parallel. If -1 then the default, number of CPU's in + the system is used. If 0 then parallel processing of hosts is disabled. + If set to positive number then specified maximum number of processes + will be used. + +:strong:`remote_copy` + Command to use for remote copy (should behave like scp). + +:strong:`remote_exec` + Command to use for remote execution (should behave like ssh). + +:strong:`remote_out_path` + Directory to save cdist output in on the target host. + +:strong:`remote_shell` + Shell command at remote host used for remote execution. + +:strong:`verbosity` + Set verbosity level. Valid values are: + 'ERROR', 'WARNING', 'INFO', 'VERBOSE', 'DEBUG', 'TRACE' and 'OFF'. + + FILES ----- ~/.cdist @@ -468,6 +563,10 @@ cdist/conf cdist/inventory The distribution inventory directory. This path is relative to cdist installation directory. +/etc/cdist.cfg + Global cdist configuration file, if exists. +~/.cdist/cdist.cfg + Local cdist configuration file, if exists. NOTES ----- @@ -592,6 +691,10 @@ CDIST_BETA CDIST_CACHE_PATH_PATTERN Custom cache path pattern. +CDIST_CONFIG_FILE + Custom configuration file. + + EXIT STATUS ----------- The following exit values shall be returned: diff --git a/scripts/cdist b/scripts/cdist index 384610b1..93fa392d 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -22,26 +22,20 @@ # import logging +import cdist +import cdist.argparse +import cdist.banner +import cdist.config +import cdist.install +import cdist.shell +import cdist.inventory def commandline(): """Parse command line""" - import cdist.argparse - import cdist.banner - import cdist.config - import cdist.install - import cdist.shell - import cdist.inventory - - parser = cdist.argparse.get_parsers() - args = parser['main'].parse_args(sys.argv[1:]) - - # Loglevels are handled globally in here - cdist.argparse.handle_loglevel(args) - - log.verbose("version %s" % cdist.VERSION) - log.trace(args) + parser, cfg = cdist.argparse.parse_and_configure(sys.argv[1:]) + args = cfg.get_args() # Work around python 3.3 bug: # http://bugs.python.org/issue16308 @@ -58,7 +52,6 @@ def commandline(): parser['main'].print_help() sys.exit(0) - cdist.argparse.check_beta(vars(args)) args.func(args) @@ -74,9 +67,8 @@ if __name__ == "__main__": exit_code = 0 try: - import os import re - import cdist + import os log = logging.getLogger("cdist") From 2f10353156f71432bbc76b79e318372194795588 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Aug 2017 23:11:10 +0200 Subject: [PATCH 0613/1332] Fix configuration bugs. --- cdist/exec/remote.py | 2 +- docs/src/man1/cdist.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 6e1dcefc..237c2a9f 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -241,7 +241,7 @@ class Remote(object): """ command = [ - self.configuration.get('CDIST_REMOTE_SHELL', "/bin/sh"), + self.configuration.get('remote_shell', "/bin/sh"), "-e" ] command.append(script) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 6ffa0f98..b6b2e04d 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -565,7 +565,7 @@ cdist/inventory This path is relative to cdist installation directory. /etc/cdist.cfg Global cdist configuration file, if exists. -~/.cdist/cdist.cfg +~/.cdist.cfg or $XDG_CONFIG_HOME/cdist/cdist.cfg Local cdist configuration file, if exists. NOTES From 704e918421cd2ba225c2de2925fba6b5bf691d99 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Aug 2017 23:12:38 +0200 Subject: [PATCH 0614/1332] changelog++ --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 7777a946..e069fc57 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Add configuration/config file support (Darko Poljak) + 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) * Explorer init: Use pgrep instead of ps for Linux (Philippe Gregoire) From 4af3c0c6d561834efad875fbf7e8efa1f95a5d58 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 Aug 2017 23:57:47 +0200 Subject: [PATCH 0615/1332] Fix empty conf_dir configuration value. --- cdist/exec/local.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 0e84c9d7..1f2c66a3 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -152,7 +152,9 @@ class Local(object): # cdist_path_dirs.reverse() # self.conf_dirs.extend(cdist_path_dirs) if 'conf_dir' in self.configuration: - self.conf_dirs.extend(self.configuration['conf_dir']) + conf_dirs = self.configuration['conf_dir'] + if conf_dirs: + self.conf_dirs.extend(conf_dirs) # Add command line supplied directories if self._add_conf_dirs: From feb221c5df277747cae340aa0e9fa3c0e99cef92 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 1 Sep 2017 10:40:01 +0200 Subject: [PATCH 0616/1332] Improve configuration docs. --- docs/src/cdist-configuration.rst | 91 ++++++++++++++++++++++++++++++++ docs/src/index.rst | 1 + docs/src/man1/cdist.rst | 15 +++--- 3 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 docs/src/cdist-configuration.rst diff --git a/docs/src/cdist-configuration.rst b/docs/src/cdist-configuration.rst new file mode 100644 index 00000000..6a0e4a4f --- /dev/null +++ b/docs/src/cdist-configuration.rst @@ -0,0 +1,91 @@ +Configuration +============= + +Description +----------- +cdist obtains configuration data from the following sources in the following +order: + + #. command-line options + #. configuration file specified at command-line using -g command line option + #. configuration file specified in CDIST_CONFIG_FILE environment variable + #. environment variables + #. user's configuration file (first one found of ~/.cdist.cfg, $XDG_CONFIG_HOME/cdist/cdist.cfg, in specified order) + #. system-wide configuration file (/etc/cdist.cfg) + +if one exists. + +Configuration source with lower ordering number from above has a higher +precedence. Configuration option value read from source with higher +precedence will overwrite option value, if exists, read from source with +lower precedence. That means that command-line option wins them all. + +Users can decide on the local conifguration file location. It can be either +~/.cdist.cfg or $XDG_CONFIG_HOME/cdist/cdist.cfg. Note that, if both exist, +then ~/.cdist.cfg is used. + +For a per-project configuration, particular environment variables or better, +CDIST_CONFIG_FILE environment variable or -g CONFIG_FILE command line option, +can be used. + +Config file format +------------------ +cdist configuration file is in the INI file format. Currently it supports +only [GLOBAL] section. +The possible keywords and their meanings are as follows: + +:strong:`archiving` + Use specified archiving. Valid values include: + 'none', 'tar', 'tgz', 'tbz2' and 'txz'. + +:strong:`beta` + Enable beta functionality. It recognizes boolean values from + 'yes'/'no', 'on'/'off', 'true'/'false' and '1'/'0' + +:strong:`cache_path_pattern` + Specify cache path pattern. + +:strong:`conf_dir` + Comma separated list of configuration directories. + If also specified at command line then values from command line are + appended to this value. + +:strong:`init_manifest` + Specify default initial manifest. + +:strong:`inventory_dir` + Specify inventory directory. + +:strong:`jobs` + Specify number of jobs for parallel processing. If -1 then the default, + number of CPU's in the system is used. If 0 then parallel processing in + jobs is disabled. If set to positive number then specified maximum + number of processes will be used. + +:strong:`local_shell` + Shell command used for local execution. + +:strong:`out_path` + Directory to save cdist output in. + +:strong:`parallel` + Process hosts in parallel. If -1 then the default, number of CPU's in + the system is used. If 0 then parallel processing of hosts is disabled. + If set to positive number then specified maximum number of processes + will be used. + +:strong:`remote_copy` + Command to use for remote copy (should behave like scp). + +:strong:`remote_exec` + Command to use for remote execution (should behave like ssh). + +:strong:`remote_out_path` + Directory to save cdist output in on the target host. + +:strong:`remote_shell` + Shell command at remote host used for remote execution. + +:strong:`verbosity` + Set verbosity level. Valid values are: + 'ERROR', 'WARNING', 'INFO', 'VERBOSE', 'DEBUG', 'TRACE' and 'OFF'. diff --git a/docs/src/index.rst b/docs/src/index.rst index 42c21199..652c6082 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -18,6 +18,7 @@ Contents: cdist-quickstart man1/cdist cdist-bootstrap + cdist-configuration cdist-manifest cdist-type cdist-types diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index b6b2e04d..0e258d8c 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -473,21 +473,20 @@ usage. Its primary use is for debugging type parameters. be POSIX compatible shell. -CONFIGURATION FILE ------------------- +CONFIGURATION +------------- cdist obtains configuration data from the following sources in the following -order: +order (from higher to lower precedence): #. command-line options #. configuration file specified at command-line #. configuration file specified in CDIST_CONFIG_FILE environment variable #. environment variables - #. user's configuration file (first one found of ~/.cdist.cfg, - $XDG_CONFIG_HOME/cdist/cdist.cfg, in specified order) - #. system-wide configuration file (/etc/cdist.cfg) - -if one exists. + #. user's configuration file (first one found of ~/.cdist.cfg, $XDG_CONFIG_HOME/cdist/cdist.cfg, in specified order) + #. system-wide configuration file (/etc/cdist.cfg). +CONFIGURATION FILE FORMAT +~~~~~~~~~~~~~~~~~~~~~~~~~ cdist configuration file is in the INI file format. Currently it supports only [GLOBAL] section. The possible keywords and their meanings are as follows: From 136f2ecd87cb2cd09777a93a4bd44b65aa61f567 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 1 Sep 2017 14:08:50 +0200 Subject: [PATCH 0617/1332] Add helpers for cdist config/install integration. (#551) Implement simple integration API. --- cdist/argparse.py | 6 +- cdist/config.py | 21 +++- cdist/configuration.py | 11 +- cdist/exec/remote.py | 3 + cdist/integration.py | 153 +++++++++++++++++++++++++++ cdist/test/configuration/__init__.py | 9 +- docs/src/cdist-integration.rst | 47 ++++++++ docs/src/index.rst | 1 + 8 files changed, 238 insertions(+), 13 deletions(-) create mode 100644 cdist/integration.py create mode 100644 docs/src/cdist-integration.rst diff --git a/cdist/argparse.py b/cdist/argparse.py index f0ea802a..28d3840e 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -73,8 +73,6 @@ def check_beta(args_dict): def check_positive_int(value): - import argparse - try: val = int(value) except ValueError: @@ -416,10 +414,10 @@ def handle_loglevel(args): logging.root.setLevel(_verbosity_level[args.verbose]) -def parse_and_configure(argv): +def parse_and_configure(argv, singleton=True): parser = get_parsers() parser_args = parser['main'].parse_args(argv) - cfg = cdist.configuration.Configuration(parser_args) + cfg = cdist.configuration.Configuration(parser_args, singleton=singleton) args = cfg.get_args() # Loglevels are handled globally in here handle_loglevel(args) diff --git a/cdist/config.py b/cdist/config.py index 779365f3..0435201c 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -45,7 +45,7 @@ class Config(object): """Cdist main class to hold arbitrary data""" def __init__(self, local, remote, dry_run=False, jobs=None, - cleanup_cmds=None): + cleanup_cmds=None, remove_remote_files_dirs=False): self.local = local self.remote = remote @@ -56,6 +56,7 @@ class Config(object): self.cleanup_cmds = cleanup_cmds else: self.cleanup_cmds = [] + self.remove_remote_files_dirs = remove_remote_files_dirs self.explorer = core.Explorer(self.local.target_host, self.local, self.remote, jobs=self.jobs) @@ -67,6 +68,15 @@ class Config(object): self.local.create_files_dirs() self.remote.create_files_dirs() + def _remove_remote_files_dirs(self): + """Remove remote files and directories for the run""" + self.remote.remove_files_dirs() + + def _remove_files_dirs(self): + """Remove files and directories for the run""" + if self.remove_remote_files_dirs: + self._remove_remote_files_dirs() + @staticmethod def hosts(source): try: @@ -283,7 +293,7 @@ class Config(object): @classmethod def onehost(cls, host, host_tags, host_base_path, host_dir_name, args, - parallel, configuration): + parallel, configuration, remove_remote_files_dirs=False): """Configure ONE system. If operating in parallel then return tuple (host, True|False, ) so that main process knows for which host function was successful. @@ -311,7 +321,8 @@ class Config(object): add_conf_dirs=args.conf_dir, cache_path_pattern=args.cache_path_pattern, quiet_mode=args.quiet, - configuration=configuration) + configuration=configuration, + exec_path=sys.argv[0]) remote = cdist.exec.remote.Remote( target_host=target_host, @@ -326,7 +337,8 @@ class Config(object): if cleanup_cmd: cleanup_cmds.append(cleanup_cmd) c = cls(local, remote, dry_run=args.dry_run, jobs=args.jobs, - cleanup_cmds=cleanup_cmds) + cleanup_cmds=cleanup_cmds, + remove_remote_files_dirs=remove_remote_files_dirs) c.run() except cdist.Error as e: @@ -367,6 +379,7 @@ class Config(object): self.manifest.run_initial_manifest(self.local.initial_manifest) self.iterate_until_finished() self.cleanup() + self._remove_files_dirs() self.local.save_cache(start_time) self.log.info("Finished successful run in {:.2f} seconds".format( diff --git a/cdist/configuration.py b/cdist/configuration.py index fa9671d0..b1154ae8 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -32,9 +32,12 @@ class Singleton(type): instance = None def __call__(cls, *args, **kwargs): - if not cls.instance: - cls.instance = super(Singleton, cls).__call__(*args, **kwargs) - return cls.instance + if 'singleton' in kwargs and kwargs['singleton'] == False: + return super(Singleton, cls).__call__(*args, **kwargs) + else: + if not cls.instance: + cls.instance = super(Singleton, cls).__call__(*args, **kwargs) + return cls.instance _VERBOSITY_VALUES = ( @@ -294,7 +297,7 @@ class Configuration(metaclass=Singleton): return None def __init__(self, command_line_args, env=os.environ, - config_files=default_config_files): + config_files=default_config_files, singleton=True): self.command_line_args = command_line_args self.args = self._convert_args(command_line_args) self.env = env diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 237c2a9f..b834cd97 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -116,6 +116,9 @@ class Remote(object): self.run(["chmod", "0700", self.base_path]) self.mkdir(self.conf_path) + def remove_files_dirs(self): + self.rmdir(self.base_path) + def rmfile(self, path): """Remove file on the remote side.""" self.log.trace("Remote rm: %s", path) diff --git a/cdist/integration.py b/cdist/integration.py new file mode 100644 index 00000000..e2f9be6e --- /dev/null +++ b/cdist/integration.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 2017 Darko Poljak (darko.poljak 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 . +# +# + +import cdist +# needed for cdist.argparse +import cdist.banner +import cdist.config +import cdist.install +import cdist.shell +import cdist.inventory +import cdist.argparse +import cdist.log +import cdist.config +import cdist.install +import sys +import os +import os.path +import collections +import uuid + + +def find_cdist_exec_in_path(): + """Search cdist executable in os.get_exec_path() entries. + """ + for path in os.get_exec_path(): + cdist_path = os.path.join(path, 'cdist') + if os.access(cdist_path, os.X_OK): + return cdist_path + return None + + +_mydir = os.path.dirname(__file__) + + +def find_cdist_exec(): + """Search cdist executable starting from local lib directory. + + Detect if ../scripts/cdist (from local lib direcotry) exists and + if it is executable. If not then try to find cdist exec path in + os.get_exec_path() entries. If no cdist path is found rasie + cdist.Error. + """ + cdist_path = os.path.abspath(os.path.join(_mydir, '..', 'scripts', + 'cdist')) + if os.access(cdist_path, os.X_OK): + return cdist_path + cdist_path = find_cdist_exec_in_path() + if not cdist_path: + raise cdist.Error('Cannot find cdist executable from local lib ' + 'directory: {}, nor in PATH: {}.'.format( + _mydir, os.environ.get('PATH'))) + return cdist_path + + +ACTION_CONFIG = 'config' +ACTION_INSTALL = 'install' + + +def _process_hosts_simple(action, host, manifest, verbose, + cdist_path=None): + """Perform cdist action ('config' or 'install') on hosts with specified + manifest using default other cdist options. host parameter can be a + string or iterbale of hosts. verbose is a desired verbosity level + which defaults to VERBOSE_INFO. cdist_path is path to cdist executable, + if it is None then integration lib tries to find it. + """ + if isinstance(host, str): + hosts = [host, ] + elif isinstance(host, collections.Iterable): + hosts = host + else: + raise cdist.Error('Invalid host argument: {}'.format(host)) + + # Setup sys.argv[0] since cdist relies on command line invocation. + if not cdist_path: + cdist_path = find_cdist_exec() + sys.argv[0] = cdist_path + + cname = action.title() + module = getattr(cdist, action) + theclass = getattr(module, cname) + + # Build argv for cdist and use argparse for argument parsing. + remote_out_dir_base = os.path.join('/', 'var', 'lib', 'cdist') + uid = str(uuid.uuid1()) + out_dir = remote_out_dir_base + uid + cache_path_pattern = '%h-' + uid + argv = [action, '-i', manifest, '-r', out_dir, '-C', cache_path_pattern, ] + for i in range(verbose): + argv.append('-v') + for x in hosts: + argv.append(x) + + parser, cfg = cdist.argparse.parse_and_configure(argv, singleton=False) + args = cfg.get_args() + configuration = cfg.get_config(section='GLOBAL') + + theclass.construct_remote_exec_copy_patterns(args) + base_root_path = theclass.create_base_root_path(None) + + for target_host in args.host: + host_base_path, hostdir = theclass.create_host_base_dirs( + target_host, base_root_path) + theclass.onehost(target_host, None, host_base_path, hostdir, args, + parallel=False, configuration=configuration, + remove_remote_files_dirs=True) + + +def configure_hosts_simple(host, manifest, + verbose=cdist.argparse.VERBOSE_INFO, + cdist_path=None): + """Configure hosts with specified manifest using default other cdist + options. host parameter can be a string or iterbale of hosts. verbose + is a desired verbosity level which defaults to VERBOSE_INFO. + cdist_path is path to cdist executable, if it is None then integration + lib tries to find it. + """ + _process_hosts_simple(action=ACTION_CONFIG, host=host, + manifest=manifest, verbose=verbose, + cdist_path=cdist_path) + + +def install_hosts_simple(host, manifest, + verbose=cdist.argparse.VERBOSE_INFO, + cdist_path=None): + """Install hosts with specified manifest using default other cdist + options. host parameter can be a string or iterbale of hosts. verbose + is a desired verbosity level which defaults to VERBOSE_INFO. + cdist_path is path to cdist executable, if it is None then integration + lib tries to find it. + """ + _process_hosts_simple(action=ACTION_INSTALL, host=host, + manifest=manifest, verbose=verbose, + cdist_path=cdist_path) diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index 2ffd8255..a91e8e8b 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -236,9 +236,16 @@ class ConfigurationTestCase(test.CdistTestCase): x = cc.Configuration(None) args = argparse.Namespace() args.a = 'a' - y = cc.Configuration() + y = cc.Configuration(args) self.assertIs(x, y) + def test_non_singleton(self): + x = cc.Configuration(None, singleton=False) + args = argparse.Namespace() + args.a = 'a' + y = cc.Configuration(args, singleton=False) + self.assertIsNot(x, y) + def test_read_config_file(self): config = cc.Configuration(None, env={}, config_files=()) d = config._read_config_file(self.config_file) diff --git a/docs/src/cdist-integration.rst b/docs/src/cdist-integration.rst new file mode 100644 index 00000000..13880cd3 --- /dev/null +++ b/docs/src/cdist-integration.rst @@ -0,0 +1,47 @@ +cdist integration / using cdist as library +========================================== + +Description +----------- + +cdist can be integrate with other applications by importing cdist and other +cdist modules and setting all by hand. There are also helper functions which +aim to ease this integration. Just import **cdist.integration** and use its +functions: + +* :strong:`cdist.integration.configure_hosts_simple` for configuration +* :strong:`cdist.integration.install_hosts_simple` for installation. + +Functions require `host` and `manifest` parameters. +`host` can be specified as a string representing host or as iterable +of hosts. `manifest` is a path to initial manifest. For other cdist +options default values will be used. `verbose` is a desired verbosity +level which defaults to VERBOSE_INFO. `cdist_path` parameter specifies +path to cdist executable, if it is `None` then functions will try to +find it first from local lib directory and then in PATH. + +In case of cdist error :strong:`cdist.Error` exception is raised. + +:strong:`WARNING`: cdist integration helper functions are not yet stable! + +Examples +-------- + +.. code-block:: sh + + # configure host from python interactive shell + >>> import cdist.integration + >>> cdist.integration.configure_hosts_simple('185.203.114.185', + ... '~/.cdist/manifest/init') + + # configure host from python interactive shell, specifying verbosity level + >>> import cdist.integration + >>> cdist.integration.configure_hosts_simple( + ... '185.203.114.185', '~/.cdist/manifest/init', + ... verbose=cdist.argparse.VERBOSE_TRACE) + + # configure specified dns hosts from python interactive shell + >>> import cdist.integration + >>> hosts = ('dns1.ungleich.ch', 'dns2.ungleich.ch', 'dns3.ungleich.ch', ) + >>> cdist.integration.configure_hosts_simple(hosts, + ... '~/.cdist/manifest/init') diff --git a/docs/src/index.rst b/docs/src/index.rst index 652c6082..d662fd73 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -26,6 +26,7 @@ Contents: cdist-messaging cdist-parallelization cdist-inventory + cdist-integration cdist-reference cdist-best-practice cdist-stages From 759a917da957e58f8613b3470dd307b8ea2148a5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 1 Sep 2017 14:10:15 +0200 Subject: [PATCH 0618/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e069fc57..21e6769f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Core: Add configuration/config file support (Darko Poljak) + * Core: Implement simple integration API (unstable) (Darko Poljak) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From 5213f343c07c0d0c47c332ab0427c223c8a8edac Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 1 Sep 2017 14:11:58 +0200 Subject: [PATCH 0619/1332] pep8 --- cdist/configuration.py | 2 +- cdist/test/configuration/__init__.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cdist/configuration.py b/cdist/configuration.py index b1154ae8..fe7fdf1b 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -32,7 +32,7 @@ class Singleton(type): instance = None def __call__(cls, *args, **kwargs): - if 'singleton' in kwargs and kwargs['singleton'] == False: + if 'singleton' in kwargs and not kwargs['singleton']: return super(Singleton, cls).__call__(*args, **kwargs) else: if not cls.instance: diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index a91e8e8b..2f83d63d 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -63,9 +63,10 @@ class ConfigurationOptionsTestCase(test.CdistTestCase): ), ) for currval, newval, update_appends, expected in test_cases: - self.assertEqual(option.update_value(currval, newval, - update_appends=update_appends), - expected) + self.assertEqual( + option.update_value(currval, newval, + update_appends=update_appends), + expected) def test_StringOption(self): option = cc.StringOption('test') From ed55d01b350947b4e15c0a2c146bd0d5a293330e Mon Sep 17 00:00:00 2001 From: Sven Wick Date: Fri, 1 Sep 2017 20:56:48 +0200 Subject: [PATCH 0620/1332] Update machine_type (#564) detect kvm on proxmox --- cdist/conf/explorer/machine_type | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cdist/conf/explorer/machine_type b/cdist/conf/explorer/machine_type index eb3c9d36..3b4f0308 100755 --- a/cdist/conf/explorer/machine_type +++ b/cdist/conf/explorer/machine_type @@ -56,6 +56,20 @@ if [ -r /proc/cpuinfo ]; then exit fi fi + + if [ -r /sys/class/dmi/id/sys_vendor ]; then + if grep -q -i 'qemu' /sys/class/dmi/id/sys_vendor; then + echo "virtual_by_kvm" + exit + fi + fi + + if [ -r /sys/class/dmi/id/chassis_vendor ]; then + if grep -q -i 'qemu' /sys/class/dmi/id/chassis_vendor; then + echo "virtual_by_kvm" + exit + fi + fi fi echo "virtual_by_unknown" else From 4f3e4173592df68ec535fa10fac52c1bc6c28901 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 1 Sep 2017 20:58:14 +0200 Subject: [PATCH 0621/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 21e6769f..7956f963 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Core: Add configuration/config file support (Darko Poljak) * Core: Implement simple integration API (unstable) (Darko Poljak) + * Explorer machine_type: Detect kvm on proxmox (Sven Wick) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From 99133219bc86b5dd3d913b8dbbeca6c4e63a8652 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 2 Sep 2017 08:40:23 +0200 Subject: [PATCH 0622/1332] Add another test case. --- cdist/test/configuration/__init__.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index 2f83d63d..acd6c0bb 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -1077,6 +1077,34 @@ class ConfigurationTestCase(test.CdistTestCase): self.assertEqual(dargs, expected_args) + def test_configuration_empty_value_in_file(self): + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'inventory_dir': '', + 'conf_dir': '', + } + + config_file = os.path.join(fixtures, 'cdist-local.cfg') + with open(config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'inventory_dir': None, + 'conf_dir': None, + }, + } + + config_files = (config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + args = argparse.Namespace() + configuration = cc.Configuration(args, env={}, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + if __name__ == "__main__": import unittest From 0043b3f4b086ea252d7017b0dee0e1870b54d658 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 2 Sep 2017 08:40:43 +0200 Subject: [PATCH 0623/1332] Add cdist config file skeleton. --- configuration/cdist.cfg.skeleton | 71 ++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 configuration/cdist.cfg.skeleton diff --git a/configuration/cdist.cfg.skeleton b/configuration/cdist.cfg.skeleton new file mode 100644 index 00000000..441f6154 --- /dev/null +++ b/configuration/cdist.cfg.skeleton @@ -0,0 +1,71 @@ +[GLOBAL] +# archiving +# Use specified archiving. Valid values include: +# none, tar, tgz, tbz2 and txz. +# archiving = tar +# +# beta +# Enable beta functionality. It recognizes boolean values from +# yes/no, on/off, true/false and 1/0 +# beta = no +# +# cache_path_pattern +# Specify cache path pattern. +# cache_path_pattern = %h +# +# conf_dir +# Comma separated list of configuration directories. +# If also specified at command line then values from command line are +# appended to this value. +# conf_dir = : +# +# init_manifest +# Specify default initial manifest. +# init_mainfest = +# +# inventory_dir +# Specify inventory directory. +# inventory_dir = +# +# jobs +# Specify number of jobs for parallel processing. If -1 then the default, +# number of CPU's in the system is used. If 0 then parallel processing in +# jobs is disabled. If set to positive number then specified maximum +# number of processes will be used. +# jobs = 0 +# +# local_shell +# Shell command used for local execution. +# local_shell = /bin/sh +# +# out_path +# Directory to save cdist output in. +# out_path = +# +# parallel +# Process hosts in parallel. If -1 then the default, number of CPU's in +# the system is used. If 0 then parallel processing of hosts is disabled. +# If set to positive number then specified maximum number of processes +# will be used. +# parallel = 0 +# +# remote_copy +# Command to use for remote copy (should behave like scp). +# remote_copy = +# +# remote_exec +# Command to use for remote execution (should behave like ssh). +# remote_exec = +# +# remote_out_path +# Directory to save cdist output in on the target host. +# remote_out_path = /var/lib/cdist +# +# remote_shell +# Shell command at remote host used for remote execution. +# remote_shell = /bin/sh +# +# verbosity +# Set verbosity level. Valid values are: +# ERROR, WARNING, INFO, VERBOSE, DEBUG, TRACE and OFF. +# verbosity = INFO From 7564038f045722367809e393d1d59169790fb083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Sat, 2 Sep 2017 21:22:33 +0200 Subject: [PATCH 0624/1332] fixes to __prometheus_{server,alertmanager} (#565) --- cdist/conf/type/__prometheus_alertmanager/manifest | 11 ++++++----- cdist/conf/type/__prometheus_server/manifest | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index 555ab1a1..0dbce3c2 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -21,13 +21,14 @@ REAL_FLAGS="$(echo "$FLAGS" | sed -nE 's/^([^#]+).*/ --\1 \\/p')" __go_get github.com/prometheus/alertmanager/cmd/... __user prometheus --system -require="__user/prometheus" __directory "$storage_path" --owner prometheus -require="__user/prometheus" __directory "$CONF_DIR" --owner prometheus +require="__user/prometheus" __directory "$storage_path" --owner prometheus --parents +require="__user/prometheus" __directory "$CONF_DIR" --owner prometheus --parents __daemontools_service alertmanager --run "setuidgid prometheus $GOBIN/alertmanager $REAL_FLAGS" require="$require __directory/$storage_path __user/prometheus" \ __config_file $CONF \ - --source $config \ - --group prometheus --mode 640 \ - --onchange "$ONCHANGE" + --source $config \ + --group prometheus --mode 640 \ + --onchange "svc -h /service/alertmanager" # TODO when a config-check tool is available, check config here + diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index dee81bc2..96717ed6 100755 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -30,8 +30,8 @@ REAL_FLAGS="$(echo "$FLAGS" | sed -nE 's/^([^#]+).*/ --\1 \\/p')" __go_get github.com/prometheus/prometheus/cmd/... __user prometheus --system -require="__user/prometheus" __directory "$storage_path" --owner prometheus -require="__user/prometheus" __directory "$CONF_DIR" --owner prometheus +require="__user/prometheus" __directory "$storage_path" --owner prometheus --parents +require="__user/prometheus" __directory "$CONF_DIR" --owner prometheus --parents __daemontools_service prometheus --run "setuidgid prometheus $GOBIN/prometheus $REAL_FLAGS" From a9f338b6a597652aaea2e9a95845017293bc04e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Sat, 2 Sep 2017 21:23:48 +0200 Subject: [PATCH 0625/1332] new type: __prometheus_exporter (#566) --- .../__prometheus_exporter/files/blackbox.yml | 63 +++++++++++++++++++ cdist/conf/type/__prometheus_exporter/man.rst | 63 +++++++++++++++++++ .../conf/type/__prometheus_exporter/manifest | 50 +++++++++++++++ .../__prometheus_exporter/parameter/boolean | 1 + .../parameter/default/exporter | 0 .../__prometheus_exporter/parameter/optional | 1 + 6 files changed, 178 insertions(+) create mode 100644 cdist/conf/type/__prometheus_exporter/files/blackbox.yml create mode 100644 cdist/conf/type/__prometheus_exporter/man.rst create mode 100644 cdist/conf/type/__prometheus_exporter/manifest create mode 100644 cdist/conf/type/__prometheus_exporter/parameter/boolean create mode 100644 cdist/conf/type/__prometheus_exporter/parameter/default/exporter create mode 100644 cdist/conf/type/__prometheus_exporter/parameter/optional diff --git a/cdist/conf/type/__prometheus_exporter/files/blackbox.yml b/cdist/conf/type/__prometheus_exporter/files/blackbox.yml new file mode 100644 index 00000000..e567c127 --- /dev/null +++ b/cdist/conf/type/__prometheus_exporter/files/blackbox.yml @@ -0,0 +1,63 @@ +modules: + http_2xx: + prober: http + timeout: 3s + http: + method: GET + no_follow_redirects: false + fail_if_ssl: false + fail_if_not_ssl: false + # http_post_2xx: + # prober: http + # timeout: 5s + # http: + # method: POST + # headers: + # Content-Type: application/json + # body: '{}' + # tcp_connect_v4_example: + # prober: tcp + # timeout: 5s + # tcp: + # protocol: "tcp4" + # irc_banner_example: + # prober: tcp + # timeout: 5s + # tcp: + # query_response: + # - send: "NICK prober" + # - send: "USER prober prober prober :prober" + # - expect: "PING :([^ ]+)" + # send: "PONG ${1}" + # - expect: "^:[^ ]+ 001" + # icmp_example: + # prober: icmp + # timeout: 5s + # icmp: + # protocol: "icmp" + # preferred_ip_protocol: "ip4" + # dns_udp_example: + # prober: dns + # timeout: 5s + # dns: + # query_name: "www.prometheus.io" + # query_type: "A" + # valid_rcodes: + # - NOERROR + # validate_answer_rrs: + # fail_if_matches_regexp: + # - ".*127.0.0.1" + # fail_if_not_matches_regexp: + # - "www.prometheus.io.\t300\tIN\tA\t127.0.0.1" + # validate_authority_rrs: + # fail_if_matches_regexp: + # - ".*127.0.0.1" + # validate_additional_rrs: + # fail_if_matches_regexp: + # - ".*127.0.0.1" + # dns_tcp_example: + # prober: dns + # dns: + # protocol: "tcp" # accepts "tcp/tcp4/tcp6/udp/udp4/udp6", defaults to "udp" + # preferred_ip_protocol: "ip4" # used for "udp/tcp", defaults to "ip6" + # query_name: "www.prometheus.io" diff --git a/cdist/conf/type/__prometheus_exporter/man.rst b/cdist/conf/type/__prometheus_exporter/man.rst new file mode 100644 index 00000000..9fbdcd2b --- /dev/null +++ b/cdist/conf/type/__prometheus_exporter/man.rst @@ -0,0 +1,63 @@ +cdist-type__prometheus_exporter(7) +================================== + +NAME +---- +cdist-type__prometheus_exporter - install some Prometheus exporters + + +DESCRIPTION +----------- +Install and configure some exporters to be used by the Prometheus monitoring system (https://prometheus.io/). + +This type creates a daemontools-compatible service directory under /service/$__object_id. +Daemontools (or something compatible) must be installed (in particular, the command `svc` must be executable). + +This type installs and builds the latest version from git, using go get. A recent version of golang as well +as build tools (make, g++, etc.) must be available. + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +exporter + Which exporter to install and configure. Default: $__object_id. + Currently supported: node, blackbox, ceph + + +BOOLEAN PARAMETERS +------------------ +add-consul-service + Add this exporter as a Consul service for automatic service discovery. + + +EXAMPLES +-------- + +.. code-block:: sh + + __daemontools + __golang_from_vendor --version 1.9 # required for prometheus and many exporters + + require="__daemontools __golang_from_vendor" __prometheus_exporter node + + +SEE ALSO +-------- +:strong:`cdist-type__prometheus_server`\ (7), :strong:`cdist-type__daemontools`\ (7), +:strong:`cdist-type__golang_from_vendor`\ (7), +Prometheus documentation: https://prometheus.io/docs/introduction/overview/ + +AUTHORS +------- +Kamila Součková + +COPYING +------- +Copyright \(C) 2017 Kamila Součková. 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/__prometheus_exporter/manifest b/cdist/conf/type/__prometheus_exporter/manifest new file mode 100644 index 00000000..3d8f460c --- /dev/null +++ b/cdist/conf/type/__prometheus_exporter/manifest @@ -0,0 +1,50 @@ +#!/bin/sh + +export GOBIN=/opt/gocode/bin # where to find go binaries + +exporter="$(cat $__object/parameter/exporter)" +[ -z "$exporter" ] && exporter="$__object_id" + +__user prometheus --system + +case $exporter in + node) + TEXTFILES=/service/node-exporter/textfiles # path for the textfiles collector + + port=9100 + run="setuidgid prometheus $GOBIN/node_exporter -web.listen-address :$port -collector.textfile.directory=$TEXTFILES" + + require="__golang_from_vendor" __go_get github.com/prometheus/node_exporter + __directory $TEXTFILES --parents --mode 777 + ;; + blackbox) + port=9115 + run="setuidgid prometheus $GOBIN/blackbox_exporter -config.file=/service/blackbox-exporter/blackbox.yml" + + require="__daemontools_service/blackbox-exporter __user/prometheus" __config_file "/service/blackbox-exporter/blackbox.yml" \ + --source $__type/files/blackbox.yml \ + --group prometheus --mode 640 \ + --onchange "svc -h /service/blackbox-exporter" + require="__golang_from_vendor" __go_get github.com/prometheus/blackbox_exporter + ;; + ceph) + port=9128 + run="setuidgid ceph $GOBIN/ceph_exporter -ceph.config /etc/ceph/ceph.conf -telemetry.addr :$port" + + __package librados-dev # dependency of ceph_exporter + require="__golang_from_vendor __package/librados-dev" __go_get github.com/digitalocean/ceph_exporter + ;; + *) + echo "Unknown exporter: $exporter." >&2 + exit 1 + ;; +esac + +require="__daemontools" __daemontools_service ${exporter}-exporter --run "$run" +if [ -f "$__object/parameter/add-consul-service" ]; then + __consul_service ${exporter}-exporter --port $port --check-http "http://localhost:$port/metrics" --check-interval 10s +fi + +#__daemontools --install-init-script +__daemontools +__golang_from_vendor --version 1.8.1 # required for many exporters diff --git a/cdist/conf/type/__prometheus_exporter/parameter/boolean b/cdist/conf/type/__prometheus_exporter/parameter/boolean new file mode 100644 index 00000000..004af844 --- /dev/null +++ b/cdist/conf/type/__prometheus_exporter/parameter/boolean @@ -0,0 +1 @@ +add-consul-service diff --git a/cdist/conf/type/__prometheus_exporter/parameter/default/exporter b/cdist/conf/type/__prometheus_exporter/parameter/default/exporter new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__prometheus_exporter/parameter/optional b/cdist/conf/type/__prometheus_exporter/parameter/optional new file mode 100644 index 00000000..9cfaec5a --- /dev/null +++ b/cdist/conf/type/__prometheus_exporter/parameter/optional @@ -0,0 +1 @@ +exporter From b8a1ad0ebd10c9695e8c73aa897aa6995cb61f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Sat, 2 Sep 2017 21:25:17 +0200 Subject: [PATCH 0626/1332] Improve __daemontools on FreeBSD (#567) Improve __daemontools on freebsd --- cdist/conf/type/__daemontools/man.rst | 5 ++++ cdist/conf/type/__daemontools/manifest | 25 ++++++++++++++++--- .../parameter/default/servicedir | 1 + .../type/__daemontools/parameter/optional | 1 + 4 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 cdist/conf/type/__daemontools/parameter/default/servicedir diff --git a/cdist/conf/type/__daemontools/man.rst b/cdist/conf/type/__daemontools/man.rst index a8e81e54..bc1b4d33 100644 --- a/cdist/conf/type/__daemontools/man.rst +++ b/cdist/conf/type/__daemontools/man.rst @@ -21,11 +21,16 @@ OPTIONAL PARAMETERS from-package Package to install. Must be compatible with the original daemontools. Example: daemontools-encore. Default: daemontools. +servicedir + Directory to scan for services. Default: `/service` + + BOOLEAN PARAMETERS ------------------ install-init-script Add an init script and set it to start on boot. + EXAMPLES -------- diff --git a/cdist/conf/type/__daemontools/manifest b/cdist/conf/type/__daemontools/manifest index 0763d7be..75f26ca0 100755 --- a/cdist/conf/type/__daemontools/manifest +++ b/cdist/conf/type/__daemontools/manifest @@ -1,17 +1,34 @@ #!/bin/sh -e pkg=$(cat "$__object/parameter/from-package") +servicedir=$(cat "$__object/parameter/servicedir") __package $pkg +__directory $servicedir --mode 755 if [ -f "$__object/parameter/install-init-script" ]; then + os=$(cat "$__global/explorer/os") init=$(cat "$__global/explorer/init") + case $init in init) - __config_file /etc/init.d/svscan --mode 755 --source "$__type/files/init.d-svscan" - require="$require __config_file/etc/init.d/svscan" __start_on_boot svscan - require="$require __start_on_boot/svscan" __process svscan --start 'service svscan start' - ;; + case $os in + freebsd) + __config_file /etc/rc.conf.d/svscan --source - <<-EOT + svscan_enable="YES" + svscan_servicedir="$servicedir" + EOT + require="$require __package/$pkg __directory/$servicedir __config_file/etc/rc.conf.d/svscan" \ + __process svscan --start 'service svscan start' + ;; + *) + __config_file /etc/init.d/svscan --mode 755 --source "$__type/files/init.d-svscan" + require="$require __config_file/etc/init.d/svscan" __start_on_boot svscan + require="$require __package/$pkg __directory/$servicedir __start_on_boot/svscan" \ + __process svscan --start 'service svscan start' + ;; + esac + ;; *) echo "Your init system ($init) is not supported by this type. Submit a patch at github.com/ungleich/cdist!" exit 1 diff --git a/cdist/conf/type/__daemontools/parameter/default/servicedir b/cdist/conf/type/__daemontools/parameter/default/servicedir new file mode 100644 index 00000000..b74e27f6 --- /dev/null +++ b/cdist/conf/type/__daemontools/parameter/default/servicedir @@ -0,0 +1 @@ +/service diff --git a/cdist/conf/type/__daemontools/parameter/optional b/cdist/conf/type/__daemontools/parameter/optional index 8eca305b..22c0805d 100644 --- a/cdist/conf/type/__daemontools/parameter/optional +++ b/cdist/conf/type/__daemontools/parameter/optional @@ -1 +1,2 @@ from-package +servicedir From 12a5aa39d4382a9a3710ad321a7b5ab66264a452 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 2 Sep 2017 21:34:50 +0200 Subject: [PATCH 0627/1332] changelog++ --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 7956f963..18a1a2f9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ next: * Core: Add configuration/config file support (Darko Poljak) * Core: Implement simple integration API (unstable) (Darko Poljak) * Explorer machine_type: Detect kvm on proxmox (Sven Wick) + * Types __prometheus_server, __prometheus_alertmanager: Bugfixes (Kamila Součková) + * New type: __prometheus_exporter (Kamila Součková) + * Type __daemontools: Improve it on FreeBSD (Kamila Součková) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From fb3cd98b543124bc53d8ee73502c2da078957f9a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 2 Sep 2017 21:38:13 +0200 Subject: [PATCH 0628/1332] Minor fixes to man page. --- cdist/conf/type/__prometheus_exporter/man.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__prometheus_exporter/man.rst b/cdist/conf/type/__prometheus_exporter/man.rst index 9fbdcd2b..f91fe668 100644 --- a/cdist/conf/type/__prometheus_exporter/man.rst +++ b/cdist/conf/type/__prometheus_exporter/man.rst @@ -25,7 +25,7 @@ OPTIONAL PARAMETERS ------------------- exporter Which exporter to install and configure. Default: $__object_id. - Currently supported: node, blackbox, ceph + Currently supported: node, blackbox, ceph. BOOLEAN PARAMETERS @@ -47,8 +47,8 @@ EXAMPLES SEE ALSO -------- -:strong:`cdist-type__prometheus_server`\ (7), :strong:`cdist-type__daemontools`\ (7), -:strong:`cdist-type__golang_from_vendor`\ (7), +:strong:`cdist-type__daemontools`\ (7), :strong:`cdist-type__golang_from_vendor`\ (7), +:strong:`cdist-type__prometheus_server`\ (7), Prometheus documentation: https://prometheus.io/docs/introduction/overview/ AUTHORS From 0dd5411216318933d6fb03ec3ef548d0e2f5275d Mon Sep 17 00:00:00 2001 From: uqam-fob Date: Sun, 3 Sep 2017 17:27:27 -0400 Subject: [PATCH 0629/1332] __package_pkg_openbsd: fix use of --name (#568) Fixes the improper use of the file holding the value of the 'name' option. --- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 5f479147..4a6763cd 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -41,7 +41,7 @@ fi pkgopts="-x" if [ -f "$__object/parameter/name" ]; then - name="$__object/parameter/name" + name=$(cat "$__object/parameter/name") else name="$__object_id" fi From 4f078b52b192df302056639a68265923d808073f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 3 Sep 2017 23:28:49 +0200 Subject: [PATCH 0630/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 18a1a2f9..582f1a31 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Types __prometheus_server, __prometheus_alertmanager: Bugfixes (Kamila Součková) * New type: __prometheus_exporter (Kamila Součková) * Type __daemontools: Improve it on FreeBSD (Kamila Součková) + * Type __package_pkg_openbsd: Fix use of --name (Philippe Gregoire) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From b2fb38d1f400d7b95565699783914b6f3a5bdfba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Gr=C3=A9goire?= Date: Mon, 4 Sep 2017 13:07:49 -0400 Subject: [PATCH 0631/1332] __package_pkg_openbsd: fix pkg_version explorer The pkg_version explorer will fail to properly detect if a package is installed when a package's name is present in the description of a package (as returned by pkg_info). Currently, trying to install libtool fails due to incorrect parsing: $ pkg_info | grep libtool libltdl-2.4.2p1 GNU libtool system independent dlopen wrapper Additionally, trying to install nagios results in the following output: $ pkg_info | grep nagios nagios-4.0.8p3-chroot host and service monitor nagios-web-4.0.8p2-chroot cgis and webpages for nagios This commit fixes detection by properly parsing pkg_info's output. Specifically, descriptions are ignored and package names are properly extracted. --- cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version index bc23a85d..212f0d96 100755 --- a/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version +++ b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version @@ -1,6 +1,7 @@ #!/bin/sh # # 2011 Andi Brönnimann (andi-cdist at v-net.ch) +# Copyright 2017, Philippe Gregoire # # This file is part of cdist. # @@ -28,4 +29,4 @@ else fi #TODO: Is there a better way? -pkg_info | grep "$name" | sed 's .*\(-[0-9.][0-9.]*\).* \1 ' | sed 's/-//' +pkg_info | grep "^$name-[0-9]" | sed 's|.*\(-[0-9][0-9.]*\).*|\1|' | sed 's/-//' From b0cbd8f5bd05b8800214114f8f1bd59f0c08ca80 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 4 Sep 2017 20:27:40 +0200 Subject: [PATCH 0632/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 582f1a31..3167cec6 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * New type: __prometheus_exporter (Kamila Součková) * Type __daemontools: Improve it on FreeBSD (Kamila Součková) * Type __package_pkg_openbsd: Fix use of --name (Philippe Gregoire) + * Type __package_pkg_openbsd: Fix pkg_version explorer (Philippe Gregoire) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From 97332833bc2652c71b71d91f4666343401a1458e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 6 Sep 2017 21:47:53 +0200 Subject: [PATCH 0633/1332] Document __cdist_loglevel values. --- docs/src/cdist-reference.rst.sh | 5 +++++ docs/src/cdist-type.rst | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index 89820358..cb717c4a 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -198,6 +198,11 @@ Environment variables (for reading) ----------------------------------- The following environment variables are exported by cdist: +__cdist_loglevel + Value of cdist log level. One of 60, 40, 30, 20, 15, 10 and 5 where + the meaning is OFF, ERROR, WARNING, INFO, VERBOSE, DEBUG and TRACE, + respectively. + Available for: initial manifest, type manifest, type gencode. __explorer Directory that contains all global explorers. Available for: initial manifest, explorer, type explorer, shell. diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index bfe3c35d..8c8605d1 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -331,6 +331,14 @@ So when you generate a script with the following content, it will work: fi +Log level in types +------------------ +cdist log level can be accessed from __cdist_loglevel variable. +Value is one of 60, 40, 30, 20, 15, 10 and 5 where the meaning is +OFF, ERROR, WARNING, INFO, VERBOSE, DEBUG and TRACE, respectively. +It is available for initial manifest, type manifest and type gencode. + + Hints for typewriters ---------------------- It must be assumed that the target is pretty dumb and thus does not have high From 92488e83d6c90fea629dbbe1ffe9500befb68947 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 6 Sep 2017 21:59:57 +0200 Subject: [PATCH 0634/1332] __debug -> __cdist_loglevel --- cdist/conf/type/__install_stage/gencode-remote | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_stage/gencode-remote b/cdist/conf/type/__install_stage/gencode-remote index 3eb90477..1da6e7e9 100755 --- a/cdist/conf/type/__install_stage/gencode-remote +++ b/cdist/conf/type/__install_stage/gencode-remote @@ -22,8 +22,16 @@ uri="$(cat "$__object/parameter/uri" 2>/dev/null \ || echo "$__object_id")" target="$(cat "$__object/parameter/target")" -[ "$__debug" = "yes" ] && curl="curl" || curl="curl -s" -[ "$__debug" = "yes" ] && tar="tar -xvzp" || tar="tar -xzp" +case "$__cdist_loglevel" in + 10|5) # DEBUG or TRACE + curl="curl" + tar="tar -xvzp" + ;; + *) + curl="curl -s" + tar="tar -xzp" + ;; +esac if [ -f "$__object/parameter/insecure" ] ; then curl="$curl -k" From 8360ca24452b915d8c7354c99ba6a24894a50081 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 6 Sep 2017 22:02:02 +0200 Subject: [PATCH 0635/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 3167cec6..25bcbe4e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Type __daemontools: Improve it on FreeBSD (Kamila Součková) * Type __package_pkg_openbsd: Fix use of --name (Philippe Gregoire) * Type __package_pkg_openbsd: Fix pkg_version explorer (Philippe Gregoire) + * Documentation: Document __cdist_loglevel type variable (Darko Poljak) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From 481b987c7e8ed9629667d4f3e48ac7402ec12d8d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Sep 2017 10:11:06 +0200 Subject: [PATCH 0636/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 25bcbe4e..4a7f8c8b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -11,6 +11,7 @@ next: * Type __package_pkg_openbsd: Fix use of --name (Philippe Gregoire) * Type __package_pkg_openbsd: Fix pkg_version explorer (Philippe Gregoire) * Documentation: Document __cdist_loglevel type variable (Darko Poljak) + * Type __install_stage: Fix __debug -> __cdist_loglevel (Darko Poljak) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From dd48c826564f54de2bc192792deed08179eec607 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Sep 2017 11:30:02 +0200 Subject: [PATCH 0637/1332] Log 'Processing' line even if dry run. --- cdist/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 0435201c..45f099de 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -649,9 +649,9 @@ class Config(object): cdist_object.changed = True # Execute + if cdist_object.code_local or cdist_object.code_remote: + self.log.info("Processing %s" % (cdist_object.name)) if not self.dry_run: - if cdist_object.code_local or cdist_object.code_remote: - self.log.info("Processing %s" % (cdist_object.name)) if cdist_object.code_local: self.log.trace("Executing local code for %s" % (cdist_object.name)) From e0a4fc4ea7916438aecf7e3b9feac7b7ae0b649e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Sep 2017 11:58:19 +0200 Subject: [PATCH 0638/1332] verbose -> info --- cdist/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index 45f099de..877014a0 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -662,7 +662,7 @@ class Config(object): self.code.transfer_code_remote(cdist_object) self.code.run_code_remote(cdist_object) else: - self.log.verbose("Skipping code execution due to DRY RUN") + self.log.info("Skipping code execution due to DRY RUN") # Mark this object as done self.log.trace("Finishing run of " + cdist_object.name) From cb38354df338f464588de02b919ea17712f5e056 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Sep 2017 12:10:17 +0200 Subject: [PATCH 0639/1332] Run cleanup commands in quiet mode for DEBUG, TRACE. --- cdist/config.py | 7 ++++++- cdist/exec/local.py | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 877014a0..6566205d 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -391,7 +391,12 @@ class Config(object): cmd = cleanup_cmd.split() cmd.append(self.local.target_host[0]) try: - self.local.run(cmd, return_output=False, save_output=False) + if self.log.getEffectiveLevel() <= logging.DEBUG: + quiet_mode = False + else: + quiet_mode = True + self.local.run(cmd, return_output=False, save_output=False, + quiet_mode=quiet_mode) except cdist.Error as e: # Log warning but continue. self.log.warning("Cleanup command failed: %s", e) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 1f2c66a3..468deb4a 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -201,7 +201,7 @@ class Local(object): os.makedirs(path, exist_ok=True) def run(self, command, env=None, return_output=False, message_prefix=None, - save_output=True): + save_output=True, quiet_mode=False): """Run the given command with the given environment. Return the output as a string. @@ -226,7 +226,7 @@ class Local(object): self.log.trace("Local run: %s", command) try: - if self.quiet_mode: + if self.quiet_mode or quiet_mode: stderr = subprocess.DEVNULL else: stderr = None @@ -242,7 +242,7 @@ class Local(object): # In some cases no output is saved. # This is used for shell command, stdout and stderr # must not be catched. - if self.quiet_mode: + if self.quiet_mode or quiet_mode: stdout = subprocess.DEVNULL else: stdout = None From 28d3466e9d252b12575890c1c42b284ee1d01118 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Sep 2017 12:32:04 +0200 Subject: [PATCH 0640/1332] Fix logging dry run line. --- cdist/config.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 6566205d..d367b6ad 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -666,8 +666,9 @@ class Config(object): % (cdist_object.name)) self.code.transfer_code_remote(cdist_object) self.code.run_code_remote(cdist_object) - else: - self.log.info("Skipping code execution due to DRY RUN") + elif cdist_object.code_local or cdist_object.code_remote: + self.log.info("Skipping code execution for %s due to DRY RUN", + cdist_object.name) # Mark this object as done self.log.trace("Finishing run of " + cdist_object.name) From 97f6517715aa91572d2ab8dd03e70d9e0e90cfac Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Sep 2017 16:13:46 +0200 Subject: [PATCH 0641/1332] Configuration fixes. --- cdist/argparse.py | 9 ++++++--- cdist/configuration.py | 18 +++++++++++++++++- cdist/test/configuration/__init__.py | 20 ++++++++++++++++++-- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 28d3840e..391541b0 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -106,7 +106,7 @@ def get_parsers(): 'The levels, in order from the lowest to the highest, are: ' 'ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) ' 'TRACE (4 or higher).'), - action='count', default=0) + action='count', default=None) parser['beta'] = argparse.ArgumentParser(add_help=False) parser['beta'].add_argument( @@ -417,8 +417,11 @@ def handle_loglevel(args): def parse_and_configure(argv, singleton=True): parser = get_parsers() parser_args = parser['main'].parse_args(argv) - cfg = cdist.configuration.Configuration(parser_args, singleton=singleton) - args = cfg.get_args() + try: + cfg = cdist.configuration.Configuration(parser_args, singleton=singleton) + args = cfg.get_args() + except ValueError as e: + raise cdist.Error(str(e)) # Loglevels are handled globally in here handle_loglevel(args) diff --git a/cdist/configuration.py b/cdist/configuration.py index fe7fdf1b..8fc5c473 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -285,6 +285,11 @@ class Configuration(metaclass=Singleton): ADJUST_ARG_OPTION_MAPPING = { _ARG_OPTION_MAPPING[key]: key for key in _ARG_OPTION_MAPPING } + REQUIRED_DEFAULT_CONFIG_VALUES = { + 'GLOBAL': { + 'verbosity': 0, + }, + } def _convert_args(self, args): if args: @@ -372,7 +377,8 @@ class Configuration(metaclass=Singleton): for option in self.ARG_OPTION_MAPPING: if option in args: dst_opt = self.ARG_OPTION_MAPPING[option] - d[dst_opt] = args[option] + if args[option]: + d[dst_opt] = args[option] return d def _update_config_dict(self, config, newconfig, update_appends=False): @@ -394,6 +400,15 @@ class Configuration(metaclass=Singleton): config[section][option] = option_object.update_value( currval, newval, update_appends) + def _update_defaults_for_unset(self, config): + defaults = self.REQUIRED_DEFAULT_CONFIG_VALUES + + for section in defaults: + section_values = defaults[section] + for option in section_values: + if option not in config[section]: + config[section][option] = section_values[option] + def _get_config(self): # global config file # local config file @@ -421,4 +436,5 @@ class Configuration(metaclass=Singleton): for section in config: self._update_config_dict_section(section, config, newconfig, update_appends=True) + self._update_defaults_for_unset(config) return config diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index acd6c0bb..0e324e0b 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -286,7 +286,6 @@ class ConfigurationTestCase(test.CdistTestCase): args.tag = 'test' expected = { - 'beta': False, 'conf_dir': ['/usr/local/cdist1', ], 'verbosity': 3, } @@ -373,12 +372,13 @@ class ConfigurationTestCase(test.CdistTestCase): args = argparse.Namespace() expected_config_dict = { 'GLOBAL': { + 'verbosity': 0, }, } # bypass singleton so we can test further cc.Configuration.instance = None - configuration = cc.Configuration(args, env=env) + configuration = cc.Configuration(args, env=env, config_files=('cdist.cfg')) self.assertIsNotNone(configuration.args) self.assertIsNotNone(configuration.env) self.assertIsNotNone(configuration.config_files) @@ -668,6 +668,20 @@ class ConfigurationTestCase(test.CdistTestCase): config_files=config_files) self.assertEqual(configuration.config, expected_config_dict) + def test_update_defaults_for_unset(self): + config = { + 'GLOBAL': { + }, + } + expected_config = { + 'GLOBAL': { + 'verbosity': 0, + }, + } + cfg = cc.Configuration(None, env={}, config_files=()) + cfg._update_defaults_for_unset(config) + self.assertEqual(config, expected_config) + def test_configuration6(self): env = { 'PATH': '/usr/local/bin:/usr/bin:/bin', @@ -725,6 +739,7 @@ class ConfigurationTestCase(test.CdistTestCase): args.conf_dir = ['/opt/sysadmin/cdist/conf', ] args.manifest = '/opt/sysadmin/cdist/conf/manifest/init' args.jobs = 10 + args.verbose = None expected_config_dict = { 'GLOBAL': { @@ -1092,6 +1107,7 @@ class ConfigurationTestCase(test.CdistTestCase): 'GLOBAL': { 'inventory_dir': None, 'conf_dir': None, + 'verbosity': 0, }, } From 2e4c0d3465196b7f7b8d2d515326602a4d704ab6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Sep 2017 16:33:22 +0200 Subject: [PATCH 0642/1332] Improve dry run logging. --- cdist/config.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index d367b6ad..e33a6027 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -371,7 +371,8 @@ class Config(object): """Do what is most often done: deploy & cleanup""" start_time = time.time() - self.log.info("Starting configuration run") + self.log.info("Starting {} run".format( + 'dry' if self.dry_run else 'configuration')) self._init_files_dirs() @@ -382,7 +383,8 @@ class Config(object): self._remove_files_dirs() self.local.save_cache(start_time) - self.log.info("Finished successful run in {:.2f} seconds".format( + self.log.info("Finished {} run in {:.2f} seconds".format( + 'dry' if self.dry_run else 'successful', time.time() - start_time)) def cleanup(self): @@ -666,9 +668,6 @@ class Config(object): % (cdist_object.name)) self.code.transfer_code_remote(cdist_object) self.code.run_code_remote(cdist_object) - elif cdist_object.code_local or cdist_object.code_remote: - self.log.info("Skipping code execution for %s due to DRY RUN", - cdist_object.name) # Mark this object as done self.log.trace("Finishing run of " + cdist_object.name) From 57f15f9cce199b18de11281b679af39e2c7c6a22 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Sep 2017 16:36:23 +0200 Subject: [PATCH 0643/1332] Make __cdist_loglevel value more expressive. (#571) --- .../conf/type/__install_config/gencode-local | 8 +++--- .../conf/type/__install_stage/gencode-remote | 2 +- cdist/core/manifest.py | 2 +- cdist/emulator.py | 10 +++++-- cdist/test/emulator/__init__.py | 28 +++++++++++++++++++ cdist/test/manifest/__init__.py | 1 + docs/changelog | 1 + docs/src/cdist-reference.rst.sh | 5 ++-- docs/src/cdist-type.rst | 5 ++-- 9 files changed, 48 insertions(+), 14 deletions(-) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index d7e98734..41517bd8 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -24,16 +24,16 @@ remote_copy="$__type/files/remote/copy" cdist_args="" case "$__cdist_loglevel" in - 20) + INFO) cdist_args="-v" ;; - 15) + VERBOSE) cdist_args="-vv" ;; - 10) + DEBUG) cdist_args="-vvv" ;; - 5) + TRACE) cdist_args="-vvvv" ;; esac diff --git a/cdist/conf/type/__install_stage/gencode-remote b/cdist/conf/type/__install_stage/gencode-remote index 1da6e7e9..214e4b52 100755 --- a/cdist/conf/type/__install_stage/gencode-remote +++ b/cdist/conf/type/__install_stage/gencode-remote @@ -23,7 +23,7 @@ uri="$(cat "$__object/parameter/uri" 2>/dev/null \ target="$(cat "$__object/parameter/target")" case "$__cdist_loglevel" in - 10|5) # DEBUG or TRACE + DEBUG|TRACE) curl="curl" tar="tar -xvzp" ;; diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 0a26601a..b7538887 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -114,7 +114,7 @@ class Manifest(object): } self.env.update( - {'__cdist_loglevel': str(self.log.getEffectiveLevel())}) + {'__cdist_loglevel': logging.getLevelName(self.log.getEffectiveLevel())}) def _open_logger(self): self.log = logging.getLogger(self.target_host[0]) diff --git a/cdist/emulator.py b/cdist/emulator.py index f1419ceb..f3e9b9b0 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -111,12 +111,18 @@ class Emulator(object): if '__cdist_loglevel' in self.env: try: - level = int(self.env['__cdist_loglevel']) + loglevel = self.env['__cdist_loglevel'] + # For a text level it returns its numerical value. + level = logging.getLevelName(loglevel) except ValueError: level = logging.WARNING else: level = logging.WARNING - logging.root.setLevel(level) + try: + logging.root.setLevel(level) + except (ValueError, TypeError): + # if invalid __cdist_loglevel value + logging.root.setLevel(logging.WARNING) self.log = logging.getLogger(self.target_host[0]) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 664ab20b..a63ce04a 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -27,6 +27,7 @@ import shutil import string import filecmp import random +import logging import cdist from cdist import test @@ -63,6 +64,8 @@ class EmulatorTestCase(test.CdistTestCase): self.manifest = core.Manifest(self.target_host, self.local) self.env = self.manifest.env_initial_manifest(self.script) self.env['__cdist_object_marker'] = self.local.object_marker_name + if '__cdist_loglevel' in self.env: + del self.env['__cdist_loglevel'] def tearDown(self): shutil.rmtree(self.temp_dir) @@ -115,6 +118,31 @@ class EmulatorTestCase(test.CdistTestCase): emu = emulator.Emulator(argv, env=self.env) # if we get here all is fine + def test_loglevel(self): + argv = ['__file', '/tmp/foobar'] + self.env['require'] = '__file/etc/*' + emu = emulator.Emulator(argv, env=self.env) + emu_loglevel = emu.log.getEffectiveLevel() + self.assertEqual(emu_loglevel, logging.WARNING) + self.env['__cdist_loglevel'] = logging.getLevelName(logging.DEBUG) + emu = emulator.Emulator(argv, env=self.env) + emu_loglevel = emu.log.getEffectiveLevel() + self.assertEqual(emu_loglevel, logging.DEBUG) + del self.env['__cdist_loglevel'] + + def test_invalid_loglevel_value(self): + argv = ['__file', '/tmp/foobar'] + self.env['require'] = '__file/etc/*' + emu = emulator.Emulator(argv, env=self.env) + emu_loglevel = emu.log.getEffectiveLevel() + self.assertEqual(emu_loglevel, logging.WARNING) + # lowercase is invalid + self.env['__cdist_loglevel'] = 'debug' + emu = emulator.Emulator(argv, env=self.env) + emu_loglevel = emu.log.getEffectiveLevel() + self.assertEqual(emu_loglevel, logging.WARNING) + del self.env['__cdist_loglevel'] + def test_requirement_via_order_dependency(self): self.env['CDIST_ORDER_DEPENDENCY'] = 'on' argv = ['__planet', 'erde'] diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index 95bf2768..3462c9ca 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -137,6 +137,7 @@ class ManifestTestCase(test.CdistTestCase): self.log.setLevel(logging.DEBUG) manifest = cdist.core.manifest.Manifest(self.target_host, self.local) self.assertTrue("__cdist_loglevel" in manifest.env) + self.assertEqual(manifest.env["__cdist_loglevel"], 'DEBUG') self.log.setLevel(current_level) diff --git a/docs/changelog b/docs/changelog index 4a7f8c8b..3006e188 100644 --- a/docs/changelog +++ b/docs/changelog @@ -12,6 +12,7 @@ next: * Type __package_pkg_openbsd: Fix pkg_version explorer (Philippe Gregoire) * Documentation: Document __cdist_loglevel type variable (Darko Poljak) * Type __install_stage: Fix __debug -> __cdist_loglevel (Darko Poljak) + * Core, types: Make __cdist_loglevel value more expressive (Darko Poljak) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index cb717c4a..0117c04d 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -199,9 +199,8 @@ Environment variables (for reading) The following environment variables are exported by cdist: __cdist_loglevel - Value of cdist log level. One of 60, 40, 30, 20, 15, 10 and 5 where - the meaning is OFF, ERROR, WARNING, INFO, VERBOSE, DEBUG and TRACE, - respectively. + String value of cdist log level. One of OFF, ERROR, WARNING, INFO, + VERBOSE, DEBUG and TRACE. Available for: initial manifest, type manifest, type gencode. __explorer Directory that contains all global explorers. diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 8c8605d1..2e6cbc96 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -334,9 +334,8 @@ So when you generate a script with the following content, it will work: Log level in types ------------------ cdist log level can be accessed from __cdist_loglevel variable. -Value is one of 60, 40, 30, 20, 15, 10 and 5 where the meaning is -OFF, ERROR, WARNING, INFO, VERBOSE, DEBUG and TRACE, respectively. -It is available for initial manifest, type manifest and type gencode. +Value is a string, one of OFF, ERROR, WARNING, INFO, VERBOSE, DEBUG and +TRACE. It is available for initial manifest, type manifest and type gencode. Hints for typewriters From f08ac264a09ae7bfef13b32bd5966985969a8af4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 7 Sep 2017 16:37:49 +0200 Subject: [PATCH 0644/1332] pep8 --- cdist/argparse.py | 3 ++- cdist/core/manifest.py | 3 ++- cdist/test/configuration/__init__.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 391541b0..1b655ebf 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -418,7 +418,8 @@ def parse_and_configure(argv, singleton=True): parser = get_parsers() parser_args = parser['main'].parse_args(argv) try: - cfg = cdist.configuration.Configuration(parser_args, singleton=singleton) + cfg = cdist.configuration.Configuration(parser_args, + singleton=singleton) args = cfg.get_args() except ValueError as e: raise cdist.Error(str(e)) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index b7538887..98a44629 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -114,7 +114,8 @@ class Manifest(object): } self.env.update( - {'__cdist_loglevel': logging.getLevelName(self.log.getEffectiveLevel())}) + {'__cdist_loglevel': logging.getLevelName( + self.log.getEffectiveLevel())}) def _open_logger(self): self.log = logging.getLogger(self.target_host[0]) diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index 0e324e0b..3630fb95 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -378,7 +378,8 @@ class ConfigurationTestCase(test.CdistTestCase): # bypass singleton so we can test further cc.Configuration.instance = None - configuration = cc.Configuration(args, env=env, config_files=('cdist.cfg')) + configuration = cc.Configuration(args, env=env, + config_files=('cdist.cfg')) self.assertIsNotNone(configuration.args) self.assertIsNotNone(configuration.env) self.assertIsNotNone(configuration.config_files) From 3454da076f911d3d196df28cb41d9f3a2cb68f61 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 9 Sep 2017 21:17:29 +0200 Subject: [PATCH 0645/1332] Add -l/--log-level option. Honor __cdist_loglevel env var. (#572) Add -l/--log-level option, __cdist_loglevel -> __cdist_log_level; honor __cdist_log_level env var --- cdist/argparse.py | 28 +++++++-- .../conf/type/__install_config/gencode-local | 17 ------ .../conf/type/__install_stage/gencode-remote | 2 +- cdist/configuration.py | 1 + cdist/core/__init__.py | 1 + cdist/core/code.py | 2 + cdist/core/explorer.py | 2 + cdist/core/manifest.py | 6 +- cdist/core/util.py | 5 ++ cdist/emulator.py | 6 +- cdist/test/code/__init__.py | 3 + .../type/__dump_environment/gencode-local | 1 + cdist/test/emulator/__init__.py | 12 ++-- cdist/test/explorer/__init__.py | 25 ++++++++ .../conf/type/__dump_env/explorer/dump | 8 +++ cdist/test/manifest/__init__.py | 20 +++++-- .../fixtures/conf/manifest/dump_environment | 1 + .../conf/type/__dump_environment/manifest | 1 + docs/changelog | 2 + docs/src/cdist-reference.rst.sh | 12 +++- docs/src/cdist-type.rst | 5 +- docs/src/man1/cdist.rst | 58 ++++++++++++------- scripts/cdist | 3 +- 23 files changed, 152 insertions(+), 69 deletions(-) create mode 100755 cdist/test/explorer/fixtures/conf/type/__dump_env/explorer/dump diff --git a/cdist/argparse.py b/cdist/argparse.py index 1b655ebf..5bce1b76 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -3,6 +3,7 @@ import cdist import multiprocessing import logging import collections +import functools import cdist.configuration @@ -72,15 +73,15 @@ def check_beta(args_dict): raise cdist.CdistBetaRequired(cmd, arg) -def check_positive_int(value): +def check_lower_bounded_int(value, lower_bound, name): try: val = int(value) except ValueError: raise argparse.ArgumentTypeError( "{} is invalid int value".format(value)) - if val <= 0: + if val < lower_bound: raise argparse.ArgumentTypeError( - "{} is invalid positive int value".format(val)) + "{} is invalid {} value".format(val, name)) return val @@ -94,6 +95,17 @@ def get_parsers(): parser = {} # Options _all_ parsers have in common parser['loglevel'] = argparse.ArgumentParser(add_help=False) + parser['loglevel'].add_argument( + '-l', '--log-level', metavar='LOGLEVEL', + type=functools.partial(check_lower_bounded_int, lower_bound=-1, + name="log level"), + help=('Set the specified verbosity level. ' + 'The levels, in order from the lowest to the highest, are: ' + 'ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) ' + 'TRACE (4 or higher). If used along with -v then -v ' + 'increases last set value and -l overwrites last set ' + 'value.'), + action='store', dest='verbose', required=False) parser['loglevel'].add_argument( '-q', '--quiet', help='Quiet mode: disables logging, including WARNING and ERROR.', @@ -105,7 +117,9 @@ def get_parsers(): 'is 0 which includes ERROR and WARNING levels. ' 'The levels, in order from the lowest to the highest, are: ' 'ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) ' - 'TRACE (4 or higher).'), + 'TRACE (4 or higher). If used along with -l then -l ' + 'overwrites last set value and -v increases last set ' + 'value.'), action='count', default=None) parser['beta'] = argparse.ArgumentParser(add_help=False) @@ -164,7 +178,8 @@ def get_parsers(): dest='manifest', required=False) parser['config_main'].add_argument( '-j', '--jobs', nargs='?', - type=check_positive_int, + type=functools.partial(check_lower_bounded_int, lower_bound=1, + name="positive int"), help=('Operate in parallel in specified maximum number of jobs. ' 'Global explorers, object prepare and object run are ' 'supported. Without argument CPU count is used by default. ' @@ -229,7 +244,8 @@ def get_parsers(): dest='hostfile', required=False) parser['config_args'].add_argument( '-p', '--parallel', nargs='?', metavar='HOST_MAX', - type=check_positive_int, + type=functools.partial(check_lower_bounded_int, lower_bound=1, + name="positive int"), help=('Operate on multiple hosts in parallel for specified maximum ' 'hosts at a time. Without argument CPU count is used by ' 'default.'), diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 41517bd8..a298a5cc 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -22,27 +22,10 @@ chroot="$(cat "$__object/parameter/chroot")" remote_exec="$__type/files/remote/exec" remote_copy="$__type/files/remote/copy" -cdist_args="" -case "$__cdist_loglevel" in - INFO) - cdist_args="-v" - ;; - VERBOSE) - cdist_args="-vv" - ;; - DEBUG) - cdist_args="-vvv" - ;; - TRACE) - cdist_args="-vvvv" - ;; -esac - cat << DONE export __default_remote_exec="$__remote_exec" export __default_remote_copy="$__remote_copy" cdist config \ - $cdist_args \ --remote-exec="$remote_exec $chroot" \ --remote-copy="$remote_copy $chroot" \ $__target_host diff --git a/cdist/conf/type/__install_stage/gencode-remote b/cdist/conf/type/__install_stage/gencode-remote index 214e4b52..4d013e3d 100755 --- a/cdist/conf/type/__install_stage/gencode-remote +++ b/cdist/conf/type/__install_stage/gencode-remote @@ -22,7 +22,7 @@ uri="$(cat "$__object/parameter/uri" 2>/dev/null \ || echo "$__object_id")" target="$(cat "$__object/parameter/target")" -case "$__cdist_loglevel" in +case "$__cdist_log_level" in DEBUG|TRACE) curl="curl" tar="tar -xvzp" diff --git a/cdist/configuration.py b/cdist/configuration.py index 8fc5c473..30176200 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -278,6 +278,7 @@ class Configuration(metaclass=Singleton): 'CDIST_REMOTE_COPY': 'remote_copy', 'CDIST_INVENTORY_DIR': 'inventory_dir', 'CDIST_CACHE_PATH_PATTERN': 'cache_path_pattern', + '__cdist_log_level': 'verbosity', } ENV_VAR_BOOLEAN_OPTIONS = ('CDIST_BETA', ) diff --git a/cdist/core/__init__.py b/cdist/core/__init__.py index 8c384b3c..adec60b2 100644 --- a/cdist/core/__init__.py +++ b/cdist/core/__init__.py @@ -28,3 +28,4 @@ from cdist.core.explorer import Explorer from cdist.core.manifest import Manifest from cdist.core.code import Code from cdist.core.util import listdir +from cdist.core.util import log_level_env_var_val diff --git a/cdist/core/code.py b/cdist/core/code.py index 94ede0f9..5ada4c14 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -22,6 +22,7 @@ # import os +from . import util ''' @@ -107,6 +108,7 @@ class Code(object): '__global': self.local.base_path, '__files': self.local.files_path, '__target_host_tags': self.local.target_host_tags, + '__cdist_log_level': util.log_level_env_var_val(local.log), } def _run_gencode(self, cdist_object, which): diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 38f2a921..8d7cd593 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -25,6 +25,7 @@ import os import glob import multiprocessing from cdist.mputil import mp_pool_run +from . import util ''' common: @@ -78,6 +79,7 @@ class Explorer(object): '__target_fqdn': self.target_host[2], '__explorer': self.remote.global_explorer_path, '__target_host_tags': self.local.target_host_tags, + '__cdist_log_level': util.log_level_env_var_val(self.log), } self._type_explorers_transferred = [] self.jobs = jobs diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 98a44629..e69db63f 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -24,6 +24,7 @@ import logging import os import cdist +from . import util ''' common: @@ -111,12 +112,9 @@ class Manifest(object): '__target_fqdn': self.target_host[2], '__files': self.local.files_path, '__target_host_tags': self.local.target_host_tags, + '__cdist_log_level': util.log_level_env_var_val(self.log), } - self.env.update( - {'__cdist_loglevel': logging.getLevelName( - self.log.getEffectiveLevel())}) - def _open_logger(self): self.log = logging.getLogger(self.target_host[0]) diff --git a/cdist/core/util.py b/cdist/core/util.py index ca48c4c8..cce608bc 100644 --- a/cdist/core/util.py +++ b/cdist/core/util.py @@ -20,6 +20,7 @@ # import os +import logging def listdir(path='.', include_dot=False): @@ -34,3 +35,7 @@ def listdir(path='.', include_dot=False): def _ishidden(path): return path[0] in ('.', b'.'[0]) + + +def log_level_env_var_val(log): + return logging.getLevelName(log.getEffectiveLevel()) diff --git a/cdist/emulator.py b/cdist/emulator.py index f3e9b9b0..0655fe9c 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -109,9 +109,9 @@ class Emulator(object): def __init_log(self): """Setup logging facility""" - if '__cdist_loglevel' in self.env: + if '__cdist_log_level' in self.env: try: - loglevel = self.env['__cdist_loglevel'] + loglevel = self.env['__cdist_log_level'] # For a text level it returns its numerical value. level = logging.getLevelName(loglevel) except ValueError: @@ -121,7 +121,7 @@ class Emulator(object): try: logging.root.setLevel(level) except (ValueError, TypeError): - # if invalid __cdist_loglevel value + # if invalid __cdist_log_level value logging.root.setLevel(logging.WARNING) self.log = logging.getLogger(self.target_host[0]) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 50da2b8a..4d0427aa 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -23,6 +23,7 @@ import getpass import os import shutil +import logging import cdist from cdist import core @@ -100,6 +101,7 @@ class CodeTestCase(test.CdistTestCase): self.assertEqual(output_dict['__files'], self.local.files_path) self.assertEqual(output_dict['__target_host_tags'], self.local.target_host_tags) + self.assertEqual(output_dict['__cdist_log_level'], 'WARNING') def test_run_gencode_remote_environment(self): output_string = self.code.run_gencode_remote(self.cdist_object) @@ -125,6 +127,7 @@ class CodeTestCase(test.CdistTestCase): self.assertEqual(output_dict['__files'], self.local.files_path) self.assertEqual(output_dict['__target_host_tags'], self.local.target_host_tags) + self.assertEqual(output_dict['__cdist_log_level'], 'WARNING') def test_transfer_code_remote(self): self.cdist_object.code_remote = self.code.run_gencode_remote( diff --git a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local index 56744a27..35120f10 100755 --- a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local +++ b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local @@ -10,3 +10,4 @@ echo "echo __object_id: $__object_id" echo "echo __object_name: $__object_name" echo "echo __files: $__files" echo "echo __target_host_tags: $__target_host_tags" +echo "echo __cdist_log_level: $__cdist_log_level" diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index a63ce04a..48c5362e 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -64,8 +64,8 @@ class EmulatorTestCase(test.CdistTestCase): self.manifest = core.Manifest(self.target_host, self.local) self.env = self.manifest.env_initial_manifest(self.script) self.env['__cdist_object_marker'] = self.local.object_marker_name - if '__cdist_loglevel' in self.env: - del self.env['__cdist_loglevel'] + if '__cdist_log_level' in self.env: + del self.env['__cdist_log_level'] def tearDown(self): shutil.rmtree(self.temp_dir) @@ -124,11 +124,11 @@ class EmulatorTestCase(test.CdistTestCase): emu = emulator.Emulator(argv, env=self.env) emu_loglevel = emu.log.getEffectiveLevel() self.assertEqual(emu_loglevel, logging.WARNING) - self.env['__cdist_loglevel'] = logging.getLevelName(logging.DEBUG) + self.env['__cdist_log_level'] = logging.getLevelName(logging.DEBUG) emu = emulator.Emulator(argv, env=self.env) emu_loglevel = emu.log.getEffectiveLevel() self.assertEqual(emu_loglevel, logging.DEBUG) - del self.env['__cdist_loglevel'] + del self.env['__cdist_log_level'] def test_invalid_loglevel_value(self): argv = ['__file', '/tmp/foobar'] @@ -137,11 +137,11 @@ class EmulatorTestCase(test.CdistTestCase): emu_loglevel = emu.log.getEffectiveLevel() self.assertEqual(emu_loglevel, logging.WARNING) # lowercase is invalid - self.env['__cdist_loglevel'] = 'debug' + self.env['__cdist_log_level'] = 'debug' emu = emulator.Emulator(argv, env=self.env) emu_loglevel = emu.log.getEffectiveLevel() self.assertEqual(emu_loglevel, logging.WARNING) - del self.env['__cdist_loglevel'] + del self.env['__cdist_log_level'] def test_requirement_via_order_dependency(self): self.env['CDIST_ORDER_DEPENDENCY'] = 'on' diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 928b4e0d..48b54cd7 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -210,6 +210,31 @@ class ExplorerClassTestCase(test.CdistTestCase): self.assertEqual(names, output) shutil.rmtree(out_path) + def test_explorer_environment(self): + cdist_type = core.CdistType(self.local.type_path, '__dump_env') + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + 'whatever') + self.explorer.transfer_type_explorers(cdist_type) + output = self.explorer.run_type_explorer('dump', cdist_object) + + output_dict = {} + for line in output.split('\n'): + if line: + key, value = line.split(': ') + output_dict[key] = value + self.assertEqual(output_dict['__target_host'], + self.local.target_host[0]) + self.assertEqual(output_dict['__target_hostname'], + self.local.target_host[1]) + self.assertEqual(output_dict['__target_fqdn'], + self.local.target_host[2]) + self.assertEqual(output_dict['__explorer'], + self.remote.global_explorer_path) + self.assertEqual(output_dict['__target_host_tags'], + self.local.target_host_tags) + self.assertEqual(output_dict['__cdist_log_level'], 'WARNING') + if __name__ == '__main__': import unittest diff --git a/cdist/test/explorer/fixtures/conf/type/__dump_env/explorer/dump b/cdist/test/explorer/fixtures/conf/type/__dump_env/explorer/dump new file mode 100755 index 00000000..ae477cd0 --- /dev/null +++ b/cdist/test/explorer/fixtures/conf/type/__dump_env/explorer/dump @@ -0,0 +1,8 @@ +#!/bin/sh + +echo "__target_host: $__target_host" +echo "__target_hostname: $__target_hostname" +echo "__target_fqdn: $__target_fqdn" +echo "__explorer: $__explorer" +echo "__target_host_tags: $__target_host_tags" +echo "__cdist_log_level: $__cdist_log_level" diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index 3462c9ca..5b372f35 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -73,7 +73,10 @@ class ManifestTestCase(test.CdistTestCase): handle, output_file = self.mkstemp(dir=self.temp_dir) os.close(handle) os.environ['__cdist_test_out'] = output_file - self.manifest.run_initial_manifest(initial_manifest) + old_loglevel = logging.root.getEffectiveLevel() + self.log.setLevel(logging.VERBOSE) + manifest = cdist.core.manifest.Manifest(self.target_host, self.local) + manifest.run_initial_manifest(initial_manifest) with open(output_file, 'r') as fd: output_string = fd.read() @@ -96,6 +99,8 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__files'], self.local.files_path) self.assertEqual(output_dict['__target_host_tags'], self.local.target_host_tags) + self.assertEqual(output_dict['__cdist_log_level'], 'VERBOSE') + self.log.setLevel(old_loglevel) def test_type_manifest_environment(self): cdist_type = core.CdistType(self.local.type_path, '__dump_environment') @@ -105,7 +110,10 @@ class ManifestTestCase(test.CdistTestCase): handle, output_file = self.mkstemp(dir=self.temp_dir) os.close(handle) os.environ['__cdist_test_out'] = output_file - self.manifest.run_type_manifest(cdist_object) + old_loglevel = self.log.getEffectiveLevel() + self.log.setLevel(logging.VERBOSE) + manifest = cdist.core.manifest.Manifest(self.target_host, self.local) + manifest.run_type_manifest(cdist_object) with open(output_file, 'r') as fd: output_string = fd.read() @@ -131,13 +139,15 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__files'], self.local.files_path) self.assertEqual(output_dict['__target_host_tags'], self.local.target_host_tags) + self.assertEqual(output_dict['__cdist_log_level'], 'VERBOSE') + self.log.setLevel(old_loglevel) - def test_debug_env_setup(self): + def test_loglevel_env_setup(self): current_level = self.log.getEffectiveLevel() self.log.setLevel(logging.DEBUG) manifest = cdist.core.manifest.Manifest(self.target_host, self.local) - self.assertTrue("__cdist_loglevel" in manifest.env) - self.assertEqual(manifest.env["__cdist_loglevel"], 'DEBUG') + self.assertTrue("__cdist_log_level" in manifest.env) + self.assertEqual(manifest.env["__cdist_log_level"], 'DEBUG') self.log.setLevel(current_level) diff --git a/cdist/test/manifest/fixtures/conf/manifest/dump_environment b/cdist/test/manifest/fixtures/conf/manifest/dump_environment index 9f9df372..adf3c3e0 100755 --- a/cdist/test/manifest/fixtures/conf/manifest/dump_environment +++ b/cdist/test/manifest/fixtures/conf/manifest/dump_environment @@ -10,4 +10,5 @@ __cdist_type_base_path: $__cdist_type_base_path __manifest: $__manifest __files: $__files __target_host_tags: $__target_host_tags +__cdist_log_level: $__cdist_log_level DONE diff --git a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest index fec5cb3f..f2ae74e2 100755 --- a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest +++ b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest @@ -14,4 +14,5 @@ __object_id: $__object_id __object_name: $__object_name __files: $__files __target_host_tags: $__target_host_tags +__cdist_log_level: $__cdist_log_level DONE diff --git a/docs/changelog b/docs/changelog index 3006e188..5105a503 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,8 @@ next: * Documentation: Document __cdist_loglevel type variable (Darko Poljak) * Type __install_stage: Fix __debug -> __cdist_loglevel (Darko Poljak) * Core, types: Make __cdist_loglevel value more expressive (Darko Poljak) + * Core: Add -l/--log-level option (Darko Poljak) + * Core: __cdist_loglevel -> __cdist_log_level and make cdist honor __cdist_log_level env var (Darko Poljak) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index 0117c04d..ec3216c2 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -198,10 +198,11 @@ Environment variables (for reading) ----------------------------------- The following environment variables are exported by cdist: -__cdist_loglevel +__cdist_log_level String value of cdist log level. One of OFF, ERROR, WARNING, INFO, VERBOSE, DEBUG and TRACE. - Available for: initial manifest, type manifest, type gencode. + Available for: initial manifest, explorer, type manifest, type explorer, + type gencode. __explorer Directory that contains all global explorers. Available for: initial manifest, explorer, type explorer, shell. @@ -264,6 +265,13 @@ The following environment variables influence the behaviour of cdist: require Setup dependencies between objects (see \`cdist manifest \`_). +__cdist_log_level + String value of cdist log level. One of OFF, ERROR, WARNING, INFO, + VERBOSE, DEBUG and TRACE. If set cdist will set this log level in + accordance with configuration rules. If cdist invokation is used + in types then nested cdist will honor this specified log level if + not specified otherwise while invoking it. + CDIST_PATH Colon delimited list of config directories. diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 2e6cbc96..dbecc409 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -333,9 +333,10 @@ So when you generate a script with the following content, it will work: Log level in types ------------------ -cdist log level can be accessed from __cdist_loglevel variable. +cdist log level can be accessed from __cdist_log_level variable. Value is a string, one of OFF, ERROR, WARNING, INFO, VERBOSE, DEBUG and -TRACE. It is available for initial manifest, type manifest and type gencode. +TRACE. It is available for initial manifest, explorer, type manifest, +type explorer, type gencode. Hints for typewriters diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 0e258d8c..c21b9996 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -11,11 +11,12 @@ SYNOPSIS :: - cdist [-h] [-q] [-v] [-V] {banner,config,install,inventory,shell} ... + cdist [-h] [-l LOGLEVEL] [-q] [-v] [-V] + {banner,config,install,inventory,shell} ... - cdist banner [-h] [-q] [-v] + cdist banner [-h] [-l LOGLEVEL] [-q] [-v] - cdist config [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + cdist config [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] @@ -23,7 +24,7 @@ SYNOPSIS [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] [host [host ...]] - cdist install [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + cdist install [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] @@ -31,32 +32,35 @@ SYNOPSIS [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] [host [host ...]] - cdist inventory [-h] [-q] [-v] [-b] [-g CONFIG_FILE] [-I INVENTORY_DIR] + cdist inventory [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] + [-I INVENTORY_DIR] {add-host,add-tag,del-host,del-tag,list} ... - cdist inventory add-host [-h] [-q] [-v] [-b] [-g CONFIG_FILE] - [-I INVENTORY_DIR] [-f HOSTFILE] + cdist inventory add-host [-h] [-l LOGLEVEL] [-q] [-v] [-b] + [-g CONFIG_FILE] [-I INVENTORY_DIR] + [-f HOSTFILE] [host [host ...]] - cdist inventory add-tag [-h] [-q] [-v] [-b] [-g CONFIG_FILE] - [-I INVENTORY_DIR] [-f HOSTFILE] [-T TAGFILE] - [-t TAGLIST] + cdist inventory add-tag [-h] [-l LOGLEVEL] [-q] [-v] [-b] + [-g CONFIG_FILE] [-I INVENTORY_DIR] + [-f HOSTFILE] [-T TAGFILE] [-t TAGLIST] [host [host ...]] - cdist inventory del-host [-h] [-q] [-v] [-b] [-g CONFIG_FILE] - [-I INVENTORY_DIR] [-a] [-f HOSTFILE] + cdist inventory del-host [-h] [-l LOGLEVEL] [-q] [-v] [-b] + [-g CONFIG_FILE] [-I INVENTORY_DIR] [-a] + [-f HOSTFILE] [host [host ...]] - cdist inventory del-tag [-h] [-q] [-v] [-b] [-g CONFIG_FILE] - [-I INVENTORY_DIR] [-a] [-f HOSTFILE] - [-T TAGFILE] [-t TAGLIST] + cdist inventory del-tag [-h] [-l LOGLEVEL] [-q] [-v] [-b] + [-g CONFIG_FILE] [-I INVENTORY_DIR] [-a] + [-f HOSTFILE] [-T TAGFILE] [-t TAGLIST] [host [host ...]] - cdist inventory list [-h] [-q] [-v] [-b] [-g CONFIG_FILE] + cdist inventory list [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] [-I INVENTORY_DIR] [-a] [-f HOSTFILE] [-H] [-t] [host [host ...]] - cdist shell [-h] [-q] [-v] [-s SHELL] + cdist shell [-h] [-l LOGLEVEL] [-q] [-v] [-s SHELL] DESCRIPTION @@ -75,16 +79,28 @@ All commands accept the following options: Show the help screen. +.. option:: -l LOGLEVEL, --log-level LOGLEVEL + + Set the specified verbosity level. The levels, in + order from the lowest to the highest, are: ERROR (-1), + WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) TRACE (4 + or higher). If used along with -v then -v increases + last set value and -l overwrites last set value. + .. option:: -q, --quiet Quiet mode: disables logging, including WARNING and ERROR. .. option:: -v, --verbose - Increase the verbosity level. Every instance of -v increments the verbosity - level by one. Its default value is 0 which includes ERROR and WARNING levels. - The levels, in order from the lowest to the highest, are: - ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) TRACE (4 or higher). + Increase the verbosity level. Every instance of -v + increments the verbosity level by one. Its default + value is 0 which includes ERROR and WARNING levels. + The levels, in order from the lowest to the highest, + are: ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), + DEBUG (3) TRACE (4 or higher). If used along with -l + then -l overwrites last set value and -v increases + last set value. .. option:: -V, --version diff --git a/scripts/cdist b/scripts/cdist index 93fa392d..088e4dc2 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -22,6 +22,7 @@ # import logging +import sys import cdist import cdist.argparse import cdist.banner @@ -56,8 +57,6 @@ def commandline(): if __name__ == "__main__": - import sys - cdistpythonversion = '3.2' if sys.version < cdistpythonversion: print('Python >= {} is required on the source host.'.format( From 1f00a357950749cd63fac016e7ca8f470bf7fcd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Sat, 9 Sep 2017 21:21:15 +0200 Subject: [PATCH 0646/1332] fixes + go version bump in __prometheus_exporter (#573) --- cdist/conf/type/__prometheus_exporter/man.rst | 7 +++++ .../conf/type/__prometheus_exporter/manifest | 29 +++++++++---------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/cdist/conf/type/__prometheus_exporter/man.rst b/cdist/conf/type/__prometheus_exporter/man.rst index f91fe668..3b1ee4d7 100644 --- a/cdist/conf/type/__prometheus_exporter/man.rst +++ b/cdist/conf/type/__prometheus_exporter/man.rst @@ -16,6 +16,13 @@ Daemontools (or something compatible) must be installed (in particular, the comm This type installs and builds the latest version from git, using go get. A recent version of golang as well as build tools (make, g++, etc.) must be available. +Currently supported exporters: + +- node +- blackbox +- ceph + + REQUIRED PARAMETERS ------------------- None diff --git a/cdist/conf/type/__prometheus_exporter/manifest b/cdist/conf/type/__prometheus_exporter/manifest index 3d8f460c..ae4ed94a 100644 --- a/cdist/conf/type/__prometheus_exporter/manifest +++ b/cdist/conf/type/__prometheus_exporter/manifest @@ -10,41 +10,40 @@ __user prometheus --system case $exporter in node) TEXTFILES=/service/node-exporter/textfiles # path for the textfiles collector + __directory $TEXTFILES --parents --mode 777 + require="$require __golang_from_vendor" __go_get github.com/prometheus/node_exporter port=9100 run="setuidgid prometheus $GOBIN/node_exporter -web.listen-address :$port -collector.textfile.directory=$TEXTFILES" - - require="__golang_from_vendor" __go_get github.com/prometheus/node_exporter - __directory $TEXTFILES --parents --mode 777 ;; blackbox) - port=9115 - run="setuidgid prometheus $GOBIN/blackbox_exporter -config.file=/service/blackbox-exporter/blackbox.yml" - - require="__daemontools_service/blackbox-exporter __user/prometheus" __config_file "/service/blackbox-exporter/blackbox.yml" \ + require="$require __daemontools_service/${exporter}-exporter __user/prometheus" __config_file "/service/${exporter}-exporter/blackbox.yml" \ --source $__type/files/blackbox.yml \ --group prometheus --mode 640 \ - --onchange "svc -h /service/blackbox-exporter" - require="__golang_from_vendor" __go_get github.com/prometheus/blackbox_exporter + --onchange "svc -h /service/${exporter}-exporter" + require="$require __golang_from_vendor" __go_get github.com/prometheus/blackbox_exporter + + port=9115 + run="setuidgid prometheus $GOBIN/blackbox_exporter -config.file=/service/${exporter}-exporter/blackbox.yml" ;; ceph) + __package librados-dev # dependency of ceph_exporter + require="$require __golang_from_vendor __package/librados-dev" __go_get github.com/digitalocean/ceph_exporter + port=9128 run="setuidgid ceph $GOBIN/ceph_exporter -ceph.config /etc/ceph/ceph.conf -telemetry.addr :$port" - - __package librados-dev # dependency of ceph_exporter - require="__golang_from_vendor __package/librados-dev" __go_get github.com/digitalocean/ceph_exporter ;; *) - echo "Unknown exporter: $exporter." >&2 + echo "Unsupported exporter: $exporter." >&2 exit 1 ;; esac -require="__daemontools" __daemontools_service ${exporter}-exporter --run "$run" +require="$require __daemontools" __daemontools_service ${exporter}-exporter --run "$run" if [ -f "$__object/parameter/add-consul-service" ]; then __consul_service ${exporter}-exporter --port $port --check-http "http://localhost:$port/metrics" --check-interval 10s fi #__daemontools --install-init-script __daemontools -__golang_from_vendor --version 1.8.1 # required for many exporters +__golang_from_vendor --version 1.9 # required for many exporters From 3f6a3005679e8b2f75ce20f4429baae11df7b970 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 9 Sep 2017 21:21:55 +0200 Subject: [PATCH 0647/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 5105a503..9ca5e2f2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -15,6 +15,7 @@ next: * Core, types: Make __cdist_loglevel value more expressive (Darko Poljak) * Core: Add -l/--log-level option (Darko Poljak) * Core: __cdist_loglevel -> __cdist_log_level and make cdist honor __cdist_log_level env var (Darko Poljak) + * Type __prometheus_exporter: Fixes + go version bump (Kamila Součková) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From 519eb606645a56fa984abb0833b6412ba175d34f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 10 Sep 2017 22:05:05 +0200 Subject: [PATCH 0648/1332] Fix exec/{local,remote} tests. Add exec/local test to make test. --- cdist/test/exec/__init__.py | 7 +++++++ cdist/test/exec/local.py | 11 ++++++++++- cdist/test/exec/remote.py | 9 +++++---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/cdist/test/exec/__init__.py b/cdist/test/exec/__init__.py index e69de29b..b55cffa9 100644 --- a/cdist/test/exec/__init__.py +++ b/cdist/test/exec/__init__.py @@ -0,0 +1,7 @@ +from .local import * + + +if __name__ == "__main__": + import unittest + + unittest.main() diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index 1b298143..0e0cc755 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -61,6 +61,7 @@ class LocalTestCase(test.CdistTestCase): self.local = local.Local( target_host=target_host, + target_host_tags=None, base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=test.cdist_exec_path @@ -124,6 +125,7 @@ class LocalTestCase(test.CdistTestCase): 'localhost', 'localhost', ), + target_host_tags=None, base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, @@ -147,6 +149,7 @@ class LocalTestCase(test.CdistTestCase): 'localhost', 'localhost', ), + target_host_tags=None, base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, @@ -176,10 +179,11 @@ class LocalTestCase(test.CdistTestCase): 'localhost', 'localhost', ), + target_host_tags=None, base_root_path=self.host_base_path, host_dir_name=self.hostdir, exec_path=test.cdist_exec_path, - configuration=configuration + configuration=configuration.get_config(section='GLOBAL') ) link_test_local._create_conf_path_and_link_conf_dirs() @@ -191,24 +195,29 @@ class LocalTestCase(test.CdistTestCase): # other tests def test_run_success(self): + self.local.create_files_dirs() self.local.run([bin_true]) def test_run_fail(self): + self.local.create_files_dirs() self.assertRaises(cdist.Error, self.local.run, [bin_false]) def test_run_script_success(self): + self.local.create_files_dirs() handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", bin_true]) self.local.run_script(script) def test_run_script_fail(self): + self.local.create_files_dirs() handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", bin_false]) self.assertRaises(cdist.Error, self.local.run_script, script) def test_run_script_get_output(self): + self.local.create_files_dirs() handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", "echo foobar"]) diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 371d17e3..723d6ddd 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -22,8 +22,6 @@ import os import getpass import shutil -import string -import random import multiprocessing import cdist @@ -40,7 +38,8 @@ class RemoteTestCase(test.CdistTestCase): 'localhost', 'localhost', ) - self.base_path = self.temp_dir + # another temp dir for remote base path + self.base_path = self.mkdtemp() user = getpass.getuser() remote_exec = "ssh -o User=%s -q" % user remote_copy = "scp -o User=%s -q" % user @@ -113,7 +112,8 @@ class RemoteTestCase(test.CdistTestCase): os.close(handle) target = self.mkdtemp(dir=self.temp_dir) self.remote.transfer(source, target) - self.assertTrue(os.path.isfile(target)) + self.assertTrue(os.path.isfile( + os.path.join(target, os.path.basename(source)))) def test_transfer_dir(self): source = self.mkdtemp(dir=self.temp_dir) @@ -206,6 +206,7 @@ class RemoteTestCase(test.CdistTestCase): output = r.run_script(script, env=env, return_output=True) self.assertEqual(output, "test_object\n") + if __name__ == '__main__': import unittest From 1ae5b1732edbc63d449c61c889715e2f40b6518a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 10 Sep 2017 23:08:21 +0200 Subject: [PATCH 0649/1332] Fix missing dirs cleanup. --- cdist/config.py | 4 ++++ cdist/exec/local.py | 1 - cdist/test/exec/remote.py | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index e33a6027..ed69e3e4 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -260,6 +260,10 @@ class Config(object): if len(failed_hosts) > 0: raise cdist.Error("Failed to configure the following hosts: " + " ".join(failed_hosts)) + elif not args.out_path: + # If tmp out path created then remove it, but only if no failed + # hosts. + shutil.rmtree(base_root_path) @classmethod def _resolve_ssh_control_path(cls): diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 468deb4a..9f37bde2 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -79,7 +79,6 @@ class Local(object): self._init_log() self._init_permissions() self.mkdir(self.base_path) - # FIXME: create dir that does not require moving later self._init_cache_dir(None) self._init_paths() self._init_object_marker() diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 723d6ddd..5137c59c 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -49,6 +49,7 @@ class RemoteTestCase(test.CdistTestCase): def tearDown(self): shutil.rmtree(self.temp_dir) + shutil.rmtree(self.base_path) # test api From f0dc21ec0c72aeec58dc0f47edf74d4ca223f03d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 11 Sep 2017 09:06:47 +0200 Subject: [PATCH 0650/1332] __cdist_log_level=; __cdist_log_level_name= (#574) --- .../conf/type/__install_stage/gencode-remote | 18 +++--- cdist/configuration.py | 29 +++++++++- cdist/core/__init__.py | 2 +- cdist/core/code.py | 2 + cdist/core/explorer.py | 2 + cdist/core/manifest.py | 2 + cdist/core/util.py | 4 ++ cdist/emulator.py | 3 +- cdist/test/code/__init__.py | 8 ++- .../type/__dump_environment/gencode-local | 1 + cdist/test/configuration/__init__.py | 55 +++++++++++++++++-- cdist/test/emulator/__init__.py | 2 +- cdist/test/explorer/__init__.py | 5 +- .../conf/type/__dump_env/explorer/dump | 1 + cdist/test/manifest/__init__.py | 13 ++++- .../fixtures/conf/manifest/dump_environment | 1 + .../conf/type/__dump_environment/manifest | 1 + docs/changelog | 11 ++-- docs/src/cdist-reference.rst.sh | 47 ++++++++++++++-- docs/src/cdist-type.rst | 25 ++++++++- 20 files changed, 192 insertions(+), 40 deletions(-) diff --git a/cdist/conf/type/__install_stage/gencode-remote b/cdist/conf/type/__install_stage/gencode-remote index 4d013e3d..776e9fd5 100755 --- a/cdist/conf/type/__install_stage/gencode-remote +++ b/cdist/conf/type/__install_stage/gencode-remote @@ -22,16 +22,14 @@ uri="$(cat "$__object/parameter/uri" 2>/dev/null \ || echo "$__object_id")" target="$(cat "$__object/parameter/target")" -case "$__cdist_log_level" in - DEBUG|TRACE) - curl="curl" - tar="tar -xvzp" - ;; - *) - curl="curl -s" - tar="tar -xzp" - ;; -esac +if [ "$__cdist_log_level" -le "10" ] +then + curl="curl" + tar="tar -xvzp" +else + curl="curl -s" + tar="tar -xzp" +fi if [ -f "$__object/parameter/insecure" ] ; then curl="$curl -k" diff --git a/cdist/configuration.py b/cdist/configuration.py index 30176200..4a8274d8 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -26,6 +26,7 @@ import cdist import cdist.argparse import re import multiprocessing +import logging class Singleton(type): @@ -215,6 +216,24 @@ class ArchivingOption(SelectOption): return val +class LogLevelOption(OptionBase): + def __init__(self): + super().__init__('__cdist_log_level') + + def converter(self): + def log_level_converter(val): + try: + val = logging.getLevelName(int(val)) + return self.translate(val) + except (ValueError, AttributeError): + raise ValueError("Invalid {} value: {}.".format( + self.name, val)) + return log_level_converter + + def translate(self, val): + return VerbosityOption().translate(val) + + _ARG_OPTION_MAPPING = { 'beta': 'beta', 'cache_path_pattern': 'cache_path_pattern', @@ -281,6 +300,9 @@ class Configuration(metaclass=Singleton): '__cdist_log_level': 'verbosity', } ENV_VAR_BOOLEAN_OPTIONS = ('CDIST_BETA', ) + ENV_VAR_OPTIONS = { + '__cdist_log_level': LogLevelOption(), + } ARG_OPTION_MAPPING = _ARG_OPTION_MAPPING ADJUST_ARG_OPTION_MAPPING = { @@ -366,8 +388,11 @@ class Configuration(metaclass=Singleton): if option in self.ENV_VAR_BOOLEAN_OPTIONS: d[dst_opt] = True else: - option_object = self.CONFIG_FILE_OPTIONS[section][dst_opt] - converter = option_object.converter() + if option in self.ENV_VAR_OPTIONS: + opt = self.ENV_VAR_OPTIONS[option] + else: + opt = self.CONFIG_FILE_OPTIONS[section][dst_opt] + converter = opt.converter() val = env[option] newval = converter(val) d[dst_opt] = newval diff --git a/cdist/core/__init__.py b/cdist/core/__init__.py index adec60b2..179c1a29 100644 --- a/cdist/core/__init__.py +++ b/cdist/core/__init__.py @@ -28,4 +28,4 @@ from cdist.core.explorer import Explorer from cdist.core.manifest import Manifest from cdist.core.code import Code from cdist.core.util import listdir -from cdist.core.util import log_level_env_var_val +from cdist.core.util import log_level_env_var_val, log_level_name_env_var_val diff --git a/cdist/core/code.py b/cdist/core/code.py index 5ada4c14..ad02e199 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -109,6 +109,8 @@ class Code(object): '__files': self.local.files_path, '__target_host_tags': self.local.target_host_tags, '__cdist_log_level': util.log_level_env_var_val(local.log), + '__cdist_log_level_name': util.log_level_name_env_var_val( + local.log), } def _run_gencode(self, cdist_object, which): diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 8d7cd593..c4708eac 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -80,6 +80,8 @@ class Explorer(object): '__explorer': self.remote.global_explorer_path, '__target_host_tags': self.local.target_host_tags, '__cdist_log_level': util.log_level_env_var_val(self.log), + '__cdist_log_level_name': util.log_level_name_env_var_val( + self.log), } self._type_explorers_transferred = [] self.jobs = jobs diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index e69db63f..82e9f780 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -113,6 +113,8 @@ class Manifest(object): '__files': self.local.files_path, '__target_host_tags': self.local.target_host_tags, '__cdist_log_level': util.log_level_env_var_val(self.log), + '__cdist_log_level_name': util.log_level_name_env_var_val( + self.log), } def _open_logger(self): diff --git a/cdist/core/util.py b/cdist/core/util.py index cce608bc..64570d34 100644 --- a/cdist/core/util.py +++ b/cdist/core/util.py @@ -38,4 +38,8 @@ def _ishidden(path): def log_level_env_var_val(log): + return str(log.getEffectiveLevel()) + + +def log_level_name_env_var_val(log): return logging.getLevelName(log.getEffectiveLevel()) diff --git a/cdist/emulator.py b/cdist/emulator.py index 0655fe9c..40b19e4b 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -112,8 +112,7 @@ class Emulator(object): if '__cdist_log_level' in self.env: try: loglevel = self.env['__cdist_log_level'] - # For a text level it returns its numerical value. - level = logging.getLevelName(loglevel) + level = int(loglevel) except ValueError: level = logging.WARNING else: diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 4d0427aa..c1d19d33 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -101,7 +101,9 @@ class CodeTestCase(test.CdistTestCase): self.assertEqual(output_dict['__files'], self.local.files_path) self.assertEqual(output_dict['__target_host_tags'], self.local.target_host_tags) - self.assertEqual(output_dict['__cdist_log_level'], 'WARNING') + self.assertEqual(output_dict['__cdist_log_level'], + str(logging.WARNING)) + self.assertEqual(output_dict['__cdist_log_level_name'], 'WARNING') def test_run_gencode_remote_environment(self): output_string = self.code.run_gencode_remote(self.cdist_object) @@ -127,7 +129,9 @@ class CodeTestCase(test.CdistTestCase): self.assertEqual(output_dict['__files'], self.local.files_path) self.assertEqual(output_dict['__target_host_tags'], self.local.target_host_tags) - self.assertEqual(output_dict['__cdist_log_level'], 'WARNING') + self.assertEqual(output_dict['__cdist_log_level'], + str(logging.WARNING)) + self.assertEqual(output_dict['__cdist_log_level_name'], 'WARNING') def test_transfer_code_remote(self): self.cdist_object.code_remote = self.code.run_gencode_remote( diff --git a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local index 35120f10..2829d633 100755 --- a/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local +++ b/cdist/test/code/fixtures/conf/type/__dump_environment/gencode-local @@ -11,3 +11,4 @@ echo "echo __object_name: $__object_name" echo "echo __files: $__files" echo "echo __target_host_tags: $__target_host_tags" echo "echo __cdist_log_level: $__cdist_log_level" +echo "echo __cdist_log_level_name: $__cdist_log_level_name" diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index 3630fb95..c6135317 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -27,7 +27,7 @@ import os.path as op import argparse from cdist import test import cdist.argparse as cap - +import logging my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') @@ -124,6 +124,18 @@ class ConfigurationOptionsTestCase(test.CdistTestCase): self.assertEqual(converter(value), ['spam', 'eggs', 'ham', ]) self.assertIsNone(converter('')) + def test_LogLevelOption(self): + option = cc.LogLevelOption() + converter = option.converter() + value = str(logging.DEBUG) + conv_val = converter(value) + self.assertEqual(conv_val, cap.VERBOSE_DEBUG) + value = str(logging.INFO) + conv_val = converter(value) + self.assertEqual(conv_val, cap.VERBOSE_INFO) + for value in ('11', '80', 'a'): + self.assertRaises(ValueError, converter, value) + class ConfigurationTestCase(test.CdistTestCase): @@ -234,17 +246,17 @@ class ConfigurationTestCase(test.CdistTestCase): os.remove(custom_config_file) def test_singleton(self): - x = cc.Configuration(None) + x = cc.Configuration(None, env={}, config_files=()) args = argparse.Namespace() args.a = 'a' - y = cc.Configuration(args) + y = cc.Configuration(args, env={}, config_files=()) self.assertIs(x, y) def test_non_singleton(self): - x = cc.Configuration(None, singleton=False) + x = cc.Configuration(None, env={}, config_files=(), singleton=False) args = argparse.Namespace() args.a = 'a' - y = cc.Configuration(args, singleton=False) + y = cc.Configuration(args, env={}, config_files=(), singleton=False) self.assertIsNot(x, y) def test_read_config_file(self): @@ -1122,6 +1134,39 @@ class ConfigurationTestCase(test.CdistTestCase): config_files=config_files) self.assertEqual(configuration.config, expected_config_dict) + def test_configuration_cdist_log_level_env_var(self): + env = { + '__cdist_log_level': str(logging.DEBUG), + } + args = argparse.Namespace() + + expected_config_dict = { + 'GLOBAL': { + 'verbosity': cap.VERBOSE_DEBUG, + }, + } + + # bypass singleton so we can test further + cc.Configuration.instance = None + + configuration = cc.Configuration(args, env=env, + config_files=()) + self.assertEqual(configuration.config, expected_config_dict) + + # bypass singleton so we can test further + cc.Configuration.instance = None + env['__cdist_log_level'] = '80' + with self.assertRaises(ValueError): + configuration = cc.Configuration(args, env=env, + config_files=()) + + # bypass singleton so we can test further + cc.Configuration.instance = None + env['__cdist_log_level'] = 'x' + with self.assertRaises(ValueError): + configuration = cc.Configuration(args, env=env, + config_files=()) + if __name__ == "__main__": import unittest diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 48c5362e..6bc80e96 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -124,7 +124,7 @@ class EmulatorTestCase(test.CdistTestCase): emu = emulator.Emulator(argv, env=self.env) emu_loglevel = emu.log.getEffectiveLevel() self.assertEqual(emu_loglevel, logging.WARNING) - self.env['__cdist_log_level'] = logging.getLevelName(logging.DEBUG) + self.env['__cdist_log_level'] = str(logging.DEBUG) emu = emulator.Emulator(argv, env=self.env) emu_loglevel = emu.log.getEffectiveLevel() self.assertEqual(emu_loglevel, logging.DEBUG) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index 48b54cd7..dcdd91f1 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -31,6 +31,7 @@ from cdist import test from cdist.exec import local from cdist.exec import remote from cdist.core import explorer +import logging import os.path as op my_dir = op.abspath(op.dirname(__file__)) @@ -233,7 +234,9 @@ class ExplorerClassTestCase(test.CdistTestCase): self.remote.global_explorer_path) self.assertEqual(output_dict['__target_host_tags'], self.local.target_host_tags) - self.assertEqual(output_dict['__cdist_log_level'], 'WARNING') + self.assertEqual(output_dict['__cdist_log_level'], + str(logging.WARNING)) + self.assertEqual(output_dict['__cdist_log_level_name'], 'WARNING') if __name__ == '__main__': diff --git a/cdist/test/explorer/fixtures/conf/type/__dump_env/explorer/dump b/cdist/test/explorer/fixtures/conf/type/__dump_env/explorer/dump index ae477cd0..3682816b 100755 --- a/cdist/test/explorer/fixtures/conf/type/__dump_env/explorer/dump +++ b/cdist/test/explorer/fixtures/conf/type/__dump_env/explorer/dump @@ -6,3 +6,4 @@ echo "__target_fqdn: $__target_fqdn" echo "__explorer: $__explorer" echo "__target_host_tags: $__target_host_tags" echo "__cdist_log_level: $__cdist_log_level" +echo "__cdist_log_level_name: $__cdist_log_level_name" diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index 5b372f35..fffa77b8 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -99,7 +99,9 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__files'], self.local.files_path) self.assertEqual(output_dict['__target_host_tags'], self.local.target_host_tags) - self.assertEqual(output_dict['__cdist_log_level'], 'VERBOSE') + self.assertEqual(output_dict['__cdist_log_level'], + str(logging.VERBOSE)) + self.assertEqual(output_dict['__cdist_log_level_name'], 'VERBOSE') self.log.setLevel(old_loglevel) def test_type_manifest_environment(self): @@ -139,7 +141,9 @@ class ManifestTestCase(test.CdistTestCase): self.assertEqual(output_dict['__files'], self.local.files_path) self.assertEqual(output_dict['__target_host_tags'], self.local.target_host_tags) - self.assertEqual(output_dict['__cdist_log_level'], 'VERBOSE') + self.assertEqual(output_dict['__cdist_log_level'], + str(logging.VERBOSE)) + self.assertEqual(output_dict['__cdist_log_level_name'], 'VERBOSE') self.log.setLevel(old_loglevel) def test_loglevel_env_setup(self): @@ -147,7 +151,10 @@ class ManifestTestCase(test.CdistTestCase): self.log.setLevel(logging.DEBUG) manifest = cdist.core.manifest.Manifest(self.target_host, self.local) self.assertTrue("__cdist_log_level" in manifest.env) - self.assertEqual(manifest.env["__cdist_log_level"], 'DEBUG') + self.assertTrue("__cdist_log_level_name" in manifest.env) + self.assertEqual(manifest.env["__cdist_log_level"], + str(logging.DEBUG)) + self.assertEqual(manifest.env["__cdist_log_level_name"], 'DEBUG') self.log.setLevel(current_level) diff --git a/cdist/test/manifest/fixtures/conf/manifest/dump_environment b/cdist/test/manifest/fixtures/conf/manifest/dump_environment index adf3c3e0..8057ca42 100755 --- a/cdist/test/manifest/fixtures/conf/manifest/dump_environment +++ b/cdist/test/manifest/fixtures/conf/manifest/dump_environment @@ -11,4 +11,5 @@ __manifest: $__manifest __files: $__files __target_host_tags: $__target_host_tags __cdist_log_level: $__cdist_log_level +__cdist_log_level_name: $__cdist_log_level_name DONE diff --git a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest index f2ae74e2..a38050f9 100755 --- a/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest +++ b/cdist/test/manifest/fixtures/conf/type/__dump_environment/manifest @@ -15,4 +15,5 @@ __object_name: $__object_name __files: $__files __target_host_tags: $__target_host_tags __cdist_log_level: $__cdist_log_level +__cdist_log_level_name: $__cdist_log_level_name DONE diff --git a/docs/changelog b/docs/changelog index 9ca5e2f2..ddf4a685 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,12 +10,13 @@ next: * Type __daemontools: Improve it on FreeBSD (Kamila Součková) * Type __package_pkg_openbsd: Fix use of --name (Philippe Gregoire) * Type __package_pkg_openbsd: Fix pkg_version explorer (Philippe Gregoire) - * Documentation: Document __cdist_loglevel type variable (Darko Poljak) - * Type __install_stage: Fix __debug -> __cdist_loglevel (Darko Poljak) - * Core, types: Make __cdist_loglevel value more expressive (Darko Poljak) - * Core: Add -l/--log-level option (Darko Poljak) - * Core: __cdist_loglevel -> __cdist_log_level and make cdist honor __cdist_log_level env var (Darko Poljak) * Type __prometheus_exporter: Fixes + go version bump (Kamila Součková) + * Core, types: __cdist_loglevel -> __cdist_log_level (Darko Poljak) + * Core, types: Add __cdist_log_level_name env var with vlaue of log level name (Darko Poljak) + * Core: Make cdist honor __cdist_log_level env var (Darko Poljak) + * Core: Add -l/--log-level option (Darko Poljak) + * Type __install_stage: Fix __debug -> __cdist_log_level (Darko Poljak) + * Documentation: Document __cdist_log_level (Darko Poljak) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index ec3216c2..59ce018b 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -198,9 +198,27 @@ Environment variables (for reading) ----------------------------------- The following environment variables are exported by cdist: -__cdist_log_level - String value of cdist log level. One of OFF, ERROR, WARNING, INFO, - VERBOSE, DEBUG and TRACE. +__cdist_log_level, __cdist_log_level_name + cdist log level value and cdist log level name. One of: + + +----------------+-----------------+ + | Log level name | Log level value | + +================+=================+ + | OFF | 60 | + +----------------+-----------------+ + | ERROR | 40 | + +----------------+-----------------+ + | WARNING | 30 | + +----------------+-----------------+ + | INFO | 20 | + +----------------+-----------------+ + | VERBOSE | 15 | + +----------------+-----------------+ + | DEBUG | 10 | + +----------------+-----------------+ + | TRACE | 5 | + +----------------+-----------------+ + Available for: initial manifest, explorer, type manifest, type explorer, type gencode. __explorer @@ -266,8 +284,27 @@ require Setup dependencies between objects (see \`cdist manifest \`_). __cdist_log_level - String value of cdist log level. One of OFF, ERROR, WARNING, INFO, - VERBOSE, DEBUG and TRACE. If set cdist will set this log level in + cdist log level value. One of: + + +----------------+-----------------+ + | Log level | Log level value | + +================+=================+ + | OFF | 60 | + +----------------+-----------------+ + | ERROR | 40 | + +----------------+-----------------+ + | WARNING | 30 | + +----------------+-----------------+ + | INFO | 20 | + +----------------+-----------------+ + | VERBOSE | 15 | + +----------------+-----------------+ + | DEBUG | 10 | + +----------------+-----------------+ + | TRACE | 5 | + +----------------+-----------------+ + + If set cdist will set this log level in accordance with configuration rules. If cdist invokation is used in types then nested cdist will honor this specified log level if not specified otherwise while invoking it. diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index dbecc409..a6587328 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -333,9 +333,28 @@ So when you generate a script with the following content, it will work: Log level in types ------------------ -cdist log level can be accessed from __cdist_log_level variable. -Value is a string, one of OFF, ERROR, WARNING, INFO, VERBOSE, DEBUG and -TRACE. It is available for initial manifest, explorer, type manifest, +cdist log level can be accessed from __cdist_log_level variable.One of: + + +----------------+-----------------+ + | Log level | Log level value | + +================+=================+ + | OFF | 60 | + +----------------+-----------------+ + | ERROR | 40 | + +----------------+-----------------+ + | WARNING | 30 | + +----------------+-----------------+ + | INFO | 20 | + +----------------+-----------------+ + | VERBOSE | 15 | + +----------------+-----------------+ + | DEBUG | 10 | + +----------------+-----------------+ + | TRACE | 5 | + +----------------+-----------------+ + + +It is available for initial manifest, explorer, type manifest, type explorer, type gencode. From f2614469c5ef9137ca1891d7393396409d275b06 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 11 Sep 2017 22:36:45 +0200 Subject: [PATCH 0651/1332] configuration: converter() -> get_converter() --- cdist/configuration.py | 22 +++++++++++----------- cdist/test/configuration/__init__.py | 14 +++++++------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cdist/configuration.py b/cdist/configuration.py index 4a8274d8..8600cb0c 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -53,7 +53,7 @@ class OptionBase: def __init__(self, name): self.name = name - def converter(self, *args, **kwargs): + def get_converter(self, *args, **kwargs): raise NotImplementedError('Subclass should implement this method') def translate(self, val): @@ -83,7 +83,7 @@ class StringOption(OptionBase): def __init__(self, name): super().__init__(name) - def converter(self): + def get_converter(self): def string_converter(val): return self.translate(str(val)) return string_converter @@ -101,7 +101,7 @@ class BooleanOption(OptionBase): def __init__(self, name): super().__init__(name) - def converter(self): + def get_converter(self): def boolean_converter(val): v = val.lower() if v not in self.BOOLEAN_STATES: @@ -118,7 +118,7 @@ class IntOption(OptionBase): def __init__(self, name): super().__init__(name) - def converter(self): + def get_converter(self): def int_converter(val): return self.translate(int(val)) return int_converter @@ -129,9 +129,9 @@ class LowerBoundIntOption(IntOption): super().__init__(name) self.lower_bound = lower_bound - def converter(self): + def get_converter(self): def lower_bound_converter(val): - converted = super(LowerBoundIntOption, self).converter()(val) + converted = super(LowerBoundIntOption, self).get_converter()(val) if converted < self.lower_bound: raise ValueError("Invalid {} value: {} < {}".format( self.name, val, self.lower_bound)) @@ -161,7 +161,7 @@ class SelectOption(OptionBase): super().__init__(name) self.valid_values = valid_values - def converter(self): + def get_converter(self): def select_converter(val): if val in self.valid_values: return self.translate(val) @@ -186,7 +186,7 @@ class DelimitedValuesOption(OptionBase): super().__init__(name) self.delimiter = delimiter - def converter(self): + def get_converter(self): def delimited_values_converter(val): vals = re.split(r'(? Date: Wed, 13 Sep 2017 13:06:06 +0200 Subject: [PATCH 0652/1332] Log ERROR to stderr and rest to stdout. (#576) --- cdist/config.py | 4 +--- cdist/log.py | 48 +++++++++++++++++++++++++++++++++++++++++++----- docs/changelog | 1 + 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index ed69e3e4..06db807a 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -148,9 +148,7 @@ class Config(object): if args.parallel or args.jobs: # If parallel execution then also log process id - del logging.getLogger().handlers[:] - log_format = '%(levelname)s: [%(process)d]: %(message)s' - logging.basicConfig(format=log_format) + cdist.log.setupParallelLogging() log = logging.getLogger("cdist") if args.parallel: diff --git a/cdist/log.py b/cdist/log.py index ce0addcc..dba1ad2f 100644 --- a/cdist/log.py +++ b/cdist/log.py @@ -21,6 +21,7 @@ # import logging +import sys # Define additional cdist logging levels. @@ -48,14 +49,38 @@ def _trace(msg, *args, **kwargs): logging.trace = _trace -class Log(logging.Logger): +class DefaultLog(logging.Logger): + + FORMAT = '%(levelname)s: %(message)s' + + class StdoutFilter(logging.Filter): + def filter(self, rec): + return rec.levelno != logging.ERROR + + class StderrFilter(logging.Filter): + def filter(self, rec): + return rec.levelno == logging.ERROR def __init__(self, name): - - self.name = name super().__init__(name) + + formatter = logging.Formatter(self.FORMAT) + self.addFilter(self) + stdout_handler = logging.StreamHandler(sys.stdout) + stdout_handler.addFilter(self.StdoutFilter()) + stdout_handler.setLevel(logging.TRACE) + stdout_handler.setFormatter(formatter) + + stderr_handler = logging.StreamHandler(sys.stderr) + stderr_handler.addFilter(self.StderrFilter()) + stderr_handler.setLevel(logging.ERROR) + stderr_handler.setFormatter(formatter) + + self.addHandler(stdout_handler) + self.addHandler(stderr_handler) + def filter(self, record): """Prefix messages with logger name""" @@ -70,5 +95,18 @@ class Log(logging.Logger): self.log(logging.TRACE, msg, *args, **kwargs) -logging.setLoggerClass(Log) -logging.basicConfig(format='%(levelname)s: %(message)s') +class ParallelLog(DefaultLog): + FORMAT = '%(levelname)s: [%(process)d]: %(message)s' + + +def setupDefaultLogging(): + del logging.getLogger().handlers[:] + logging.setLoggerClass(DefaultLog) + + +def setupParallelLogging(): + del logging.getLogger().handlers[:] + logging.setLoggerClass(ParallelLog) + + +setupDefaultLogging() diff --git a/docs/changelog b/docs/changelog index ddf4a685..1df6af21 100644 --- a/docs/changelog +++ b/docs/changelog @@ -17,6 +17,7 @@ next: * Core: Add -l/--log-level option (Darko Poljak) * Type __install_stage: Fix __debug -> __cdist_log_level (Darko Poljak) * Documentation: Document __cdist_log_level (Darko Poljak) + * Core: Log ERROR to stderr and rest to stdout (Darko Poljak, Steven Armstrong) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From 47d72fb83a2c9b01242566255dfb6e16ac1e0258 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 14 Sep 2017 09:27:27 +0200 Subject: [PATCH 0653/1332] Create control path only if needed. --- cdist/config.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index 06db807a..11da04da 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -272,7 +272,10 @@ class Config(object): @classmethod def _resolve_remote_cmds(cls, args): - control_path = cls._resolve_ssh_control_path() + if (args.remote_exec_pattern or + args.remote_copy_pattern or + args.remote_cmds_cleanup_pattern): + control_path = cls._resolve_ssh_control_path() # If we constructed patterns for remote commands then there is # placeholder for ssh ControlPath, format it and we have unique # ControlPath for each host. From ac04edc233c61b8b730ebc43fe3c63e78d8d4cc4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 14 Sep 2017 09:53:16 +0200 Subject: [PATCH 0654/1332] Change path removal suitable for integration and normal run. --- cdist/config.py | 19 ++++++++++++++++++- cdist/integration.py | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index 11da04da..f5c3121d 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -44,6 +44,22 @@ from cdist.util.remoteutil import inspect_ssh_mux_opts class Config(object): """Cdist main class to hold arbitrary data""" + # list of paths (files and/or directories) that will be removed on finish + _paths_for_removal = [] + + @classmethod + def _register_path_for_removal(cls, path): + cls._paths_for_removal.append(path) + + @classmethod + def _remove_paths(cls): + while cls._paths_for_removal: + path = cls._paths_for_removal.pop() + if os.path.isfile(path): + os.remove(path) + else: + shutil.rmtree(path) + def __init__(self, local, remote, dry_run=False, jobs=None, cleanup_cmds=None, remove_remote_files_dirs=False): @@ -266,8 +282,8 @@ class Config(object): @classmethod def _resolve_ssh_control_path(cls): base_path = tempfile.mkdtemp() + cls._register_path_for_removal(base_path) control_path = os.path.join(base_path, "s") - atexit.register(lambda: shutil.rmtree(base_path)) return control_path @classmethod @@ -345,6 +361,7 @@ class Config(object): cleanup_cmds=cleanup_cmds, remove_remote_files_dirs=remove_remote_files_dirs) c.run() + cls._remove_paths() except cdist.Error as e: log.error(e) diff --git a/cdist/integration.py b/cdist/integration.py index e2f9be6e..ee742cc5 100644 --- a/cdist/integration.py +++ b/cdist/integration.py @@ -36,6 +36,7 @@ import os import os.path import collections import uuid +import shutil def find_cdist_exec_in_path(): @@ -123,6 +124,7 @@ def _process_hosts_simple(action, host, manifest, verbose, theclass.onehost(target_host, None, host_base_path, hostdir, args, parallel=False, configuration=configuration, remove_remote_files_dirs=True) + shutil.rmtree(base_root_path) def configure_hosts_simple(host, manifest, From 8883196efbd5ffb7c021ca0ffed720a06cb9c876 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 17 Sep 2017 08:13:05 +0200 Subject: [PATCH 0655/1332] Bugfix for: __ssh_authorized_keys overwrites existing keys #577 (#579) * Fix a bug where invalid key removes all file entries. * __ssh_authorized_key: add key validation. --- cdist/conf/type/__ssh_authorized_key/explorer/entry | 11 ++++++++--- cdist/conf/type/__ssh_authorized_key/gencode-remote | 13 +++++++++++-- docs/changelog | 1 + 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__ssh_authorized_key/explorer/entry b/cdist/conf/type/__ssh_authorized_key/explorer/entry index 40ee0cb9..1535d348 100755 --- a/cdist/conf/type/__ssh_authorized_key/explorer/entry +++ b/cdist/conf/type/__ssh_authorized_key/explorer/entry @@ -20,7 +20,12 @@ # extract the keytype and base64 encoded key ignoring any options and comment type_and_key="$(cat "$__object/parameter/key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" -file="$(cat $__object/parameter/file)" +# If type_and_key is empty, which is the case with an invalid key, do not grep $file because it results +# in greping everything in file and all entries from file are removed. +if [ -n "${type_and_key}" ] +then + file="$(cat $__object/parameter/file)" -# get any entries that match the type and key -grep ".*$type_and_key\([ \n]\|$\)" "$file" || true + # get any entries that match the type and key + grep ".*$type_and_key\([ \n]\|$\)" "$file" || true +fi diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index ae53c2fe..0ce41ea6 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -20,6 +20,15 @@ set -u +the_key="$(cat "$__object/parameter/key")" +# validate key +validated_key="$(echo "${the_key}" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" +if [ -z "${validated_key}" ] +then + echo "Key is invalid: \"${the_key}\"" >&2 + exit 1 +fi + remove_line() { file="$1" line="$2" @@ -55,11 +64,11 @@ mkdir "$__object/files" fi if [ -f "$__object/parameter/comment" ]; then # extract the keytype and base64 encoded key ignoring any options and comment - printf '%s ' "$(cat "$__object/parameter/key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" + printf '%s ' "$(echo "${the_key}" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" # override the comment with the one explicitly given printf '%s' "$(cat "$__object/parameter/comment")" else - printf '%s' "$(cat "$__object/parameter/key")" + printf '%s' "${the_key}" fi printf '\n' ) > "$__object/files/should" diff --git a/docs/changelog b/docs/changelog index 1df6af21..6d193c67 100644 --- a/docs/changelog +++ b/docs/changelog @@ -18,6 +18,7 @@ next: * Type __install_stage: Fix __debug -> __cdist_log_level (Darko Poljak) * Documentation: Document __cdist_log_level (Darko Poljak) * Core: Log ERROR to stderr and rest to stdout (Darko Poljak, Steven Armstrong) + * Type __ssh_authorized_key: Bugfix the case where invalid key clears a file and add key validation (Darko Poljak) 4.6.1: 2017-08-30 * Type __user: Explore with /etc files (passwd, group, shadow) (Philippe Gregoire) From 764ea49904c84b76c8d5eb7775078fa9843350c8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 17 Sep 2017 20:30:07 +0200 Subject: [PATCH 0656/1332] Log more data. --- cdist/config.py | 3 ++- cdist/core/manifest.py | 3 ++- cdist/exec/local.py | 3 ++- cdist/exec/remote.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index f5c3121d..6ba3d0dc 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -331,7 +331,8 @@ class Config(object): host, remote_copy)) target_host = ipaddr.resolve_target_addresses(host) - log.debug("target_host: {}".format(target_host)) + log.debug("target_host for host \"{}\": {}".format( + host, target_host)) local = cdist.exec.local.Local( target_host=target_host, diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 82e9f780..fccd3a2f 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -179,7 +179,8 @@ class Manifest(object): cdist_object.cdist_type.manifest_path) message_prefix = cdist_object.name if os.path.isfile(type_manifest): - self.log.verbose("Running type manifest " + type_manifest) + self.log.verbose("Running type manifest %s for object %s", + type_manifest, cdist_object.name) self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object), message_prefix=message_prefix, diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 9f37bde2..e5771076 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -232,7 +232,8 @@ class Local(object): if save_output: output, errout = exec_util.call_get_output( command, env=env, stderr=stderr) - self.log.trace("Local stdout: {}".format(output)) + self.log.trace("Command: {}; local stdout: {}".format( + command, output)) # Currently, stderr is not captured. # self.log.trace("Local stderr: {}".format(errout)) if return_output: diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index b834cd97..44bc2927 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -309,7 +309,8 @@ class Remote(object): stderr = None output, errout = exec_util.call_get_output( command, env=os_environ, stderr=stderr) - self.log.trace("Remote stdout: {}".format(output)) + self.log.trace("Command: {}; remote stdout: {}".format( + command, output)) # Currently, stderr is not captured. # self.log.trace("Remote stderr: {}".format(errout)) if return_output: From 21328337aeab787ec8d9f2176d5bb93e2ac6169b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 19 Sep 2017 12:07:15 +0200 Subject: [PATCH 0657/1332] Add missing dot. --- docs/src/cdist-configuration.rst | 2 +- docs/src/man1/cdist.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/cdist-configuration.rst b/docs/src/cdist-configuration.rst index 6a0e4a4f..0013973c 100644 --- a/docs/src/cdist-configuration.rst +++ b/docs/src/cdist-configuration.rst @@ -40,7 +40,7 @@ The possible keywords and their meanings are as follows: :strong:`beta` Enable beta functionality. It recognizes boolean values from - 'yes'/'no', 'on'/'off', 'true'/'false' and '1'/'0' + 'yes'/'no', 'on'/'off', 'true'/'false' and '1'/'0'. :strong:`cache_path_pattern` Specify cache path pattern. diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index c21b9996..b5333e17 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -513,7 +513,7 @@ The possible keywords and their meanings are as follows: :strong:`beta` Enable beta functionality. It recognizes boolean values from - 'yes'/'no', 'on'/'off', 'true'/'false' and '1'/'0' + 'yes'/'no', 'on'/'off', 'true'/'false' and '1'/'0'. :strong:`cache_path_pattern` Specify cache path pattern. From 0c4826ee974dc23739108af0772239bda9028ec9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 19 Sep 2017 13:52:49 +0200 Subject: [PATCH 0658/1332] Fix typo in conf_dir description: comma separated -> os.pathsep separated. --- configuration/cdist.cfg.skeleton | 4 +++- docs/src/cdist-configuration.rst | 4 +++- docs/src/man1/cdist.rst | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/configuration/cdist.cfg.skeleton b/configuration/cdist.cfg.skeleton index 441f6154..22c1ccaf 100644 --- a/configuration/cdist.cfg.skeleton +++ b/configuration/cdist.cfg.skeleton @@ -14,7 +14,9 @@ # cache_path_pattern = %h # # conf_dir -# Comma separated list of configuration directories. +# List of configuration directories separated with the character conventionally +# used by the operating system to separate search path components (as in PATH), +# such as ':' for POSIX or ';' for Windows. # If also specified at command line then values from command line are # appended to this value. # conf_dir = : diff --git a/docs/src/cdist-configuration.rst b/docs/src/cdist-configuration.rst index 0013973c..e53c818f 100644 --- a/docs/src/cdist-configuration.rst +++ b/docs/src/cdist-configuration.rst @@ -46,7 +46,9 @@ The possible keywords and their meanings are as follows: Specify cache path pattern. :strong:`conf_dir` - Comma separated list of configuration directories. + List of configuration directories separated with the character conventionally + used by the operating system to separate search path components (as in PATH), + such as ':' for POSIX or ';' for Windows. If also specified at command line then values from command line are appended to this value. diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index b5333e17..3ca0cb8c 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -519,7 +519,9 @@ The possible keywords and their meanings are as follows: Specify cache path pattern. :strong:`conf_dir` - Comma separated list of configuration directories. + List of configuration directories separated with the character conventionally + used by the operating system to separate search path components (as in PATH), + such as ':' for POSIX or ';' for Windows. If also specified at command line then values from command line are appended to this value. From ea58cbd1716b815b9557f48a5d0ae8a7097fd5fd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Sep 2017 21:19:19 +0200 Subject: [PATCH 0659/1332] Better format command error output. --- cdist/exec/util.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cdist/exec/util.py b/cdist/exec/util.py index b71b9bcc..16b685cf 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -133,10 +133,16 @@ def handle_called_process_error(err, command): # "stdout: {}\n" # "stderr: {}").format( # err.returncode, err.output, errout)) - raise cdist.Error("Command failed: " + " ".join(command) + - (" with returncode: {}\n" - "stdout: {}").format( - err.returncode, err.output)) + if err.output: + output = err.output + '\n' + else: + output = '' + raise cdist.Error(("Command failed: '{}'\n" + "return code: {}\n" + "---- BEGIN stdout ----\n" + "{}" + "---- END stdout ----").format( + " ".join(command), err.returncode, output)) def _call_get_stdout(command, env=None, stderr=None): From 966bf30bee48646687a12597fbb67273303f3d8f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Sep 2017 21:53:05 +0200 Subject: [PATCH 0660/1332] Fix \n thing. --- cdist/exec/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/exec/util.py b/cdist/exec/util.py index 16b685cf..e3c090cc 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -134,13 +134,13 @@ def handle_called_process_error(err, command): # "stderr: {}").format( # err.returncode, err.output, errout)) if err.output: - output = err.output + '\n' + output = err.output else: output = '' raise cdist.Error(("Command failed: '{}'\n" "return code: {}\n" "---- BEGIN stdout ----\n" - "{}" + "{}" + ("\n" if output else "") + "---- END stdout ----").format( " ".join(command), err.returncode, output)) From a88710a36db842782bd9580abd820befe5bbd0e9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 22 Sep 2017 21:22:41 +0200 Subject: [PATCH 0661/1332] Release 4.7.0 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 6d193c67..79bd3a6b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.7.0: 2017-09-22 * Core: Add configuration/config file support (Darko Poljak) * Core: Implement simple integration API (unstable) (Darko Poljak) * Explorer machine_type: Detect kvm on proxmox (Sven Wick) From 6bd73237cffd5796e9f95d3f17db538bbb46ad16 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 27 Sep 2017 09:14:23 +0200 Subject: [PATCH 0662/1332] Bug/dotman docs fix (#581) * fix documentation for building custom man-pages from non-standard path --- docs/src/cdist-install.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst index f9feef36..afc50016 100644 --- a/docs/src/cdist-install.rst +++ b/docs/src/cdist-install.rst @@ -131,7 +131,10 @@ some other custom .cdist directory, e.g. /opt/cdist then use: .. code-block:: sh - DOT_CDIST_PATH=/opt/cdist make dotman + make DOT_CDIST_PATH=/opt/cdist dotman + +Note that `dotman`-target has to be built before a `make docs`-run, otherwise +the custom man-pages are not picked up. Python package ~~~~~~~~~~~~~~ From e5881301ad3857eddf82bb40831420893f7c0c6a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 27 Sep 2017 09:16:05 +0200 Subject: [PATCH 0663/1332] changelog++ --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 79bd3a6b..fea395cc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Documentation: Fix documentation for building custom man-pages from non-standard path (Thomas Eckert) + 4.7.0: 2017-09-22 * Core: Add configuration/config file support (Darko Poljak) * Core: Implement simple integration API (unstable) (Darko Poljak) From 7ee56d099f6fe7546a2e0b7093edec6756acde51 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 27 Sep 2017 12:19:07 +0200 Subject: [PATCH 0664/1332] resolved #444 add messaging to __line-type (#580) #444 Add messaging to __line-type --- cdist/conf/type/__line/gencode-remote | 6 ++++-- cdist/conf/type/__line/man.rst | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index b9f118b1..fa051951 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -60,6 +60,7 @@ case "$state_should" in # Only replace ' with '"'"' and keep \ as they are line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g") printf '%s' "printf '%s\n' '$line_sanitised' >> $file" + echo "added" >> "$__messages_out" ;; absent) @@ -83,9 +84,10 @@ fi grep -v $greparg '$regex' '$file' > \$tmpfile || true mv -f "\$tmpfile" "$file" eof + echo "removed" >> "$__messages_out" ;; *) - echo "Unknown state: $state_should" >&2 - exit 1 + echo "Unknown state: $state_should" >&2 + exit 1 ;; esac diff --git a/cdist/conf/type/__line/man.rst b/cdist/conf/type/__line/man.rst index e6adce9c..b63ea2b3 100644 --- a/cdist/conf/type/__line/man.rst +++ b/cdist/conf/type/__line/man.rst @@ -40,6 +40,13 @@ file If supplied, use this as the destination file. Otherwise the object_id is used. +MESSAGES +-------- +added + The line was added. + +removed + The line was removed. EXAMPLES -------- From 3198d8e76c8c789c01cb57af55c5c82edfe256b5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 27 Sep 2017 12:20:10 +0200 Subject: [PATCH 0665/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index fea395cc..a4764043 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Type __line: Add messaging (Thomas Eckert) * Documentation: Fix documentation for building custom man-pages from non-standard path (Thomas Eckert) 4.7.0: 2017-09-22 From 8b78001c9ed98b4bed17b49c9e9760f9cef44a86 Mon Sep 17 00:00:00 2001 From: Ander Punnar <4ND3R@users.noreply.github.com> Date: Fri, 29 Sep 2017 15:44:44 +0300 Subject: [PATCH 0666/1332] fix running scripts with execute bit (#583) --- cdist/exec/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index e5771076..8b54a142 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -264,7 +264,7 @@ class Local(object): """ if os.access(script, os.X_OK): self.log.debug('%s is executable, running it', script) - command = [script] + command = [os.path.realpath(script)] else: command = [self.configuration.get('local_shell', "/bin/sh"), "-e"] self.log.debug('%s is NOT executable, running it with %s', From 07581e7231f0a3f658c793e5b55dbbe91326ab8c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 29 Sep 2017 14:47:32 +0200 Subject: [PATCH 0667/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index a4764043..9ef9fc21 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __line: Add messaging (Thomas Eckert) * Documentation: Fix documentation for building custom man-pages from non-standard path (Thomas Eckert) + * Core: Fix running scripts with execute bit when name without path is specified (Ander Punnar) 4.7.0: 2017-09-22 * Core: Add configuration/config file support (Darko Poljak) From d1c3e2420f56a147af05b80aad4257d2f9141ef1 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Fri, 29 Sep 2017 14:48:51 +0200 Subject: [PATCH 0668/1332] Add messaging to __process --- cdist/conf/type/__process/gencode-remote | 9 ++++++--- cdist/conf/type/__process/man.rst | 12 +++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote index 1a606f5d..fc491321 100755 --- a/cdist/conf/type/__process/gencode-remote +++ b/cdist/conf/type/__process/gencode-remote @@ -2,6 +2,7 @@ # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2017 Thomas Eckert (tom at it-eckert.de) # # This file is part of cdist. # @@ -45,13 +46,15 @@ case "$state_should" in else echo "$name" fi + echo "started" >> "$__messages_out" ;; absent) - if [ -f "$__object/parameter/stop" ]; then + if [ -f "$__object/parameter/stop" ]; then cat "$__object/parameter/stop" - else + else echo kill "${runs}" - fi + fi + echo "stopped" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__process/man.rst b/cdist/conf/type/__process/man.rst index e439f37c..e7303c55 100644 --- a/cdist/conf/type/__process/man.rst +++ b/cdist/conf/type/__process/man.rst @@ -30,6 +30,15 @@ start Executable to use for starting the process. +MESSAGES +-------- +started + The process was started. + +stopped + The process was stopped. + + EXAMPLES -------- @@ -63,7 +72,8 @@ SEE ALSO AUTHORS ------- -Nico Schottelius +| Nico Schottelius +| Thomas Eckert COPYING From c5f47a017fb290b0d10210d4b07ef8a6e19ed7a9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 29 Sep 2017 14:49:31 +0200 Subject: [PATCH 0669/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 9ef9fc21..690267e9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __line: Add messaging (Thomas Eckert) * Documentation: Fix documentation for building custom man-pages from non-standard path (Thomas Eckert) * Core: Fix running scripts with execute bit when name without path is specified (Ander Punnar) + * Type __process: Add messaging (Thomas Eckert) 4.7.0: 2017-09-22 * Core: Add configuration/config file support (Darko Poljak) From 9fed32e373eb7bcc8ae0dab197bbd7088bffa777 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 1 Oct 2017 11:12:24 +0200 Subject: [PATCH 0670/1332] Release 4.7.1 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 690267e9..034aaaf9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.7.1: 2017-10-01 * Type __line: Add messaging (Thomas Eckert) * Documentation: Fix documentation for building custom man-pages from non-standard path (Thomas Eckert) * Core: Fix running scripts with execute bit when name without path is specified (Ander Punnar) From 5c4cda589c1afa07b0f896f05c0f1cf7c0488a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Thu, 19 Oct 2017 19:58:25 +0200 Subject: [PATCH 0671/1332] Add support for CoreOS to __hostname type (#586) --- cdist/conf/type/__hostname/gencode-remote | 4 ++-- cdist/conf/type/__hostname/manifest | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index f5b09da2..dbffad61 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -35,7 +35,7 @@ has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") # If everything is ok -> exit # case "$os" in - archlinux|debian|suse|ubuntu|devuan) + archlinux|debian|suse|ubuntu|devuan|coreos) if [ "$name_config" = "$name_should" -a "$name_running" = "$name_should" ]; then exit 0 fi @@ -58,7 +58,7 @@ echo changed >> "$__messages_out" # Use the good old way to set the hostname even on machines running systemd. case "$os" in - archlinux|debian|ubuntu|devuan|centos) + archlinux|debian|ubuntu|devuan|centos|coreos) echo "printf '%s\n' '$name_should' > /etc/hostname" echo "hostname -F /etc/hostname" ;; diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 21c2adc6..4836c501 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -41,7 +41,7 @@ not_supported() { } case "$os" in - archlinux|debian|suse|ubuntu|devuan) + archlinux|debian|suse|ubuntu|devuan|coreos) # handled in gencode-remote : ;; From 36302f7541997b579f6a8a2604d8ef12ae2a5e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Thu, 19 Oct 2017 19:58:34 +0200 Subject: [PATCH 0672/1332] Add support for CoreOS to __timezone type (#587) --- cdist/conf/type/__timezone/gencode-remote | 2 +- cdist/conf/type/__timezone/manifest | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__timezone/gencode-remote b/cdist/conf/type/__timezone/gencode-remote index e512f861..1f3f0196 100755 --- a/cdist/conf/type/__timezone/gencode-remote +++ b/cdist/conf/type/__timezone/gencode-remote @@ -29,7 +29,7 @@ if [ "$timezone_is" = "$timezone_should" ]; then fi case "$os" in - ubuntu|debian|devuan) + ubuntu|debian|devuan|coreos) echo "echo \"$timezone_should\" > /etc/timezone" ;; esac diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index 178a9ded..a20f5d32 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -34,7 +34,7 @@ case "$os" in __package timezone export require="__package/timezone" ;; - freebsd|netbsd) + freebsd|netbsd|coreos) # whitelist : ;; From a4be44b313eef383690f50d51030391fe8687ae9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 19 Oct 2017 19:58:49 +0200 Subject: [PATCH 0673/1332] changelog++ --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index 034aaaf9..94a136e5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,10 @@ Changelog --------- +next: + * Type __hostname: Add support for CoreOS (Ľubomír Kučera) + * Type __timezone: Add support for CoreOS (Ľubomír Kučera) + 4.7.1: 2017-10-01 * Type __line: Add messaging (Thomas Eckert) * Documentation: Fix documentation for building custom man-pages from non-standard path (Thomas Eckert) From da8f6efafcf30de54e6e519ee879cabe48d0fc22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Fri, 20 Oct 2017 18:16:06 +0200 Subject: [PATCH 0674/1332] fix explorer/os for devuan ascii (#588) --- cdist/conf/explorer/os | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index d1f3ccb4..d522300c 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -51,15 +51,17 @@ if grep -q ^DISTRIB_ID=Ubuntu /etc/lsb-release 2>/dev/null; then exit 0 fi +# devuan ascii has both devuan_version and debian_version, so we need to check devuan_version first! +if [ -f /etc/devuan_version ]; then + echo devuan + exit 0 +fi + if [ -f /etc/debian_version ]; then echo debian exit 0 fi -if [ -f /etc/devuan_version ]; then - echo devuan - exit 0 -fi ### if [ -f /etc/gentoo-release ]; then From d68ab24fe3c5878969f3a02d96a06cac4fa3b353 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 20 Oct 2017 19:21:18 +0200 Subject: [PATCH 0675/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 94a136e5..6237dfd7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __hostname: Add support for CoreOS (Ľubomír Kučera) * Type __timezone: Add support for CoreOS (Ľubomír Kučera) + * Explorer os: Fix for devuan ascii (Kamila Součková) 4.7.1: 2017-10-01 * Type __line: Add messaging (Thomas Eckert) From f767ec04ec46bcceb0a706906136dfaffc3398f8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 22 Oct 2017 16:17:57 +0200 Subject: [PATCH 0676/1332] Release 4.7.2 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 6237dfd7..b7ac1e13 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.7.2: 2017-10-22 * Type __hostname: Add support for CoreOS (Ľubomír Kučera) * Type __timezone: Add support for CoreOS (Ľubomír Kučera) * Explorer os: Fix for devuan ascii (Kamila Součková) From 2cd006de79c74caa5457ec0612f3a8ddc53ac792 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Sun, 29 Oct 2017 17:23:35 +0100 Subject: [PATCH 0677/1332] F/ccollect create destination (#548) --- cdist/conf/type/__ccollect_source/man.rst | 9 +++++++++ cdist/conf/type/__ccollect_source/manifest | 4 ++++ cdist/conf/type/__ccollect_source/parameter/boolean | 1 + 3 files changed, 14 insertions(+) diff --git a/cdist/conf/type/__ccollect_source/man.rst b/cdist/conf/type/__ccollect_source/man.rst index 617571bb..b0c23482 100644 --- a/cdist/conf/type/__ccollect_source/man.rst +++ b/cdist/conf/type/__ccollect_source/man.rst @@ -38,6 +38,8 @@ BOOLEAN PARAMETERS verbose Whether to report backup verbosely +create-destination + Create the directory specified in the destination parameter on the remote host EXAMPLES -------- @@ -50,6 +52,13 @@ EXAMPLES --exclude '/proc/*' --exclude '/sys/*' \ --verbose + __ccollect_source doc.ungleich.ch \ + --source doc.ungleich.ch:/ \ + --destination /backup/doc.ungleich.ch \ + --exclude '/proc/*' --exclude '/sys/*' \ + --verbose \ + --create-destination + SEE ALSO -------- diff --git a/cdist/conf/type/__ccollect_source/manifest b/cdist/conf/type/__ccollect_source/manifest index 22326d7b..238c7e76 100755 --- a/cdist/conf/type/__ccollect_source/manifest +++ b/cdist/conf/type/__ccollect_source/manifest @@ -53,3 +53,7 @@ if [ -f "$__object/parameter/exclude" ]; then __file "$exclude_file" --source - --state "$state" \ < "$__object/parameter/exclude" fi + +if [ -f "$__object/parameter/create-destination" ]; then + __directory "${destination}" --parents --state ${state} +fi diff --git a/cdist/conf/type/__ccollect_source/parameter/boolean b/cdist/conf/type/__ccollect_source/parameter/boolean index c00ee94a..434c644f 100644 --- a/cdist/conf/type/__ccollect_source/parameter/boolean +++ b/cdist/conf/type/__ccollect_source/parameter/boolean @@ -1 +1,2 @@ verbose +create-destination From f6745c0eda5142fcf2ddae624cc209d44a974d0e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 29 Oct 2017 18:33:24 +0100 Subject: [PATCH 0678/1332] changelog++ --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index b7ac1e13..8157e98e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __ccollect_source: Add create destination parameter (Dominique Roux) + 4.7.2: 2017-10-22 * Type __hostname: Add support for CoreOS (Ľubomír Kučera) * Type __timezone: Add support for CoreOS (Ľubomír Kučera) From 5eb478da956ca37a0332e2e1c32f6806f927b654 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 31 Oct 2017 07:56:25 +0100 Subject: [PATCH 0679/1332] Add messaging to __ssh_authorized_key. (#590) --- cdist/conf/type/__ssh_authorized_key/gencode-remote | 2 ++ cdist/conf/type/__ssh_authorized_key/man.rst | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index 0ce41ea6..7ded7dc6 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -111,8 +111,10 @@ fi case "$state_should" in present) add_line "$file" "$entry" + echo "added to $file ($entry)" >> "$__messages_out" ;; absent) remove_line "$file" "$entry" + echo "removed from $file ($entry)" >> "$__messages_out" ;; esac diff --git a/cdist/conf/type/__ssh_authorized_key/man.rst b/cdist/conf/type/__ssh_authorized_key/man.rst index b58ad879..087a3dae 100644 --- a/cdist/conf/type/__ssh_authorized_key/man.rst +++ b/cdist/conf/type/__ssh_authorized_key/man.rst @@ -36,6 +36,15 @@ state if the given keys should be 'present' or 'absent', defaults to 'present'. +MESSAGES +-------- +added to `file` (`entry`) + The key `entry` (with optional comment) was added to `file`. + +removed from `file` (`entry`) + The key `entry` (with optional comment) was removed from `file`. + + EXAMPLES -------- From 1ed43c345bc1306901dd98f08e56fb037883307a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 31 Oct 2017 07:56:45 +0100 Subject: [PATCH 0680/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8157e98e..7a739ab3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Type __ccollect_source: Add create destination parameter (Dominique Roux) + * Type __ssh_authorized_key: Add messaging (Thomas Eckert) 4.7.2: 2017-10-22 * Type __hostname: Add support for CoreOS (Ľubomír Kučera) From 4799e435169d6d91f4a564e0a203443ec06ec46d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Wed, 1 Nov 2017 08:56:12 +0100 Subject: [PATCH 0681/1332] new type: __letsencrypt_cert (#591) --- .../type/__letsencrypt_cert/explorer/exists | 5 ++ .../type/__letsencrypt_cert/gencode-remote | 18 ++++++ cdist/conf/type/__letsencrypt_cert/man.rst | 46 ++++++++++++++ cdist/conf/type/__letsencrypt_cert/manifest | 62 +++++++++++++++++++ .../parameter/default/admin-email | 1 + .../__letsencrypt_cert/parameter/optional | 1 + .../__letsencrypt_cert/parameter/required | 1 + 7 files changed, 134 insertions(+) create mode 100644 cdist/conf/type/__letsencrypt_cert/explorer/exists create mode 100644 cdist/conf/type/__letsencrypt_cert/gencode-remote create mode 100644 cdist/conf/type/__letsencrypt_cert/man.rst create mode 100644 cdist/conf/type/__letsencrypt_cert/manifest create mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/default/admin-email create mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/optional create mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/required diff --git a/cdist/conf/type/__letsencrypt_cert/explorer/exists b/cdist/conf/type/__letsencrypt_cert/explorer/exists new file mode 100644 index 00000000..cb967663 --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/explorer/exists @@ -0,0 +1,5 @@ +domain=$__object_id + +if [ -f "/etc/letsencrypt/live/$domain/fullchain.pem" ]; then + echo yes +fi diff --git a/cdist/conf/type/__letsencrypt_cert/gencode-remote b/cdist/conf/type/__letsencrypt_cert/gencode-remote new file mode 100644 index 00000000..62ada241 --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/gencode-remote @@ -0,0 +1,18 @@ +domain="$__object_id" + +exists=$(cat "$__object/explorer/exists") +webroot="$(cat "$__object/parameter/webroot")" +admin_email="$(cat "$__object/parameter/admin-email")" + +if [ -n "$exists" ]; then + exit 0 +fi + +cat < +Kamila Součková + + +COPYING +------- +Copyright \(C) 2017 Nico Schottelius, Kamila Součková. 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/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest new file mode 100644 index 00000000..0dbb281e --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -0,0 +1,62 @@ +os=$(cat "$__global/explorer/os") +os_version=$(cat "$__global/explorer/os_version") + +case "$os" in + debian) + case "$os_version" in + 8*) + __apt_source jessie-backports \ + --uri http://http.debian.net/debian \ + --distribution jessie-backports \ + --component main + + require="__apt_source/jessie-backports" __package_apt python-certbot --target-release jessie-backports + require="__apt_source/jessie-backports" __package_apt certbot --target-release jessie-backports + # Seems to be a missing dependency on debian 8 + __package python-ndg-httpsclient + ;; + *) + echo "Unsupported OS version: $os_version" >&2 + exit 1 + ;; + esac + + certbot_fullpath=/usr/bin/certbot + ;; + devuan) + case "$os_version" in + jessie) + __apt_source jessie-backports \ + --uri http://auto.mirror.devuan.org/merged \ + --distribution jessie-backports \ + --component main + + require="__apt_source/jessie-backports" __package_apt python-certbot --target-release jessie-backports + require="__apt_source/jessie-backports" __package_apt certbot --target-release jessie-backports + # Seems to be a missing dependency on debian 8 + __package python-ndg-httpsclient + ;; + *) + echo "Unsupported OS version: $os_version" >&2 + exit 1 + ;; + esac + + certbot_fullpath=/usr/bin/certbot + ;; + freebsd) + __package py27-certbot + + certbot_fullpath=/usr/local/bin/certbot + ;; + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; +esac + + +__cron letsencrypt-certbot \ + --user root \ + --command "$certbot_fullpath renew -q" \ + --hour 0 diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/default/admin-email b/cdist/conf/type/__letsencrypt_cert/parameter/default/admin-email new file mode 100644 index 00000000..8da2d115 --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/parameter/default/admin-email @@ -0,0 +1 @@ +root@localhost diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/optional b/cdist/conf/type/__letsencrypt_cert/parameter/optional new file mode 100644 index 00000000..bfe77226 --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/parameter/optional @@ -0,0 +1 @@ +admin-email diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/required b/cdist/conf/type/__letsencrypt_cert/parameter/required new file mode 100644 index 00000000..fc7c3e96 --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/parameter/required @@ -0,0 +1 @@ +webroot From 5e087fd28000eff544a9bc16934b4ac95e150e3a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 1 Nov 2017 08:57:04 +0100 Subject: [PATCH 0682/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 7a739ab3..a89571e9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __ccollect_source: Add create destination parameter (Dominique Roux) * Type __ssh_authorized_key: Add messaging (Thomas Eckert) + * New type: __letsencrypt_cert (Nico Schottelius, Kamila Součková) 4.7.2: 2017-10-22 * Type __hostname: Add support for CoreOS (Ľubomír Kučera) From e6c5563a1665f1757b2000e9861808b116a109c2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 2 Nov 2017 13:57:36 +0100 Subject: [PATCH 0683/1332] NoSuchTypeError -> InvalidTypeError --- cdist/core/__init__.py | 2 +- cdist/core/cdist_type.py | 11 +++++++++-- cdist/emulator.py | 2 +- cdist/test/cdist_type/__init__.py | 2 +- cdist/test/config/__init__.py | 2 +- cdist/test/emulator/__init__.py | 4 ++-- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/cdist/core/__init__.py b/cdist/core/__init__.py index 179c1a29..ebe69366 100644 --- a/cdist/core/__init__.py +++ b/cdist/core/__init__.py @@ -21,7 +21,7 @@ # from cdist.core.cdist_type import CdistType -from cdist.core.cdist_type import NoSuchTypeError +from cdist.core.cdist_type import NoSuchTypeError, InvalidTypeError from cdist.core.cdist_object import CdistObject from cdist.core.cdist_object import IllegalObjectIdError from cdist.core.explorer import Explorer diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 1f7c3eb5..b2b5e14d 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -32,10 +32,17 @@ class NoSuchTypeError(cdist.Error): self.type_absolute_path = type_absolute_path def __str__(self): - return "Type '%s' does not exist at %s" % ( + return "Type '%s' does not exist at '%s'" % ( self.type_path, self.type_absolute_path) +class InvalidTypeError(NoSuchTypeError): + def __str__(self): + return "Invalid type '%s' at '%s' defined at '%s'" % ( + self.type_path, self.type_absolute_path, + os.path.realpath(self.type_absolute_path)) + + class CdistType(object): """Represents a cdist type. @@ -51,7 +58,7 @@ class CdistType(object): self.path = self.name self.absolute_path = os.path.join(self.base_path, self.path) if not os.path.isdir(self.absolute_path): - raise NoSuchTypeError(self.name, self.path, self.absolute_path) + raise InvalidTypeError(self.name, self.path, self.absolute_path) self.manifest_path = os.path.join(self.name, "manifest") self.explorer_path = os.path.join(self.name, "explorer") self.gencode_local_path = os.path.join(self.name, "gencode-local") diff --git a/cdist/emulator.py b/cdist/emulator.py index 40b19e4b..0bb7ff16 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -247,7 +247,7 @@ class Emulator(object): # Raises an error, if object cannot be created try: cdist_object = self.cdist_object.object_from_name(requirement) - except core.cdist_type.NoSuchTypeError as e: + except core.cdist_type.InvalidTypeError as e: self.log.error(("%s requires object %s, but type %s does not" " exist. Defined at %s" % ( self.cdist_object.name, diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index 6e11383b..ca961170 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -55,7 +55,7 @@ class TypeTestCase(test.CdistTestCase): def test_nonexistent_type(self): base_path = fixtures - self.assertRaises(core.NoSuchTypeError, core.CdistType, base_path, + self.assertRaises(core.InvalidTypeError, core.CdistType, base_path, '__i-dont-exist') def test_name(self): diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index 5ff98269..252b7c8f 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -151,7 +151,7 @@ class ConfigRunTestCase(test.CdistTestCase): """Unknown type should be detected in the resolving process""" first = self.object_index['__first/man'] first.requirements = ['__nosuchtype/not/exist'] - with self.assertRaises(cdist.core.cdist_type.NoSuchTypeError): + with self.assertRaises(cdist.core.cdist_type.InvalidTypeError): self.config.iterate_until_finished() def test_requirement_singleton_where_no_singleton(self): diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 6bc80e96..f94ce96d 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -76,14 +76,14 @@ class EmulatorTestCase(test.CdistTestCase): def test_nonexistent_type_exec(self): argv = ['__does-not-exist'] - self.assertRaises(core.cdist_type.NoSuchTypeError, emulator.Emulator, + self.assertRaises(core.cdist_type.InvalidTypeError, emulator.Emulator, argv, env=self.env) def test_nonexistent_type_requirement(self): argv = ['__file', '/tmp/foobar'] self.env['require'] = '__does-not-exist/some-id' emu = emulator.Emulator(argv, env=self.env) - self.assertRaises(core.cdist_type.NoSuchTypeError, emu.run) + self.assertRaises(core.cdist_type.InvalidTypeError, emu.run) def test_illegal_object_id_requirement(self): argv = ['__file', '/tmp/foobar'] From c14f3b68f4a4e1f690e51954eff3234ec3dd0cbc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 2 Nov 2017 17:44:47 +0100 Subject: [PATCH 0684/1332] Warn about invalid type and continue instead of error. --- cdist/core/__init__.py | 2 +- cdist/core/cdist_type.py | 18 ++++++++++-------- docs/changelog | 1 + 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cdist/core/__init__.py b/cdist/core/__init__.py index ebe69366..b79cdb21 100644 --- a/cdist/core/__init__.py +++ b/cdist/core/__init__.py @@ -21,7 +21,7 @@ # from cdist.core.cdist_type import CdistType -from cdist.core.cdist_type import NoSuchTypeError, InvalidTypeError +from cdist.core.cdist_type import InvalidTypeError from cdist.core.cdist_object import CdistObject from cdist.core.cdist_object import IllegalObjectIdError from cdist.core.explorer import Explorer diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index b2b5e14d..ed386631 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -23,20 +23,15 @@ import os import cdist import cdist.core +import logging -class NoSuchTypeError(cdist.Error): +class InvalidTypeError(cdist.Error): def __init__(self, name, type_path, type_absolute_path): self.name = name self.type_path = type_path self.type_absolute_path = type_absolute_path - def __str__(self): - return "Type '%s' does not exist at '%s'" % ( - self.type_path, self.type_absolute_path) - - -class InvalidTypeError(NoSuchTypeError): def __str__(self): return "Invalid type '%s' at '%s' defined at '%s'" % ( self.type_path, self.type_absolute_path, @@ -52,12 +47,15 @@ class CdistType(object): """ + log = logging.getLogger("cdist") + def __init__(self, base_path, name): self.base_path = base_path self.name = name self.path = self.name self.absolute_path = os.path.join(self.base_path, self.path) if not os.path.isdir(self.absolute_path): + os.remove(self.absolute_path) raise InvalidTypeError(self.name, self.path, self.absolute_path) self.manifest_path = os.path.join(self.name, "manifest") self.explorer_path = os.path.join(self.name, "explorer") @@ -80,7 +78,11 @@ class CdistType(object): def list_types(cls, base_path): """Return a list of type instances""" for name in cls.list_type_names(base_path): - yield cls(base_path, name) + try: + yield cls(base_path, name) + except InvalidTypeError as e: + # ignore invalid type, log warning and continue + cls.log.warning(e) @classmethod def list_type_names(cls, base_path): diff --git a/docs/changelog b/docs/changelog index a89571e9..291b9dab 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __ccollect_source: Add create destination parameter (Dominique Roux) * Type __ssh_authorized_key: Add messaging (Thomas Eckert) * New type: __letsencrypt_cert (Nico Schottelius, Kamila Součková) + * Core: Warn about invalid type in conf dir and continue instead of error (Darko Poljak) 4.7.2: 2017-10-22 * Type __hostname: Add support for CoreOS (Ľubomír Kučera) From 782e662a137e6985dafe700fe812b2f7033dc05c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 2 Nov 2017 17:54:14 +0100 Subject: [PATCH 0685/1332] Remove invalid type link from runtime conf dir at proper time. --- cdist/core/cdist_type.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index ed386631..42533a4d 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -55,7 +55,6 @@ class CdistType(object): self.path = self.name self.absolute_path = os.path.join(self.base_path, self.path) if not os.path.isdir(self.absolute_path): - os.remove(self.absolute_path) raise InvalidTypeError(self.name, self.path, self.absolute_path) self.manifest_path = os.path.join(self.name, "manifest") self.explorer_path = os.path.join(self.name, "explorer") @@ -83,6 +82,9 @@ class CdistType(object): except InvalidTypeError as e: # ignore invalid type, log warning and continue cls.log.warning(e) + # remove invalid from runtime conf dir + absolute_path = os.path.join(base_path, name) + os.remove(absolute_path) @classmethod def list_type_names(cls, base_path): From a8c41bfe4469158202b38cd7990b6622a5cd27db Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 2 Nov 2017 19:56:27 +0100 Subject: [PATCH 0686/1332] Change warning message for invalid type. --- cdist/core/cdist_type.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 42533a4d..beb459b3 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -31,11 +31,11 @@ class InvalidTypeError(cdist.Error): self.name = name self.type_path = type_path self.type_absolute_path = type_absolute_path + self.source_path = os.path.realpath(self.type_absolute_path) def __str__(self): return "Invalid type '%s' at '%s' defined at '%s'" % ( - self.type_path, self.type_absolute_path, - os.path.realpath(self.type_absolute_path)) + self.type_path, self.type_absolute_path, self.source_path) class CdistType(object): @@ -81,10 +81,11 @@ class CdistType(object): yield cls(base_path, name) except InvalidTypeError as e: # ignore invalid type, log warning and continue - cls.log.warning(e) + msg = "Ignoring invalid type '%s' at '%s' defined at '%s'" % ( + e.type_path, e.type_absolute_path, e.source_path) + cls.log.warning(msg) # remove invalid from runtime conf dir - absolute_path = os.path.join(base_path, name) - os.remove(absolute_path) + os.remove(e.type_absolute_path) @classmethod def list_type_names(cls, base_path): From b18327c520d8a4950b5469f8d218eb0530ca3d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Tue, 7 Nov 2017 13:25:37 +0100 Subject: [PATCH 0687/1332] Add __systemd_unit type (#589) --- .../__systemd_unit/explorer/enablement-state | 21 +++++ .../__systemd_unit/explorer/systemctl-present | 21 +++++ cdist/conf/type/__systemd_unit/gencode-remote | 62 ++++++++++++++ cdist/conf/type/__systemd_unit/man.rst | 84 +++++++++++++++++++ cdist/conf/type/__systemd_unit/manifest | 39 +++++++++ .../type/__systemd_unit/parameter/boolean | 1 + .../parameter/default/enablement-state | 0 .../__systemd_unit/parameter/default/source | 0 .../__systemd_unit/parameter/default/state | 1 + .../type/__systemd_unit/parameter/optional | 3 + 10 files changed, 232 insertions(+) create mode 100644 cdist/conf/type/__systemd_unit/explorer/enablement-state create mode 100644 cdist/conf/type/__systemd_unit/explorer/systemctl-present create mode 100644 cdist/conf/type/__systemd_unit/gencode-remote create mode 100644 cdist/conf/type/__systemd_unit/man.rst create mode 100644 cdist/conf/type/__systemd_unit/manifest create mode 100644 cdist/conf/type/__systemd_unit/parameter/boolean create mode 100644 cdist/conf/type/__systemd_unit/parameter/default/enablement-state create mode 100644 cdist/conf/type/__systemd_unit/parameter/default/source create mode 100644 cdist/conf/type/__systemd_unit/parameter/default/state create mode 100644 cdist/conf/type/__systemd_unit/parameter/optional diff --git a/cdist/conf/type/__systemd_unit/explorer/enablement-state b/cdist/conf/type/__systemd_unit/explorer/enablement-state new file mode 100644 index 00000000..5a5a4462 --- /dev/null +++ b/cdist/conf/type/__systemd_unit/explorer/enablement-state @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2017 Ľubomír Kučera +# +# 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 . +# + +systemctl is-enabled "${__object_id}" 2>/dev/null || true diff --git a/cdist/conf/type/__systemd_unit/explorer/systemctl-present b/cdist/conf/type/__systemd_unit/explorer/systemctl-present new file mode 100644 index 00000000..7218affc --- /dev/null +++ b/cdist/conf/type/__systemd_unit/explorer/systemctl-present @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2017 Ľubomír Kučera +# +# 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 . +# + +command -v systemctl > /dev/null 2>&1 && echo 0 || echo 1 diff --git a/cdist/conf/type/__systemd_unit/gencode-remote b/cdist/conf/type/__systemd_unit/gencode-remote new file mode 100644 index 00000000..6ea3ddaa --- /dev/null +++ b/cdist/conf/type/__systemd_unit/gencode-remote @@ -0,0 +1,62 @@ +#!/bin/sh -e +# +# 2017 Ľubomír Kučera +# +# 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 . +# + +systemctl_present=$(cat "${__object}/explorer/systemctl-present") + +if [ "${systemctl_present}" -ne 0 ]; then + echo "systemctl does not seem to be present on this system" >&2 + + exit 1 +fi + +name="${__object_id}" +state=$(cat "${__object}/parameter/state") +current_enablement_state=$(cat "${__object}/explorer/enablement-state") + +if [ "${state}" = "absent" ]; then + if [ ! -z "${current_enablement_state}" ]; then + echo "systemctl --now disable ${name}" + fi + + exit 0 +fi + +desired_enablement_state=$(cat "${__object}/parameter/enablement-state") + +if [ "${current_enablement_state}" = "${desired_enablement_state}" ]; then + exit 0 +fi + +case "${desired_enablement_state}" in + "") + # Do nothing + : + ;; + enabled) + echo "systemctl enable ${name}" + ;; + disabled) + echo "systemctl disable ${name}" + ;; + *) + echo "Unsupported unit status: ${desired_enablement_state}" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__systemd_unit/man.rst b/cdist/conf/type/__systemd_unit/man.rst new file mode 100644 index 00000000..c624e91e --- /dev/null +++ b/cdist/conf/type/__systemd_unit/man.rst @@ -0,0 +1,84 @@ +cdist-type__systemd_unit(7) +=========================== + +NAME +---- + +cdist-type__systemd_unit - Install a systemd unit + +DESCRIPTION +----------- + +This type can install, enable and start a systemd unit. This is particularly +useful on systems which take advantage of systemd heavily (e.g., CoreOS). For +more information about systemd units, see SYSTEMD.UNIT(5). + +REQUIRED PARAMETERS +------------------- + +None. + +OPTIONAL PARAMETERS +------------------- + +enablement-state + 'enabled' or 'disabled', where: + + enabled + enables the unit + disabled + disables the unit + +source + Path to the config file. If source is '-' (dash), take what was written to + stdin as the config file content. + +state + 'present' or 'absent', defaults to 'present' where: + + present + the unit is installed, enabled and started + absent + the unit is stopped, disabled and uninstalled + +BOOLEAN PARAMETERS +------------------ + +restart + Restart the unit on change. + +MESSAGES +-------- + +None. + +EXAMPLES +-------- + +.. code-block:: sh + + # Installs, enables and starts foobar.service + __systemd_unit foobar.service \ + --source "${__manifest}/files/foobar.service" \ + --enablement-state enabled \ + --restart + + # Disables the unit + __systemd_unit foobar.service --enablement-state disabled + + # Stops, disables and uninstalls foobar.service + __systemd_unit foobar.service --state absent + + +AUTHORS +------- + +Ľubomír Kučera + +COPYING +------- + +Copyright \(C) 2017 Ľubomír Kučera. 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/__systemd_unit/manifest b/cdist/conf/type/__systemd_unit/manifest new file mode 100644 index 00000000..10dc4f0c --- /dev/null +++ b/cdist/conf/type/__systemd_unit/manifest @@ -0,0 +1,39 @@ +#!/bin/sh -e +# +# 2017 Ľubomír Kučera +# +# 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}" +source=$(cat "${__object}/parameter/source") +state=$(cat "${__object}/parameter/state") + +onchange() { + echo -n "systemctl daemon-reload" + + if [ -f "${__object}/parameter/restart" ]; then + echo -n " && (systemctl restart ${name} || true)" + fi + + echo +} + +__config_file "/etc/systemd/system/${name}" \ + --mode 644 \ + --onchange "$(onchange)" \ + --source "${source}" \ + --state "${state}" diff --git a/cdist/conf/type/__systemd_unit/parameter/boolean b/cdist/conf/type/__systemd_unit/parameter/boolean new file mode 100644 index 00000000..eea5a271 --- /dev/null +++ b/cdist/conf/type/__systemd_unit/parameter/boolean @@ -0,0 +1 @@ +restart diff --git a/cdist/conf/type/__systemd_unit/parameter/default/enablement-state b/cdist/conf/type/__systemd_unit/parameter/default/enablement-state new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__systemd_unit/parameter/default/source b/cdist/conf/type/__systemd_unit/parameter/default/source new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__systemd_unit/parameter/default/state b/cdist/conf/type/__systemd_unit/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__systemd_unit/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__systemd_unit/parameter/optional b/cdist/conf/type/__systemd_unit/parameter/optional new file mode 100644 index 00000000..e7cc7acf --- /dev/null +++ b/cdist/conf/type/__systemd_unit/parameter/optional @@ -0,0 +1,3 @@ +enablement-state +source +state From 4cdc4ea42c46451b1a42df2de19df1202d791c75 Mon Sep 17 00:00:00 2001 From: _moep_ Date: Tue, 7 Nov 2017 13:26:44 +0100 Subject: [PATCH 0688/1332] update type for Debian Stretch (#593) --- cdist/conf/type/__letsencrypt_cert/manifest | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cdist/conf/type/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest index 0dbb281e..e7774ee1 100644 --- a/cdist/conf/type/__letsencrypt_cert/manifest +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -15,6 +15,15 @@ case "$os" in # Seems to be a missing dependency on debian 8 __package python-ndg-httpsclient ;; + 9*) + __apt_source stretch-backports \ + --uri http://http.debian.net/debian \ + --distribution stretch-backports \ + --component main + + require="__apt_source/stretch-backports" __package_apt python-certbot --target-release stretch-backports + require="__apt_source/stretch-backports" __package_apt certbot --target-release stretch-backports + ;; *) echo "Unsupported OS version: $os_version" >&2 exit 1 From 3918ad897a92851fef28f1e778e2054d87262d16 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 7 Nov 2017 13:30:04 +0100 Subject: [PATCH 0689/1332] changelog++ --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 291b9dab..46cc1f87 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,8 @@ next: * Type __ssh_authorized_key: Add messaging (Thomas Eckert) * New type: __letsencrypt_cert (Nico Schottelius, Kamila Součková) * Core: Warn about invalid type in conf dir and continue instead of error (Darko Poljak) + * New type: __systemd_unit (Ľubomír Kučera) + * Type __letsencrypt_cert: Add support for debian stretch (_moep_) 4.7.2: 2017-10-22 * Type __hostname: Add support for CoreOS (Ľubomír Kučera) From d7120d352c6fef9951b6339e747686f1b7a93d99 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 8 Nov 2017 07:51:11 +0100 Subject: [PATCH 0690/1332] Update changelog. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 46cc1f87..cdba68db 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,7 +7,7 @@ next: * New type: __letsencrypt_cert (Nico Schottelius, Kamila Součková) * Core: Warn about invalid type in conf dir and continue instead of error (Darko Poljak) * New type: __systemd_unit (Ľubomír Kučera) - * Type __letsencrypt_cert: Add support for debian stretch (_moep_) + * Type __letsencrypt_cert: Add support for debian stretch (Daniel Tschada) 4.7.2: 2017-10-22 * Type __hostname: Add support for CoreOS (Ľubomír Kučera) From 4f5dddd9d6a9ea1ae5e6ecddc9c8961c8ce26ebf Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 9 Nov 2017 08:20:33 +0100 Subject: [PATCH 0691/1332] Fix for __line containing single quotes: #154. (#594) --- cdist/conf/type/__line/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index fa051951..4a75b4c5 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -81,7 +81,7 @@ tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) if [ -f "$file" ]; then cp -p "$file" "\$tmpfile" fi -grep -v $greparg '$regex' '$file' > \$tmpfile || true +grep -v $greparg "$regex" '$file' > \$tmpfile || true mv -f "\$tmpfile" "$file" eof echo "removed" >> "$__messages_out" From 4fc72908d8a965911e0ece1d9878d01906b6aff4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 9 Nov 2017 08:20:40 +0100 Subject: [PATCH 0692/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index cdba68db..ad9c983a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Core: Warn about invalid type in conf dir and continue instead of error (Darko Poljak) * New type: __systemd_unit (Ľubomír Kučera) * Type __letsencrypt_cert: Add support for debian stretch (Daniel Tschada) + * Type __line: Fix a case for absent when line contains single quotes (Darko Poljak) 4.7.2: 2017-10-22 * Type __hostname: Add support for CoreOS (Ľubomír Kučera) From aec63d42f1e028e1b0f04cae7ce046d13f15f478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Fri, 10 Nov 2017 12:22:38 +0100 Subject: [PATCH 0693/1332] __config_file: Fix onchange command not being executed (#596) When a config file state changes from present to absent, onchange command was not being run. Fixes #595. --- cdist/conf/type/__config_file/gencode-remote | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cdist/conf/type/__config_file/gencode-remote b/cdist/conf/type/__config_file/gencode-remote index 8a580e22..5f1626be 100755 --- a/cdist/conf/type/__config_file/gencode-remote +++ b/cdist/conf/type/__config_file/gencode-remote @@ -19,16 +19,9 @@ # destination="$__object_id" -state="$(cat "$__object/parameter/state")" - -if [ "$state" = "absent" ]; then - # nothing to do - exit 0 -fi if [ -f "$__object/parameter/onchange" ]; then if grep -q "^__file/${destination}" "$__messages_in"; then cat "$__object/parameter/onchange" fi fi - From 808851d63b9e4b0710cb563b54b0c46b6039f005 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 10 Nov 2017 12:22:05 +0100 Subject: [PATCH 0694/1332] changelog++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ad9c983a..cd8d8228 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * New type: __systemd_unit (Ľubomír Kučera) * Type __letsencrypt_cert: Add support for debian stretch (Daniel Tschada) * Type __line: Fix a case for absent when line contains single quotes (Darko Poljak) + * Type __config_file: Fix onchange command not being executed (Ľubomír Kučera) 4.7.2: 2017-10-22 * Type __hostname: Add support for CoreOS (Ľubomír Kučera) From 9e7b1c4c06702e0cc1fe9263d821d4d648805b90 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 10 Nov 2017 21:19:27 +0100 Subject: [PATCH 0695/1332] Release 4.7.3 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index cd8d8228..dedd7d9d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) * Type __ssh_authorized_key: Add messaging (Thomas Eckert) * New type: __letsencrypt_cert (Nico Schottelius, Kamila Součková) From 0bf6af6d22f9d9a6ed4a4c37dd51bc0782ca51c5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 15 Nov 2017 07:30:35 +0100 Subject: [PATCH 0696/1332] Skip empty parameter. Fixes #599. (#600) --- cdist/core/cdist_type.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index beb459b3..40194f94 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -155,7 +155,9 @@ class CdistType(object): "parameter", "required")) as fd: for line in fd: - parameters.append(line.strip()) + line = line.strip() + if line: + parameters.append(line) except EnvironmentError: # error ignored pass @@ -173,7 +175,9 @@ class CdistType(object): "parameter", "required_multiple")) as fd: for line in fd: - parameters.append(line.strip()) + line = line.strip() + if line: + parameters.append(line) except EnvironmentError: # error ignored pass @@ -191,7 +195,9 @@ class CdistType(object): "parameter", "optional")) as fd: for line in fd: - parameters.append(line.strip()) + line = line.strip() + if line: + parameters.append(line) except EnvironmentError: # error ignored pass @@ -209,7 +215,9 @@ class CdistType(object): "parameter", "optional_multiple")) as fd: for line in fd: - parameters.append(line.strip()) + line = line.strip() + if line: + parameters.append(line) except EnvironmentError: # error ignored pass @@ -227,7 +235,9 @@ class CdistType(object): "parameter", "boolean")) as fd: for line in fd: - parameters.append(line.strip()) + line = line.strip() + if line: + parameters.append(line) except EnvironmentError: # error ignored pass From 3b6a4711198d6b68c6a7350d30faa650aa9863c6 Mon Sep 17 00:00:00 2001 From: uqam-fob Date: Wed, 15 Nov 2017 01:31:17 -0500 Subject: [PATCH 0697/1332] explorer/memory: Support OpenBSD (#602) Adds support to detect the amount of memory available on OpenBSD systems. --- cdist/conf/explorer/memory | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cdist/conf/explorer/memory b/cdist/conf/explorer/memory index 05db865f..4e3efff8 100755 --- a/cdist/conf/explorer/memory +++ b/cdist/conf/explorer/memory @@ -2,6 +2,7 @@ # # 2014 Daniel Heule (hda at sfs.biz) # 2014 Thomas Oettli (otho at sfs.biz) +# Copyright 2017, Philippe Gregoire # # This file is part of cdist. # @@ -28,6 +29,10 @@ case "$os" in echo "$(sysctl -n hw.memsize)/1024" | bc ;; + "openbsd") + echo "$(sysctl -n hw.physmem) / 1048576" | bc + ;; + *) if [ -r /proc/meminfo ]; then grep "MemTotal:" /proc/meminfo | awk '{print $2}' From 7c8f1e0f57ed0473fa64158c7b7b53c31d0354a4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 15 Nov 2017 07:32:35 +0100 Subject: [PATCH 0698/1332] changelog++ --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index dedd7d9d..8a9decf5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,10 @@ Changelog --------- +next: + * Core: Skip empty lines in parameter files (Darko Poljak) + * Explorer memory: Support OpenBSD (Philippe Gregoire) + 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) * Type __ssh_authorized_key: Add messaging (Thomas Eckert) From be7a99210b0cb7b8e1e9eb6baa20d10635bb8737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Sun, 19 Nov 2017 13:31:44 +0100 Subject: [PATCH 0699/1332] add --minute to __cron (#603) We don't want this to run _every_ minute (default for `--minute` is `*`). --- cdist/conf/type/__letsencrypt_cert/manifest | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest index e7774ee1..c9a688ca 100644 --- a/cdist/conf/type/__letsencrypt_cert/manifest +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -68,4 +68,5 @@ esac __cron letsencrypt-certbot \ --user root \ --command "$certbot_fullpath renew -q" \ - --hour 0 + --hour 0 \ + --minute 47 From eb8922ebcda641f63a6bca01f65a3657c357651e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 20 Nov 2017 08:02:25 +0100 Subject: [PATCH 0700/1332] Remove redundant log.error line. --- cdist/emulator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 0bb7ff16..4123a353 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -201,7 +201,6 @@ class Emulator(object): self.cdist_object.parameters, self.object_source, self.parameters)) - self.log.error(errmsg) raise cdist.Error(errmsg) else: if self.cdist_object.exists: From 71b858e46724b7ac2a908dbd1d10a5562ebd0375 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 12 Dec 2017 00:15:54 +0100 Subject: [PATCH 0701/1332] use parameter defaults for chroot; re-export cdist log level to nested cdist run Signed-off-by: Steven Armstrong --- .../conf/type/__install_config/gencode-local | 1 + cdist/conf/type/__install_config/manifest | 23 ------------------- .../__install_config/parameter/default/chroot | 1 + 3 files changed, 2 insertions(+), 23 deletions(-) delete mode 100755 cdist/conf/type/__install_config/manifest create mode 100644 cdist/conf/type/__install_config/parameter/default/chroot diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index a298a5cc..8f24cf2e 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -23,6 +23,7 @@ remote_exec="$__type/files/remote/exec" remote_copy="$__type/files/remote/copy" cat << DONE +export __cdist_log_level=$__cdist_log_level export __default_remote_exec="$__remote_exec" export __default_remote_copy="$__remote_copy" cdist config \ diff --git a/cdist/conf/type/__install_config/manifest b/cdist/conf/type/__install_config/manifest deleted file mode 100755 index b920d8ab..00000000 --- a/cdist/conf/type/__install_config/manifest +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh -e -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# 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 . -# - -# set defaults -chroot="$(cat "$__object/parameter/chroot" 2>/dev/null \ - || echo "/target" | tee "$__object/parameter/chroot")" diff --git a/cdist/conf/type/__install_config/parameter/default/chroot b/cdist/conf/type/__install_config/parameter/default/chroot new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/cdist/conf/type/__install_config/parameter/default/chroot @@ -0,0 +1 @@ +/target From b722843f01df48510e0e68802c50a2199e7dbf8b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 12 Dec 2017 00:18:49 +0100 Subject: [PATCH 0702/1332] changelog++ Signed-off-by: Steven Armstrong --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8a9decf5..98c671ad 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Core: Skip empty lines in parameter files (Darko Poljak) * Explorer memory: Support OpenBSD (Philippe Gregoire) + * Type __install_config: re-export cdist log level during installation (Steven Armstrong) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From 457233f96847c9c1b9fcc5128bbb75c0e2e1bd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Tue, 12 Dec 2017 08:50:48 +0100 Subject: [PATCH 0703/1332] __sysctl: Add support for CoreOS (#605) --- cdist/conf/type/__sysctl/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__sysctl/manifest b/cdist/conf/type/__sysctl/manifest index 2d8b8349..39a2e53c 100755 --- a/cdist/conf/type/__sysctl/manifest +++ b/cdist/conf/type/__sysctl/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - redhat|centos|ubuntu|debian|devuan|archlinux) + redhat|centos|ubuntu|debian|devuan|archlinux|coreos) : ;; *) From b4e98d4ab4ea9e1ad111f7274085ac0006fb56b3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 12 Dec 2017 08:50:25 +0100 Subject: [PATCH 0704/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 98c671ad..5b41a50c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Core: Skip empty lines in parameter files (Darko Poljak) * Explorer memory: Support OpenBSD (Philippe Gregoire) * Type __install_config: re-export cdist log level during installation (Steven Armstrong) + * Type __sysctl: Add support for CoreOS (Ľubomír Kučera) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From 3397bcbf9bc651f274dad2dcd7556a3afba12129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Fri, 29 Dec 2017 17:06:48 +0100 Subject: [PATCH 0705/1332] __systemd_unit improvements (#606) * __systemd_unit: Move systemctl detection to manifest * __systemd_unit: Restart the unit if inactive Until now, the --restart parameter caused the unit to be restarted only when the unit file has changed. This commit modifies --restart behavior so that the unit is also restarted when the unit is inactive. * __systemd_unit: Do not create unit file when source is empty --- .../type/__systemd_unit/explorer/unit-status | 21 ++++++++++++++++++ cdist/conf/type/__systemd_unit/gencode-remote | 17 +++++++------- cdist/conf/type/__systemd_unit/man.rst | 2 +- cdist/conf/type/__systemd_unit/manifest | 22 ++++++++++--------- 4 files changed, 43 insertions(+), 19 deletions(-) create mode 100644 cdist/conf/type/__systemd_unit/explorer/unit-status diff --git a/cdist/conf/type/__systemd_unit/explorer/unit-status b/cdist/conf/type/__systemd_unit/explorer/unit-status new file mode 100644 index 00000000..b68e5169 --- /dev/null +++ b/cdist/conf/type/__systemd_unit/explorer/unit-status @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2017 Ľubomír Kučera +# +# 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 . +# + +systemctl is-active "${__object_id}" || true diff --git a/cdist/conf/type/__systemd_unit/gencode-remote b/cdist/conf/type/__systemd_unit/gencode-remote index 6ea3ddaa..c608d9b3 100644 --- a/cdist/conf/type/__systemd_unit/gencode-remote +++ b/cdist/conf/type/__systemd_unit/gencode-remote @@ -18,14 +18,6 @@ # along with cdist. If not, see . # -systemctl_present=$(cat "${__object}/explorer/systemctl-present") - -if [ "${systemctl_present}" -ne 0 ]; then - echo "systemctl does not seem to be present on this system" >&2 - - exit 1 -fi - name="${__object_id}" state=$(cat "${__object}/parameter/state") current_enablement_state=$(cat "${__object}/explorer/enablement-state") @@ -38,6 +30,15 @@ if [ "${state}" = "absent" ]; then exit 0 fi +unit_status=$(cat "${__object}/explorer/unit-status") + +if [ -f "${__object}/parameter/restart" ]; then + if grep -q "^__file/etc/systemd/system/${name}" "${__messages_in}" || \ + [ "${unit_status}" != "active" ]; then + echo "systemctl restart ${name} || true" + fi +fi + desired_enablement_state=$(cat "${__object}/parameter/enablement-state") if [ "${current_enablement_state}" = "${desired_enablement_state}" ]; then diff --git a/cdist/conf/type/__systemd_unit/man.rst b/cdist/conf/type/__systemd_unit/man.rst index c624e91e..88da6b30 100644 --- a/cdist/conf/type/__systemd_unit/man.rst +++ b/cdist/conf/type/__systemd_unit/man.rst @@ -45,7 +45,7 @@ BOOLEAN PARAMETERS ------------------ restart - Restart the unit on change. + Restart the unit on unit file change or when the unit is inactive. MESSAGES -------- diff --git a/cdist/conf/type/__systemd_unit/manifest b/cdist/conf/type/__systemd_unit/manifest index 10dc4f0c..d5f04ee6 100644 --- a/cdist/conf/type/__systemd_unit/manifest +++ b/cdist/conf/type/__systemd_unit/manifest @@ -18,22 +18,24 @@ # along with cdist. If not, see . # +systemctl_present=$(cat "${__object}/explorer/systemctl-present") + +if [ "${systemctl_present}" -ne 0 ]; then + echo "systemctl does not seem to be present on this system" >&2 + + exit 1 +fi + name="${__object_id}" source=$(cat "${__object}/parameter/source") state=$(cat "${__object}/parameter/state") -onchange() { - echo -n "systemctl daemon-reload" - - if [ -f "${__object}/parameter/restart" ]; then - echo -n " && (systemctl restart ${name} || true)" - fi - - echo -} +if [ -z "${source}" ] && [ "${state}" != "absent" ]; then + exit 0 +fi __config_file "/etc/systemd/system/${name}" \ --mode 644 \ - --onchange "$(onchange)" \ + --onchange "systemctl daemon-reload" \ --source "${source}" \ --state "${state}" From fc8dded8e96c026d37d36140fcd00699413c564f Mon Sep 17 00:00:00 2001 From: uqam-fob Date: Fri, 29 Dec 2017 11:09:06 -0500 Subject: [PATCH 0706/1332] __line: Support regex beginning with an hyphen (fixes #607) (#608) If `regex` begins with an hyphen, `grep` treats it as an option and treats `file` as the regular expression. This leads to `grep` trying to read from the standard input and making it wait infinitely. This patch adds the missing argument breaker `--` and allows `regex` to begin with an hyphen (provided it is called correctly). --- cdist/conf/type/__line/explorer/state | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__line/explorer/state b/cdist/conf/type/__line/explorer/state index d04d5d09..08056c86 100755 --- a/cdist/conf/type/__line/explorer/state +++ b/cdist/conf/type/__line/explorer/state @@ -35,7 +35,7 @@ else fi # Allow missing file - thus 2>/dev/null -if grep -q $greparg "$regex" "$file" 2>/dev/null; then +if grep -q $greparg -- "$regex" "$file" 2>/dev/null; then echo present else echo absent From a657af64a15d6d713226faa13041a6a9872e8fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Fri, 29 Dec 2017 17:10:16 +0100 Subject: [PATCH 0707/1332] __letsencrypt_cert: add nonparallel and make admin-email required (#609) --- cdist/conf/type/__letsencrypt_cert/man.rst | 7 ++++--- cdist/conf/type/__letsencrypt_cert/nonparallel | 0 .../type/__letsencrypt_cert/parameter/default/admin-email | 1 - cdist/conf/type/__letsencrypt_cert/parameter/optional | 1 - cdist/conf/type/__letsencrypt_cert/parameter/required | 1 + 5 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 cdist/conf/type/__letsencrypt_cert/nonparallel delete mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/default/admin-email delete mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/optional diff --git a/cdist/conf/type/__letsencrypt_cert/man.rst b/cdist/conf/type/__letsencrypt_cert/man.rst index 81a65e66..14dbac7b 100644 --- a/cdist/conf/type/__letsencrypt_cert/man.rst +++ b/cdist/conf/type/__letsencrypt_cert/man.rst @@ -17,12 +17,13 @@ REQUIRED PARAMETERS webroot The path to your webroot, as set up in your webserver config. +admin-email + Where to send Let's Encrypt emails like "certificate needs renewal". + OPTIONAL PARAMETERS ------------------- -admin-email - Where to send Let's Encrypt emails like "certificate needs renewal". Defaults to root@localhost. - +None. EXAMPLES -------- diff --git a/cdist/conf/type/__letsencrypt_cert/nonparallel b/cdist/conf/type/__letsencrypt_cert/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/default/admin-email b/cdist/conf/type/__letsencrypt_cert/parameter/default/admin-email deleted file mode 100644 index 8da2d115..00000000 --- a/cdist/conf/type/__letsencrypt_cert/parameter/default/admin-email +++ /dev/null @@ -1 +0,0 @@ -root@localhost diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/optional b/cdist/conf/type/__letsencrypt_cert/parameter/optional deleted file mode 100644 index bfe77226..00000000 --- a/cdist/conf/type/__letsencrypt_cert/parameter/optional +++ /dev/null @@ -1 +0,0 @@ -admin-email diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/required b/cdist/conf/type/__letsencrypt_cert/parameter/required index fc7c3e96..45fe4ea6 100644 --- a/cdist/conf/type/__letsencrypt_cert/parameter/required +++ b/cdist/conf/type/__letsencrypt_cert/parameter/required @@ -1 +1,2 @@ +admin-email webroot From b1d7da42584d44198a5b1eaaea86d6c726696cbc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 29 Dec 2017 17:10:23 +0100 Subject: [PATCH 0708/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 5b41a50c..618e55b0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,9 @@ next: * Explorer memory: Support OpenBSD (Philippe Gregoire) * Type __install_config: re-export cdist log level during installation (Steven Armstrong) * Type __sysctl: Add support for CoreOS (Ľubomír Kučera) + * Type __systemd_unit: Various improvements (Ľubomír Kučera) + * Type __line: Support regex beginning with '-' (Philippe Gregoire) + * Type __letsencrypt_cert: Add nonparallel; make admin-email required (Kamila Součková) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From c895be381fcd77714448ec2277b7b59dfaaddc88 Mon Sep 17 00:00:00 2001 From: Michal Hanula Date: Tue, 2 Jan 2018 18:11:37 +0100 Subject: [PATCH 0709/1332] When installing packages on freebsd, redirect stdout and stderr to /dev/null instead of closing them. Some pre/post-install scripts rely on them being open. (It would be bette to leave them open and show the output, but I didn't want to change the behaviour) --- cdist/conf/type/__package_pkgng_freebsd/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote index aa00de6a..d21e9e2a 100755 --- a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote @@ -70,7 +70,7 @@ execcmd(){ ;; esac - echo "$_cmd 2>&- >&-" # Silence the output of the command + echo "$_cmd >/dev/null 2>&1" # Silence the output of the command echo "status=\$?" echo "if [ \"\$status\" -ne \"0\" ]; then" echo " echo \"Error: ${_cmd} exited nonzero with \$status\"'!' >&2" From f278a1e31f4d0091caa0454dc5f16767ab01b71c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 3 Jan 2018 21:02:37 +0100 Subject: [PATCH 0710/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 618e55b0..8f90adc0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Type __systemd_unit: Various improvements (Ľubomír Kučera) * Type __line: Support regex beginning with '-' (Philippe Gregoire) * Type __letsencrypt_cert: Add nonparallel; make admin-email required (Kamila Součková) + * Type __package_pkgng_freebsd: Redirect stdout and stderr to /dev/null instead of closing them (michal-hanu-la) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From 00f524773e6d798b880425dac7940439b809eb8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Fri, 5 Jan 2018 22:04:13 +0100 Subject: [PATCH 0711/1332] __daemontools fixes make __daemontools more robust and clean up the --install-init-script confusion --- cdist/conf/type/__daemontools/manifest | 56 +++++++++++++------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/cdist/conf/type/__daemontools/manifest b/cdist/conf/type/__daemontools/manifest index 75f26ca0..45ce3df6 100755 --- a/cdist/conf/type/__daemontools/manifest +++ b/cdist/conf/type/__daemontools/manifest @@ -4,34 +4,36 @@ pkg=$(cat "$__object/parameter/from-package") servicedir=$(cat "$__object/parameter/servicedir") __package $pkg -__directory $servicedir --mode 755 +__directory $servicedir --mode 700 -if [ -f "$__object/parameter/install-init-script" ]; then - os=$(cat "$__global/explorer/os") - init=$(cat "$__global/explorer/init") +os=$(cat "$__global/explorer/os") +init=$(cat "$__global/explorer/init") - case $init in - init) - case $os in - freebsd) - __config_file /etc/rc.conf.d/svscan --source - <<-EOT - svscan_enable="YES" - svscan_servicedir="$servicedir" - EOT - require="$require __package/$pkg __directory/$servicedir __config_file/etc/rc.conf.d/svscan" \ - __process svscan --start 'service svscan start' - ;; - *) +case $os in + freebsd) + # TODO change to __start_on_boot once it supports freebsd + __config_file /etc/rc.conf.d/svscan --source - <<-EOT + svscan_enable="YES" + svscan_servicedir="$servicedir" + EOT + require="$require __package/$pkg __directory/$servicedir __config_file/etc/rc.conf.d/svscan" \ + __process svscan --name ".*/svscan $servicedir" --start 'service svscan start' + ;; + *) + case $init in + init) + if [ -f "$__object/parameter/install-init-script" ]; then __config_file /etc/init.d/svscan --mode 755 --source "$__type/files/init.d-svscan" - require="$require __config_file/etc/init.d/svscan" __start_on_boot svscan - require="$require __package/$pkg __directory/$servicedir __start_on_boot/svscan" \ - __process svscan --start 'service svscan start' - ;; - esac + REQUIREEXTRA="__config_file/etc/init.d/svscan" + fi + require="$require $REQUIREEXTRA" __start_on_boot svscan + require="$require __package/$pkg __directory/$servicedir __start_on_boot/svscan" \ + __process svscan --name ".*/svscan $servicedir" --start 'service svscan start' ;; - *) - echo "Your init system ($init) is not supported by this type. Submit a patch at github.com/ungleich/cdist!" - exit 1 - ;; - esac -fi + *) + echo "Your init system ($init) is not supported by this type. Submit a patch at github.com/ungleich/cdist!" + exit 1 + ;; + esac + ;; +esac From ec9ce90b8b4a737c62079b425fa0b3b4cf36f1f0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Jan 2018 08:42:52 +0100 Subject: [PATCH 0712/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8f90adc0..ea98aba7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Type __line: Support regex beginning with '-' (Philippe Gregoire) * Type __letsencrypt_cert: Add nonparallel; make admin-email required (Kamila Součková) * Type __package_pkgng_freebsd: Redirect stdout and stderr to /dev/null instead of closing them (michal-hanu-la) + * Type __daemontools: Make it more robust and clean up the code (Kamila Součková) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From 9779c8c0f8ef704c9fc9a285cccd53e617fb0f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Sat, 6 Jan 2018 17:19:27 +0100 Subject: [PATCH 0713/1332] Add cdist.egg-info/ to gitignore When installing the package in editable mode, cdist.egg-info/ is created and is necessary for editable mode to work properly. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 55374d6d..0c664232 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ __pycache__/ MANIFEST dist/ cdist/version.py +cdist.egg-info/ # sphinx build dirs, cache _build/ From 9703e0f08e979640fc1956fbe7fd2e763dde39f1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 9 Jan 2018 09:31:40 +0100 Subject: [PATCH 0714/1332] Save output streams. Implementation is 99% based on Steven's initial implementation. --- cdist/__init__.py | 76 ++++++++-- cdist/config.py | 48 +++--- cdist/core/cdist_object.py | 13 +- cdist/core/code.py | 18 ++- cdist/core/manifest.py | 30 ++-- cdist/exec/local.py | 71 +++++---- cdist/exec/remote.py | 67 ++++++--- cdist/exec/util.py | 18 ++- cdist/shell.py | 1 - cdist/test/capture_output/__init__.py | 137 ++++++++++++++++++ .../fixtures/conf/manifest/init | 4 + .../gencode-local | 6 + .../gencode-remote | 6 + .../__write_to_stdout_and_stderr/manifest | 4 + .../__write_to_stdout_and_stderr/singleton | 0 cdist/test/code/__init__.py | 7 +- cdist/test/config/__init__.py | 53 +++++-- cdist/test/exec/remote.py | 38 +++-- cdist/test/explorer/__init__.py | 4 +- cdist/test/manifest/__init__.py | 1 + docs/changelog | 1 + 21 files changed, 483 insertions(+), 120 deletions(-) create mode 100644 cdist/test/capture_output/__init__.py create mode 100755 cdist/test/capture_output/fixtures/conf/manifest/init create mode 100755 cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-local create mode 100755 cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-remote create mode 100755 cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/manifest create mode 100644 cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/singleton diff --git a/cdist/__init__.py b/cdist/__init__.py index 37651fb5..1e2c9255 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2015 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2017 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -42,7 +43,7 @@ BANNER = """ "P' "" "" """ -REMOTE_COPY = "scp -o User=root" +REMOTE_COPY = "scp -o User=root -q" REMOTE_EXEC = "ssh -o User=root" REMOTE_CMDS_CLEANUP_PATTERN = "ssh -o User=root -O exit -S {}" @@ -80,18 +81,73 @@ class CdistBetaRequired(cdist.Error): return err_msg.format(*fmt_args) -class CdistObjectError(Error): - """Something went wrong with an object""" +class CdistEntityError(Error): + """Something went wrong while executing cdist entity""" + def __init__(self, entity_name, entity_params, stderr_paths, subject=''): + self.entity_name = entity_name + self.entity_params = entity_params + self.stderr_paths = stderr_paths + if isinstance(subject, Error): + self.original_error = subject + else: + self.original_error = None + self.message = str(subject) - def __init__(self, cdist_object, message): - self.name = cdist_object.name - self.source = " ".join(cdist_object.source) - self.message = message + @property + def stderr(self): + output = [] + for stderr_name, stderr_path in self.stderr_paths: + if os.path.getsize(stderr_path) > 0: + label_begin = '---- BEGIN ' + stderr_name + ':stderr ----' + label_end = '---- END ' + stderr_name + ':stderr ----' + output.append('\n' + label_begin) + with open(stderr_path, 'r') as fd: + output.append(fd.read()) + output.append(label_end) + return '\n'.join(output) def __str__(self): - return '%s: %s (defined at %s)' % (self.name, - self.message, - self.source) + output = [] + output.append(self.message) + header = "\nError processing " + self.entity_name + under_header = '=' * len(header) + output.append(header) + output.append(under_header) + for param_name, param_value in self.entity_params: + output.append(param_name + ': ' + str(param_value)) + output.append(self.stderr + '\n') + return '\n'.join(output) + + +class CdistObjectError(CdistEntityError): + """Something went wrong while working on a specific cdist object""" + def __init__(self, cdist_object, subject=''): + params = [ + ('name', cdist_object.name, ), + ('path', cdist_object.absolute_path, ), + ('source', " ".join(cdist_object.source), ), + ('type', cdist_object.cdist_type.absolute_path, ), + ] + stderr_paths = [] + for stderr_name in os.listdir(cdist_object.stderr_path): + stderr_path = os.path.join(cdist_object.stderr_path, + stderr_name) + stderr_paths.append((stderr_name, stderr_path, )) + super().__init__("object '{}'".format(cdist_object.name), + params, stderr_paths, subject) + + +class InitialManifestError(CdistEntityError): + """Something went wrong while executing initial manifest""" + def __init__(self, initial_manifest, stderr_path, subject=''): + params = [ + ('path', initial_manifest, ), + ] + stderr_paths = [] + stderr_paths = [ + ('init', stderr_path, ), + ] + super().__init__('initial manifest', params, stderr_paths, subject) def file_to_list(filename): diff --git a/cdist/config.py b/cdist/config.py index 6ba3d0dc..dc73830c 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- # # 2010-2015 Nico Schottelius (nico-cdist at schottelius.org) +# 2013-2017 Steven Armstrong (steven-cdist at armstrong.cc) # 2016-2017 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. @@ -353,7 +354,9 @@ class Config(object): base_path=args.remote_out_path, quiet_mode=args.quiet, archiving_mode=args.use_archiving, - configuration=configuration) + configuration=configuration, + stdout_base_path=local.stdout_base_path, + stderr_base_path=local.stderr_base_path) cleanup_cmds = [] if cleanup_cmd: @@ -400,7 +403,13 @@ class Config(object): self._init_files_dirs() self.explorer.run_global_explorers(self.local.global_explorer_out_path) - self.manifest.run_initial_manifest(self.local.initial_manifest) + try: + self.manifest.run_initial_manifest(self.local.initial_manifest) + except cdist.Error as e: + which = "init" + stderr_path = os.path.join(self.local.stderr_base_path, which) + raise cdist.InitialManifestError(self.local.initial_manifest, + stderr_path, e) self.iterate_until_finished() self.cleanup() self._remove_files_dirs() @@ -453,25 +462,30 @@ class Config(object): objects_changed = False for cdist_object in self.object_list(): - if cdist_object.requirements_unfinished(cdist_object.requirements): - """We cannot do anything for this poor object""" - continue + try: + if cdist_object.requirements_unfinished( + cdist_object.requirements): + """We cannot do anything for this poor object""" + continue - if cdist_object.state == core.CdistObject.STATE_UNDEF: - """Prepare the virgin object""" + if cdist_object.state == core.CdistObject.STATE_UNDEF: + """Prepare the virgin object""" - self.object_prepare(cdist_object) - objects_changed = True + self.object_prepare(cdist_object) + objects_changed = True - if cdist_object.requirements_unfinished(cdist_object.autorequire): - """The previous step created objects we depend on - - wait for them - """ - continue + if cdist_object.requirements_unfinished( + cdist_object.autorequire): + """The previous step created objects we depend on - + wait for them + """ + continue - if cdist_object.state == core.CdistObject.STATE_PREPARED: - self.object_run(cdist_object) - objects_changed = True + if cdist_object.state == core.CdistObject.STATE_PREPARED: + self.object_run(cdist_object) + objects_changed = True + except cdist.Error as e: + raise cdist.CdistObjectError(cdist_object, e) return objects_changed diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 8c7ce635..e2cd22a2 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) # 2011-2015 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Daniel Heule (hda at sfs.biz) # @@ -80,6 +80,8 @@ class CdistObject(object): self.code_local_path = os.path.join(self.path, "code-local") self.code_remote_path = os.path.join(self.path, "code-remote") self.parameter_path = os.path.join(self.path, "parameter") + self.stdout_path = os.path.join(self.absolute_path, "stdout") + self.stderr_path = os.path.join(self.absolute_path, "stderr") @classmethod def list_objects(cls, object_base_path, type_base_path, object_marker): @@ -246,10 +248,11 @@ class CdistObject(object): """Create this cdist object on the filesystem. """ try: - os.makedirs(self.absolute_path, exist_ok=allow_overwrite) - absolute_parameter_path = os.path.join(self.base_path, - self.parameter_path) - os.makedirs(absolute_parameter_path, exist_ok=allow_overwrite) + for path in (self.absolute_path, + os.path.join(self.base_path, self.parameter_path), + self.stdout_path, + self.stderr_path): + os.makedirs(path, exist_ok=allow_overwrite) except EnvironmentError as error: raise cdist.Error(('Error creating directories for cdist object: ' '%s: %s') % (self, error)) diff --git a/cdist/core/code.py b/cdist/core/code.py index ad02e199..65d095cf 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Daniel Heule (hda at sfs.biz) # @@ -127,8 +127,13 @@ class Code(object): '__object_name': cdist_object.name, }) message_prefix = cdist_object.name - return self.local.run_script(script, env=env, return_output=True, - message_prefix=message_prefix) + stderr_path = os.path.join(cdist_object.stderr_path, + 'gencode-' + which) + with open(stderr_path, 'ba+') as stderr: + return self.local.run_script(script, env=env, + return_output=True, + message_prefix=message_prefix, + stderr=stderr) def run_gencode_local(self, cdist_object): """Run the gencode-local script for the given cdist object.""" @@ -152,7 +157,12 @@ class Code(object): which_exec = getattr(self, which) script = os.path.join(which_exec.object_path, getattr(cdist_object, 'code_%s_path' % which)) - return which_exec.run_script(script, env=env) + stderr_path = os.path.join(cdist_object.stderr_path, 'code-' + which) + stdout_path = os.path.join(cdist_object.stdout_path, 'code-' + which) + with open(stderr_path, 'ba+') as stderr, \ + open(stdout_path, 'ba+') as stdout: + return which_exec.run_script(script, env=env, stdout=stdout, + stderr=stderr) def run_code_local(self, cdist_object): """Run the code-local script for the given cdist object.""" diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index fccd3a2f..12b5b005 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. @@ -153,10 +153,16 @@ class Manifest(object): message_prefix = "initialmanifest" self.log.verbose("Running initial manifest " + initial_manifest) - self.local.run_script(initial_manifest, - env=self.env_initial_manifest(initial_manifest), - message_prefix=message_prefix, - save_output=False) + which = "init" + stderr_path = os.path.join(self.local.stderr_base_path, which) + stdout_path = os.path.join(self.local.stdout_base_path, which) + with open(stderr_path, 'ba+') as stderr, \ + open(stdout_path, 'ba+') as stdout: + self.local.run_script( + initial_manifest, + env=self.env_initial_manifest(initial_manifest), + message_prefix=message_prefix, + stdout=stdout, stderr=stderr) def env_type_manifest(self, cdist_object): type_manifest = os.path.join(self.local.type_path, @@ -178,10 +184,16 @@ class Manifest(object): type_manifest = os.path.join(self.local.type_path, cdist_object.cdist_type.manifest_path) message_prefix = cdist_object.name + which = 'manifest' if os.path.isfile(type_manifest): self.log.verbose("Running type manifest %s for object %s", type_manifest, cdist_object.name) - self.local.run_script(type_manifest, - env=self.env_type_manifest(cdist_object), - message_prefix=message_prefix, - save_output=False) + stderr_path = os.path.join(cdist_object.stderr_path, which) + stdout_path = os.path.join(cdist_object.stdout_path, which) + with open(stderr_path, 'ba+') as stderr, \ + open(stdout_path, 'ba+') as stdout: + self.local.run_script( + type_manifest, + env=self.env_type_manifest(cdist_object), + message_prefix=message_prefix, + stdout=stdout, stderr=stderr) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 8b54a142..eec79399 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) # 2011-2015 Nico Schottelius (nico-cdist at schottelius.org) # 2016-2017 Darko Poljak (darko.poljak at gmail.com) # @@ -34,7 +34,7 @@ import datetime import cdist import cdist.message from cdist import core -import cdist.exec.util as exec_util +import cdist.exec.util as util CONF_SUBDIRS_LINKED = ["explorer", "files", "manifest", "type", ] @@ -120,9 +120,11 @@ class Local(object): "explorer") self.object_path = os.path.join(self.base_path, "object") self.messages_path = os.path.join(self.base_path, "messages") - self.files_path = os.path.join(self.conf_path, "files") + self.stdout_base_path = os.path.join(self.base_path, "stdout") + self.stderr_base_path = os.path.join(self.base_path, "stderr") # Depending on conf_path + self.files_path = os.path.join(self.conf_path, "files") self.global_explorer_path = os.path.join(self.conf_path, "explorer") self.manifest_path = os.path.join(self.conf_path, "manifest") self.initial_manifest = (self.custom_initial_manifest or @@ -165,6 +167,8 @@ class Local(object): self.mkdir(self.object_path) self.mkdir(self.bin_path) self.mkdir(self.cache_path) + self.mkdir(self.stdout_base_path) + self.mkdir(self.stderr_base_path) def create_files_dirs(self): self._init_directories() @@ -200,7 +204,7 @@ class Local(object): os.makedirs(path, exist_ok=True) def run(self, command, env=None, return_output=False, message_prefix=None, - save_output=True, quiet_mode=False): + stdout=None, stderr=None, save_output=True, quiet_mode=False): """Run the given command with the given environment. Return the output as a string. @@ -208,6 +212,22 @@ class Local(object): assert isinstance(command, (list, tuple)), ( "list or tuple argument expected, got: %s" % command) + quiet = self.quiet_mode or quiet_mode + do_save_output = save_output and not quiet + + close_stdout = False + close_stderr = False + if quiet: + stderr = subprocess.DEVNULL + stdout = subprocess.DEVNULL + elif do_save_output: + if not return_output and stdout is None: + stdout = util.get_std_fd(self.stdout_base_path, 'local') + close_stdout = True + if stderr is None: + stderr = util.get_std_fd(self.stderr_base_path, 'local') + close_stderr = True + if env is None: env = os.environ.copy() # Export __target_host, __target_hostname, __target_fqdn @@ -225,39 +245,33 @@ class Local(object): self.log.trace("Local run: %s", command) try: - if self.quiet_mode or quiet_mode: - stderr = subprocess.DEVNULL + if return_output: + output = subprocess.check_output( + command, env=env, stderr=stderr).decode() else: - stderr = None - if save_output: - output, errout = exec_util.call_get_output( - command, env=env, stderr=stderr) - self.log.trace("Command: {}; local stdout: {}".format( - command, output)) - # Currently, stderr is not captured. - # self.log.trace("Local stderr: {}".format(errout)) - if return_output: - return output.decode() - else: - # In some cases no output is saved. - # This is used for shell command, stdout and stderr - # must not be catched. - if self.quiet_mode or quiet_mode: - stdout = subprocess.DEVNULL - else: - stdout = None subprocess.check_call(command, env=env, stderr=stderr, stdout=stdout) + output = None + + if do_save_output: + util.log_std_fd(self.log, command, stderr, 'Local stderr') + util.log_std_fd(self.log, command, stdout, 'Local stdout') + + return output except subprocess.CalledProcessError as e: - exec_util.handle_called_process_error(e, command) + util.handle_called_process_error(e, command) except OSError as error: raise cdist.Error(" ".join(command) + ": " + error.args[1]) finally: if message_prefix: message.merge_messages() + if close_stdout: + stdout.close() + if close_stderr: + stderr.close() def run_script(self, script, env=None, return_output=False, - message_prefix=None, save_output=True): + message_prefix=None, stdout=None, stderr=None): """Run the given script with the given environment. Return the output as a string. @@ -271,8 +285,9 @@ class Local(object): script, " ".join(command)) command.append(script) - return self.run(command=command, env=env, return_output=return_output, - message_prefix=message_prefix, save_output=save_output) + return self.run(command, env=env, return_output=return_output, + message_prefix=message_prefix, stdout=stdout, + stderr=stderr) def _cache_subpath_repl(self, matchobj): if matchobj.group(2) == '%P': diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 44bc2927..8fcd0981 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. @@ -27,7 +27,7 @@ import logging import multiprocessing import cdist -import cdist.exec.util as exec_util +import cdist.exec.util as util import cdist.util.ipaddr as ipaddr from cdist.mputil import mp_pool_run @@ -63,7 +63,9 @@ class Remote(object): base_path=None, quiet_mode=None, archiving_mode=None, - configuration=None): + configuration=None, + stdout_base_path=None, + stderr_base_path=None): self.target_host = target_host self._exec = remote_exec self._copy = remote_copy @@ -79,6 +81,9 @@ class Remote(object): else: self.configuration = {} + self.stdout_base_path = stdout_base_path + self.stderr_base_path = stderr_base_path + self.conf_path = os.path.join(self.base_path, "conf") self.object_path = os.path.join(self.base_path, "object") @@ -105,7 +110,7 @@ class Remote(object): self._open_logger() def _init_env(self): - """Setup environment for scripts - HERE????""" + """Setup environment for scripts.""" # FIXME: better do so in exec functions that require it! os.environ['__remote_copy'] = self._copy os.environ['__remote_exec'] = self._exec @@ -237,7 +242,8 @@ class Remote(object): self.log.trace(("Multiprocessing for parallel transfer " "finished")) - def run_script(self, script, env=None, return_output=False): + def run_script(self, script, env=None, return_output=False, stdout=None, + stderr=None): """Run the given script with the given environment on the remote side. Return the output as a string. @@ -249,9 +255,11 @@ class Remote(object): ] command.append(script) - return self.run(command, env, return_output) + return self.run(command, env=env, return_output=return_output, + stdout=stdout, stderr=stderr) - def run(self, command, env=None, return_output=False): + def run(self, command, env=None, return_output=False, stdout=None, + stderr=None): """Run the given command with the given environment on the remote side. Return the output as a string. @@ -284,9 +292,11 @@ class Remote(object): cmd.append(string_cmd) else: cmd.extend(command) - return self._run_command(cmd, env=env, return_output=return_output) + return self._run_command(cmd, env=env, return_output=return_output, + stdout=stdout, stderr=stderr) - def _run_command(self, command, env=None, return_output=False): + def _run_command(self, command, env=None, return_output=False, stdout=None, + stderr=None): """Run the given command with the given environment. Return the output as a string. @@ -294,6 +304,18 @@ class Remote(object): assert isinstance(command, (list, tuple)), ( "list or tuple argument expected, got: %s" % command) + if return_output and stdout is not subprocess.PIPE: + self.log.debug("return_output is True, ignoring stdout") + + close_stdout = False + close_stderr = False + if not return_output and stdout is None: + stdout = util.get_std_fd(self.stdout_base_path, 'remote') + close_stdout = True + if stderr is None: + stderr = util.get_std_fd(self.stderr_base_path, 'remote') + close_stderr = True + # export target_host, target_hostname, target_fqdn # for use in __remote_{exec,copy} scripts os_environ = os.environ.copy() @@ -305,19 +327,26 @@ class Remote(object): try: if self.quiet_mode: stderr = subprocess.DEVNULL - else: - stderr = None - output, errout = exec_util.call_get_output( - command, env=os_environ, stderr=stderr) - self.log.trace("Command: {}; remote stdout: {}".format( - command, output)) - # Currently, stderr is not captured. - # self.log.trace("Remote stderr: {}".format(errout)) if return_output: - return output.decode() + output = subprocess.check_output(command, env=os_environ, + stderr=stderr).decode() + else: + subprocess.check_call(command, env=os_environ, stdout=stdout, + stderr=stderr) + output = None + + util.log_std_fd(self.log, command, stderr, 'Remote stderr') + util.log_std_fd(self.log, command, stdout, 'Remote stdout') + + return output except subprocess.CalledProcessError as e: - exec_util.handle_called_process_error(e, command) + util.handle_called_process_error(e, command) except OSError as error: raise cdist.Error(" ".join(command) + ": " + error.args[1]) except UnicodeDecodeError: raise DecodeError(command) + finally: + if close_stdout: + stdout.close() + if close_stderr: + stderr.close() diff --git a/cdist/exec/util.py b/cdist/exec/util.py index e3c090cc..2f2aa38c 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2016 Darko Poljak (darko.poljak at gmail.com) +# 2016-2017 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -20,6 +20,7 @@ # import subprocess +import os from tempfile import TemporaryFile import cdist @@ -115,6 +116,7 @@ import cdist # return (result.stdout, result.stderr) +# Currently not used. def call_get_output(command, env=None, stderr=None): """Run the given command with the given environment. Return the tuple of stdout and stderr output as a byte strings. @@ -145,6 +147,7 @@ def handle_called_process_error(err, command): " ".join(command), err.returncode, output)) +# Currently not used. def _call_get_stdout(command, env=None, stderr=None): """Run the given command with the given environment. Return the stdout output as a byte string, stderr is ignored. @@ -158,3 +161,16 @@ def _call_get_stdout(command, env=None, stderr=None): output = fout.read() return output + + +def get_std_fd(base_path, name): + path = os.path.join(base_path, name) + stdfd = open(path, 'ba+') + return stdfd + + +def log_std_fd(log, command, stdfd, prefix): + if stdfd is not None and stdfd != subprocess.DEVNULL: + stdfd.seek(0, 0) + log.trace("Command: {}; {}: {}".format( + command, prefix, stdfd.read().decode())) diff --git a/cdist/shell.py b/cdist/shell.py index a9457aaf..60b6a9f0 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -89,7 +89,6 @@ class Shell(object): self._init_environment() log.trace("Starting shell...") - # save_output=False -> do not catch stdout and stderr self.local.run([self.shell], self.env, save_output=False) log.trace("Finished shell.") diff --git a/cdist/test/capture_output/__init__.py b/cdist/test/capture_output/__init__.py new file mode 100644 index 00000000..229cbf70 --- /dev/null +++ b/cdist/test/capture_output/__init__.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +# +# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# +# 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 . +# +# + +import os +import shutil + +import cdist +from cdist import core +from cdist import test +from cdist.exec import local +from cdist.exec import remote +from cdist.core import code +from cdist.core import manifest + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +conf_dir = op.join(fixtures, 'conf') + + +class CaptureOutputTestCase(test.CdistTestCase): + + def setUp(self): + # logging.root.setLevel(logging.TRACE) + self.temp_dir = self.mkdtemp() + + self.local_dir = os.path.join(self.temp_dir, "local") + self.hostdir = cdist.str_hash(self.target_host[0]) + self.host_base_path = os.path.join(self.local_dir, self.hostdir) + os.makedirs(self.host_base_path) + self.local = local.Local( + target_host=self.target_host, + target_host_tags=None, + base_root_path=self.host_base_path, + host_dir_name=self.hostdir, + exec_path=cdist.test.cdist_exec_path, + add_conf_dirs=[conf_dir]) + self.local.create_files_dirs() + + self.remote_dir = self.mkdtemp() + remote_exec = self.remote_exec + remote_copy = self.remote_copy + self.remote = remote.Remote( + target_host=self.target_host, + remote_exec=remote_exec, + remote_copy=remote_copy, + base_path=self.remote_dir, + stdout_base_path=self.local.stdout_base_path, + stderr_base_path=self.local.stderr_base_path) + self.remote.create_files_dirs() + + self.code = code.Code(self.target_host, self.local, self.remote) + + self.manifest = manifest.Manifest(self.target_host, self.local) + + self.cdist_type = core.CdistType(self.local.type_path, + '__write_to_stdout_and_stderr') + self.cdist_object = core.CdistObject(self.cdist_type, + self.local.object_path, + self.local.object_marker_name, + '') + self.cdist_object.create() + self.output_dirs = { + 'object': { + 'stdout': os.path.join(self.cdist_object.absolute_path, + 'stdout'), + 'stderr': os.path.join(self.cdist_object.absolute_path, + 'stderr'), + }, + 'init': { + 'stdout': os.path.join(self.local.base_path, 'stdout'), + 'stderr': os.path.join(self.local.base_path, 'stderr'), + }, + } + + def tearDown(self): + shutil.rmtree(self.local_dir) + shutil.rmtree(self.remote_dir) + shutil.rmtree(self.temp_dir) + + def _test_output(self, which, target, streams=('stdout', 'stderr')): + for stream in streams: + _should = '{0}: {1}\n'.format(which, stream) + stream_path = os.path.join(self.output_dirs[target][stream], which) + with open(stream_path, 'r') as fd: + _is = fd.read() + self.assertEqual(_should, _is) + + def test_capture_code_output(self): + self.cdist_object.code_local = self.code.run_gencode_local( + self.cdist_object) + self._test_output('gencode-local', 'object', ('stderr',)) + + self.code.run_code_local(self.cdist_object) + self._test_output('code-local', 'object') + + self.cdist_object.code_remote = self.code.run_gencode_remote( + self.cdist_object) + self._test_output('gencode-remote', 'object', ('stderr',)) + + self.code.transfer_code_remote(self.cdist_object) + self.code.run_code_remote(self.cdist_object) + self._test_output('code-remote', 'object') + + def test_capture_manifest_output(self): + self.manifest.run_type_manifest(self.cdist_object) + self._test_output('manifest', 'object') + + def test_capture_init_manifest_output(self): + initial_manifest = os.path.join(conf_dir, 'manifest', 'init') + self.manifest.run_initial_manifest(initial_manifest) + self._test_output('init', 'init') + + +if __name__ == "__main__": + import unittest + + unittest.main() diff --git a/cdist/test/capture_output/fixtures/conf/manifest/init b/cdist/test/capture_output/fixtures/conf/manifest/init new file mode 100755 index 00000000..68d7da97 --- /dev/null +++ b/cdist/test/capture_output/fixtures/conf/manifest/init @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "init: stdout" +echo "init: stderr" >&2 diff --git a/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-local b/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-local new file mode 100755 index 00000000..1946dbd3 --- /dev/null +++ b/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-local @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "gencode-local: stderr" >&2 + +echo "echo \"code-local: stdout\"" +echo "echo \"code-local: stderr\" >&2" diff --git a/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-remote b/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-remote new file mode 100755 index 00000000..f713b932 --- /dev/null +++ b/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-remote @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "gencode-remote: stderr" >&2 + +echo "echo \"code-remote: stdout\"" +echo "echo \"code-remote: stderr\" >&2" diff --git a/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/manifest b/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/manifest new file mode 100755 index 00000000..4f122f25 --- /dev/null +++ b/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/manifest @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "manifest: stdout" +echo "manifest: stderr" >&2 diff --git a/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/singleton b/cdist/test/capture_output/fixtures/conf/type/__write_to_stdout_and_stderr/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index c1d19d33..bf80110d 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) # 2012-2015 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. @@ -61,7 +61,9 @@ class CodeTestCase(test.CdistTestCase): target_host=self.target_host, remote_exec=remote_exec, remote_copy=remote_copy, - base_path=self.remote_dir) + base_path=self.remote_dir, + stdout_base_path=self.local.stdout_base_path, + stderr_base_path=self.local.stderr_base_path) self.remote.create_files_dirs() self.code = code.Code(self.target_host, self.local, self.remote) @@ -152,6 +154,7 @@ class CodeTestCase(test.CdistTestCase): self.code.transfer_code_remote(self.cdist_object) self.code.run_code_remote(self.cdist_object) + if __name__ == '__main__': import unittest unittest.main() diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index 252b7c8f..2b0d8b5f 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2010-2017 Steven Armstrong (steven-cdist at armstrong.cc) # 2012-2015 Nico Schottelius (nico-cdist at schottelius.org) # 2014 Daniel Heule (hda at sfs.biz) # @@ -45,6 +45,19 @@ expected_object_names = sorted([ '__third/moon']) +class CdistObjectErrorContext(object): + def __init__(self, original_error): + self.original_error = original_error + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + if exc_type is not None: + if exc_value.original_error: + raise exc_value.original_error + + class ConfigRunTestCase(test.CdistTestCase): def setUp(self): @@ -87,7 +100,9 @@ class ConfigRunTestCase(test.CdistTestCase): target_host=self.target_host, remote_copy=self.remote_copy, remote_exec=self.remote_exec, - base_path=self.remote_dir) + base_path=self.remote_dir, + stdout_base_path=self.local.stdout_base_path, + stderr_base_path=self.local.stderr_base_path) self.local.object_path = self.object_base_path self.local.type_path = type_base_path @@ -102,6 +117,20 @@ class ConfigRunTestCase(test.CdistTestCase): os.environ = self.orig_environ shutil.rmtree(self.temp_dir) + def assertRaisesCdistObjectError(self, original_error, callable_obj): + """ + Test if a raised CdistObjectError was caused by the given + original_error. + """ + with self.assertRaises(original_error): + try: + callable_obj() + except cdist.CdistObjectError as e: + if e.original_error: + raise e.original_error + else: + raise + def test_dependency_resolution(self): first = self.object_index['__first/man'] second = self.object_index['__second/on-the'] @@ -137,29 +166,33 @@ class ConfigRunTestCase(test.CdistTestCase): first.requirements = [second.name] second.requirements = [first.name] - with self.assertRaises(cdist.UnresolvableRequirementsError): - self.config.iterate_until_finished() + self.assertRaisesCdistObjectError( + cdist.UnresolvableRequirementsError, + self.config.iterate_until_finished) def test_missing_requirements(self): """Throw an error if requiring something non-existing""" first = self.object_index['__first/man'] first.requirements = ['__first/not/exist'] - with self.assertRaises(cdist.UnresolvableRequirementsError): - self.config.iterate_until_finished() + self.assertRaisesCdistObjectError( + cdist.UnresolvableRequirementsError, + self.config.iterate_until_finished) def test_requirement_broken_type(self): """Unknown type should be detected in the resolving process""" first = self.object_index['__first/man'] first.requirements = ['__nosuchtype/not/exist'] - with self.assertRaises(cdist.core.cdist_type.InvalidTypeError): - self.config.iterate_until_finished() + self.assertRaisesCdistObjectError( + cdist.core.cdist_type.InvalidTypeError, + self.config.iterate_until_finished) def test_requirement_singleton_where_no_singleton(self): """Missing object id should be detected in the resolving process""" first = self.object_index['__first/man'] first.requirements = ['__first'] - with self.assertRaises(cdist.core.cdist_object.MissingObjectIdError): - self.config.iterate_until_finished() + self.assertRaisesCdistObjectError( + cdist.core.cdist_object.MissingObjectIdError, + self.config.iterate_until_finished) def test_dryrun(self): """Test if the dryrun option is working like expected""" diff --git a/cdist/test/exec/remote.py b/cdist/test/exec/remote.py index 5137c59c..a7fe384d 100644 --- a/cdist/test/exec/remote.py +++ b/cdist/test/exec/remote.py @@ -40,12 +40,24 @@ class RemoteTestCase(test.CdistTestCase): ) # another temp dir for remote base path self.base_path = self.mkdtemp() + self.remote = self.create_remote() + + def create_remote(self, *args, **kwargs): + if not args: + args = (self.target_host,) + kwargs.setdefault('base_path', self.base_path) user = getpass.getuser() - remote_exec = "ssh -o User=%s -q" % user - remote_copy = "scp -o User=%s -q" % user - self.remote = remote.Remote(self.target_host, base_path=self.base_path, - remote_exec=remote_exec, - remote_copy=remote_copy) + kwargs.setdefault('remote_exec', 'ssh -o User=%s -q' % user) + kwargs.setdefault('remote_copy', 'scp -o User=%s -q' % user) + if 'stdout_base_path' not in kwargs: + stdout_path = os.path.join(self.temp_dir, 'stdout') + os.makedirs(stdout_path, exist_ok=True) + kwargs['stdout_base_path'] = stdout_path + if 'stderr_base_path' not in kwargs: + stderr_path = os.path.join(self.temp_dir, 'stderr') + os.makedirs(stderr_path, exist_ok=True) + kwargs['stderr_base_path'] = stderr_path + return remote.Remote(*args, **kwargs) def tearDown(self): shutil.rmtree(self.temp_dir) @@ -155,8 +167,8 @@ class RemoteTestCase(test.CdistTestCase): os.chmod(remote_exec_path, 0o755) remote_exec = remote_exec_path remote_copy = "echo" - r = remote.Remote(self.target_host, base_path=self.base_path, - remote_exec=remote_exec, remote_copy=remote_copy) + r = self.create_remote(remote_exec=remote_exec, + remote_copy=remote_copy) self.assertEqual(r.run('true', return_output=True), "%s\n" % self.target_host[0]) @@ -167,8 +179,8 @@ class RemoteTestCase(test.CdistTestCase): os.chmod(remote_exec_path, 0o755) remote_exec = remote_exec_path remote_copy = "echo" - r = remote.Remote(self.target_host, base_path=self.base_path, - remote_exec=remote_exec, remote_copy=remote_copy) + r = self.create_remote(remote_exec=remote_exec, + remote_copy=remote_copy) handle, script = self.mkstemp(dir=self.temp_dir) with os.fdopen(handle, "w") as fd: fd.writelines(["#!/bin/sh\n", "true"]) @@ -189,8 +201,8 @@ class RemoteTestCase(test.CdistTestCase): os.chmod(remote_exec_path, 0o755) remote_exec = remote_exec_path remote_copy = "echo" - r = remote.Remote(self.target_host, base_path=self.base_path, - remote_exec=remote_exec, remote_copy=remote_copy) + r = self.create_remote(remote_exec=remote_exec, + remote_copy=remote_copy) output = r.run_script(script, return_output=True) self.assertEqual(output, "no_env\n") @@ -202,8 +214,8 @@ class RemoteTestCase(test.CdistTestCase): env = { '__object': 'test_object', } - r = remote.Remote(self.target_host, base_path=self.base_path, - remote_exec=remote_exec, remote_copy=remote_copy) + r = self.create_remote(remote_exec=remote_exec, + remote_copy=remote_copy) output = r.run_script(script, env=env, return_output=True) self.assertEqual(output, "test_object\n") diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index dcdd91f1..1c4e4bc4 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -64,7 +64,9 @@ class ExplorerClassTestCase(test.CdistTestCase): target_host=self.target_host, remote_exec=self.remote_exec, remote_copy=self.remote_copy, - base_path=self.remote_base_path) + base_path=self.remote_base_path, + stdout_base_path=self.local.stdout_base_path, + stderr_base_path=self.local.stderr_base_path) self.remote.create_files_dirs() self.explorer = explorer.Explorer( diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index fffa77b8..68e777a4 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -109,6 +109,7 @@ class ManifestTestCase(test.CdistTestCase): cdist_object = core.CdistObject(cdist_type, self.local.object_path, self.local.object_marker_name, 'whatever') + cdist_object.create() handle, output_file = self.mkstemp(dir=self.temp_dir) os.close(handle) os.environ['__cdist_test_out'] = output_file diff --git a/docs/changelog b/docs/changelog index ea98aba7..23b01635 100644 --- a/docs/changelog +++ b/docs/changelog @@ -11,6 +11,7 @@ next: * Type __letsencrypt_cert: Add nonparallel; make admin-email required (Kamila Součková) * Type __package_pkgng_freebsd: Redirect stdout and stderr to /dev/null instead of closing them (michal-hanu-la) * Type __daemontools: Make it more robust and clean up the code (Kamila Součková) + * Core: Save output streams (Steven Armstrong, Darko Poljak) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From 7558af17072aa266ee6d30a574e9722027903ea4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 14 Jan 2018 10:03:57 +0100 Subject: [PATCH 0715/1332] Add local cache overview docs. --- docs/src/cdist-cache.rst | 96 ++++++++++++++++++++++++++++++++++++++++ docs/src/index.rst | 1 + docs/src/man1/cdist.rst | 2 + 3 files changed, 99 insertions(+) create mode 100644 docs/src/cdist-cache.rst diff --git a/docs/src/cdist-cache.rst b/docs/src/cdist-cache.rst new file mode 100644 index 00000000..b4335db9 --- /dev/null +++ b/docs/src/cdist-cache.rst @@ -0,0 +1,96 @@ +Local cache overview +==================== + +Description +----------- +While executing, cdist stores data to local cache. Currently this feature is +one way only. That means that cdist does not use stored data for future runs. +Anyway, those data can be used for debugging cdist, debugging types and +debugging after host configuration fails. + +Local cache is saved under $HOME/.cdist/cache directory, one directory entry +for each host. Subdirectory path is specified by +:strong:`-C/--cache-path-pattern` option, :strong:`cache_path_pattern` +configuration option or by using :strong:`CDIST_CACHE_PATH_PATTERN` +environment variable. + +For more info on cache path pattern see :strong:`CACHE PATH PATTERN FORMAT` +section in cdist man page. + + +Cache overview +-------------- +As noted above each configured host has got its subdirectory in local cache. +Entries in host's cache directory are as follows. + +bin + directory with cdist type emulators + +conf + dynamically determined cdist conf directory, union of all specified + conf directories + +explorer + directory containing global explorer named files containing explorer output + after running on target host + +messages + file containing messages + +object + directory containing subdirectory for each cdist object + +object_marker + object marker for this particular cdist run + +stderr + directory containing init manifest and remote stderr stream output + +stdout + directory containing init manifest and remote stdout stream output + +target_host + file containing target host of this cdist run, as specified when running + cdist + +typeorder + file containing types in order of execution. + + +Object cache overview +~~~~~~~~~~~~~~~~~~~~~ +Each object under :strong:`object` directory has its own structurue. + +code-local + code generated from gencode-local, present only if something is + generated + +code-remote + code generated from gencode-remote, present only if something is + generated + +explorer + directory containing type explorer named files containing explorer output + after running on target host + +files + directory with object files created during type execution + +parameter + directory containing type parameter named files containing parameter + values + +source + this type's source (init manifest) + +state + this type execution state ('done' when finished) + +stderr + directory containing type's gencode-* and code-* stderr stream outputs + +stdin + this type stdin content + +stdout + directory containing type's gencode-* and code-* stdout stream outputs. diff --git a/docs/src/index.rst b/docs/src/index.rst index d662fd73..efbc3cb9 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -30,6 +30,7 @@ Contents: cdist-reference cdist-best-practice cdist-stages + cdist-cache cdist-remote-exec-copy cdist-hacker cdist-troubleshooting diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 3ca0cb8c..ea66c37e 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -571,6 +571,8 @@ FILES ~/.cdist Your personal cdist config directory. If exists it will be automatically used. +~/.cdist/cache + Local cache directory. ~/.cdist/inventory The home inventory directory. If ~/.cdist exists it will be used as default inventory directory. From fd6337bb09f2c701e25206907d5419ea15459e82 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 14 Jan 2018 10:22:57 +0100 Subject: [PATCH 0716/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 23b01635..555481d5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -12,6 +12,7 @@ next: * Type __package_pkgng_freebsd: Redirect stdout and stderr to /dev/null instead of closing them (michal-hanu-la) * Type __daemontools: Make it more robust and clean up the code (Kamila Součková) * Core: Save output streams (Steven Armstrong, Darko Poljak) + * Documentation: Add local cache overview (Darko Poljak) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From dd188ca5884fa4a030b1bee73c94a20f5bab3c4c Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Fri, 19 Jan 2018 22:06:37 +0100 Subject: [PATCH 0717/1332] Handle stdin to __systemd_unit correctly When directly piping in the source of a systemd unit file, cdist errored out. This is due to not propagating the stdin file to the underlying __config_file type (which already contains code for this case, but this has to be duplicated in __systemd_unit). The following example thus works: __systemd_unit test.service --source - < Date: Sun, 21 Jan 2018 12:21:41 +0100 Subject: [PATCH 0718/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 555481d5..8f1de875 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,7 @@ next: * Type __daemontools: Make it more robust and clean up the code (Kamila Součková) * Core: Save output streams (Steven Armstrong, Darko Poljak) * Documentation: Add local cache overview (Darko Poljak) + * Type __systemd_unit: Fix handling stdin (Jonas Weber) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From 3545d0157f7fdb3a398324946fa7ca1f2c1edd69 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Tue, 30 Jan 2018 12:04:19 +0100 Subject: [PATCH 0719/1332] Provide `--purge-if-absent` to __package_apt Configuration files are not purged under Debian when the package is deinstalled. If this parameter is given, they are deleted upon package deinstallation. --- cdist/conf/type/__package_apt/gencode-remote | 7 ++++++- cdist/conf/type/__package_apt/man.rst | 3 +++ cdist/conf/type/__package_apt/parameter/boolean | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 cdist/conf/type/__package_apt/parameter/boolean diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index e3e31c2b..1a86e72c 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -35,6 +35,11 @@ else target_release="" fi +if [ -f "$__object/parameter/purge-if-absent" ]; then + purgeparam="--purge" +else + purgeparam="" +fi # FIXME: use grep directly, state is a list, not a line! @@ -57,7 +62,7 @@ case "$state_should" in echo $aptget install $target_release \"$name\" ;; absent) - echo $aptget remove \"$name\" + echo $aptget remove $purgeparam \"$name\" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_apt/man.rst b/cdist/conf/type/__package_apt/man.rst index 0a7958d4..991962e5 100644 --- a/cdist/conf/type/__package_apt/man.rst +++ b/cdist/conf/type/__package_apt/man.rst @@ -28,6 +28,9 @@ state target-release Passed on to apt-get install, see apt-get(8). Essentially allows you to retrieve packages from a different release +purge-if-absent + If this parameter is given when state is `absent`, the package is + purged from the system (using `--purge`). EXAMPLES -------- diff --git a/cdist/conf/type/__package_apt/parameter/boolean b/cdist/conf/type/__package_apt/parameter/boolean new file mode 100644 index 00000000..f9a0f6b0 --- /dev/null +++ b/cdist/conf/type/__package_apt/parameter/boolean @@ -0,0 +1 @@ +purge-if-absent From 27d38a28abfe79657828953c365b62bd1ab14a55 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 30 Jan 2018 13:16:29 +0100 Subject: [PATCH 0720/1332] __package_update_index: optional `--maxage `-parameter for apt `--maxage 3600` ensures that `apt-get --quiet update` is only done if the previous run was at least 1 hour ago. This also adds messaging --- .../__package_update_index/explorer/currage | 15 ++++++++++++++ .../__package_update_index/gencode-remote | 20 ++++++++++++++++++- .../conf/type/__package_update_index/man.rst | 10 +++++++++- .../__package_update_index/parameter/optional | 1 + 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 cdist/conf/type/__package_update_index/explorer/currage diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage new file mode 100644 index 00000000..bd53a789 --- /dev/null +++ b/cdist/conf/type/__package_update_index/explorer/currage @@ -0,0 +1,15 @@ +#!/bin/sh -e + +os="$("$__explorer/os")" + +case "$os" in + debian|ubuntu|devuan) + if [ -f "/var/cache/apt/pkgcache.bin" ]; then + echo $(($(date +"%s")-$(stat --format '%Y' /var/cache/apt/pkgcache.bin))) + else + echo 0 + fi + ;; + *) ## not supported $os + ;; +esac diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index 20beed5b..d84e7953 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -22,6 +22,10 @@ # type="$__object/parameter/type" +if [ -f "$__object/parameter/maxage" ]; then + maxage="$(cat "$__object/parameter/maxage")" + currage="$(cat "$__object/explorer/currage")" +fi if [ -f "$type" ]; then type="$(cat "$type")" @@ -39,9 +43,23 @@ else esac fi +if [ -n "$maxage" ] && [ "$type" != "apt" ]; then + echo "ERROR: \"--maxage\" only supported for \"apt\" pkg-manager." >&2 + exit 1 +fi + case "$type" in yum) ;; - apt) echo "apt-get --quiet update" ;; + apt) if [ -n "$maxage" ]; then + ## check if we need to update: + if [ $currage -ge $maxage ]; then + echo "apt-get --quiet update" + fi + else + echo "apt-get --quiet update" + fi + echo "apt-cache updated (age was: $currage)" >> "$__messages_out" + ;; pacman) echo "pacman --noprogressbar --sync --refresh" ;; *) echo "Don't know how to manage packages on: $os" >&2 diff --git a/cdist/conf/type/__package_update_index/man.rst b/cdist/conf/type/__package_update_index/man.rst index 454aa05b..ac954faa 100644 --- a/cdist/conf/type/__package_update_index/man.rst +++ b/cdist/conf/type/__package_update_index/man.rst @@ -27,6 +27,9 @@ type * yum for Red Hat * pacman for Arch Linux +maxage + Available for package manager apt, max time in seconds since last update. + Repo update is skipped if maxage is not reached yet. EXAMPLES -------- @@ -39,10 +42,15 @@ EXAMPLES # Force use of a specific package manager __package_update_index --type apt + # Only update every hour: + __package_update_index --maxage 3600 --type apt + # same as avove (on apt-type systems): + __package_update_index --maxage 3600 AUTHORS ------- -Ricardo Catalinas Jiménez +| Ricardo Catalinas Jiménez +| Thomas Eckert COPYING diff --git a/cdist/conf/type/__package_update_index/parameter/optional b/cdist/conf/type/__package_update_index/parameter/optional index aa80e646..7a0be716 100644 --- a/cdist/conf/type/__package_update_index/parameter/optional +++ b/cdist/conf/type/__package_update_index/parameter/optional @@ -1 +1,2 @@ type +maxage From 2dc5550fa4f6fb4acb20e6fc2a8a8ef996aa6221 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 30 Jan 2018 13:24:28 +0100 Subject: [PATCH 0721/1332] __package_update_index: update man-page w/ `--magage` and MESSAGING --- cdist/conf/type/__package_update_index/man.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_update_index/man.rst b/cdist/conf/type/__package_update_index/man.rst index ac954faa..b63af654 100644 --- a/cdist/conf/type/__package_update_index/man.rst +++ b/cdist/conf/type/__package_update_index/man.rst @@ -31,6 +31,13 @@ maxage Available for package manager apt, max time in seconds since last update. Repo update is skipped if maxage is not reached yet. +MESSAGES +-------- +apt-cache updated (age was: currage) + apt-cache was updated (run of `apt-get update`). `currage` is the time + in seconds since the previous run. + + EXAMPLES -------- @@ -44,7 +51,7 @@ EXAMPLES # Only update every hour: __package_update_index --maxage 3600 --type apt - # same as avove (on apt-type systems): + # same as above (on apt-type systems): __package_update_index --maxage 3600 AUTHORS From 179c5a2dfee051dcac544b3070a0e8fbfea98494 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 30 Jan 2018 13:16:29 +0100 Subject: [PATCH 0722/1332] __package_update_index: optional `--maxage `-parameter for apt `--maxage 3600` ensures that `apt-get --quiet update` is only done if the previous run was at least 1 hour ago. This also adds messaging --- .../__package_update_index/explorer/currage | 15 ++++++++++++++ .../__package_update_index/gencode-remote | 20 ++++++++++++++++++- .../conf/type/__package_update_index/man.rst | 10 +++++++++- .../__package_update_index/parameter/optional | 1 + 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 cdist/conf/type/__package_update_index/explorer/currage diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage new file mode 100644 index 00000000..bd53a789 --- /dev/null +++ b/cdist/conf/type/__package_update_index/explorer/currage @@ -0,0 +1,15 @@ +#!/bin/sh -e + +os="$("$__explorer/os")" + +case "$os" in + debian|ubuntu|devuan) + if [ -f "/var/cache/apt/pkgcache.bin" ]; then + echo $(($(date +"%s")-$(stat --format '%Y' /var/cache/apt/pkgcache.bin))) + else + echo 0 + fi + ;; + *) ## not supported $os + ;; +esac diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index 20beed5b..d84e7953 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -22,6 +22,10 @@ # type="$__object/parameter/type" +if [ -f "$__object/parameter/maxage" ]; then + maxage="$(cat "$__object/parameter/maxage")" + currage="$(cat "$__object/explorer/currage")" +fi if [ -f "$type" ]; then type="$(cat "$type")" @@ -39,9 +43,23 @@ else esac fi +if [ -n "$maxage" ] && [ "$type" != "apt" ]; then + echo "ERROR: \"--maxage\" only supported for \"apt\" pkg-manager." >&2 + exit 1 +fi + case "$type" in yum) ;; - apt) echo "apt-get --quiet update" ;; + apt) if [ -n "$maxage" ]; then + ## check if we need to update: + if [ $currage -ge $maxage ]; then + echo "apt-get --quiet update" + fi + else + echo "apt-get --quiet update" + fi + echo "apt-cache updated (age was: $currage)" >> "$__messages_out" + ;; pacman) echo "pacman --noprogressbar --sync --refresh" ;; *) echo "Don't know how to manage packages on: $os" >&2 diff --git a/cdist/conf/type/__package_update_index/man.rst b/cdist/conf/type/__package_update_index/man.rst index 454aa05b..ac954faa 100644 --- a/cdist/conf/type/__package_update_index/man.rst +++ b/cdist/conf/type/__package_update_index/man.rst @@ -27,6 +27,9 @@ type * yum for Red Hat * pacman for Arch Linux +maxage + Available for package manager apt, max time in seconds since last update. + Repo update is skipped if maxage is not reached yet. EXAMPLES -------- @@ -39,10 +42,15 @@ EXAMPLES # Force use of a specific package manager __package_update_index --type apt + # Only update every hour: + __package_update_index --maxage 3600 --type apt + # same as avove (on apt-type systems): + __package_update_index --maxage 3600 AUTHORS ------- -Ricardo Catalinas Jiménez +| Ricardo Catalinas Jiménez +| Thomas Eckert COPYING diff --git a/cdist/conf/type/__package_update_index/parameter/optional b/cdist/conf/type/__package_update_index/parameter/optional index aa80e646..7a0be716 100644 --- a/cdist/conf/type/__package_update_index/parameter/optional +++ b/cdist/conf/type/__package_update_index/parameter/optional @@ -1 +1,2 @@ type +maxage From e31de114e35ee1642d8944d354d58b4b0b46e2b8 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 30 Jan 2018 13:24:28 +0100 Subject: [PATCH 0723/1332] __package_update_index: update man-page w/ `--magage` and MESSAGING --- cdist/conf/type/__package_update_index/man.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_update_index/man.rst b/cdist/conf/type/__package_update_index/man.rst index ac954faa..b63af654 100644 --- a/cdist/conf/type/__package_update_index/man.rst +++ b/cdist/conf/type/__package_update_index/man.rst @@ -31,6 +31,13 @@ maxage Available for package manager apt, max time in seconds since last update. Repo update is skipped if maxage is not reached yet. +MESSAGES +-------- +apt-cache updated (age was: currage) + apt-cache was updated (run of `apt-get update`). `currage` is the time + in seconds since the previous run. + + EXAMPLES -------- @@ -44,7 +51,7 @@ EXAMPLES # Only update every hour: __package_update_index --maxage 3600 --type apt - # same as avove (on apt-type systems): + # same as above (on apt-type systems): __package_update_index --maxage 3600 AUTHORS From cb21b3679a6f23b2a97e5bb2b7f8c6d19b38fe4c Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 31 Jan 2018 09:22:19 +0100 Subject: [PATCH 0724/1332] add missing legal boilerplate to explorer --- .../__package_update_index/explorer/currage | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage index bd53a789..543d1b29 100644 --- a/cdist/conf/type/__package_update_index/explorer/currage +++ b/cdist/conf/type/__package_update_index/explorer/currage @@ -1,4 +1,21 @@ -#!/bin/sh -e +#!/bin/sh +# +# 2018 Thomas Eckert (tom at it-eckert.de) +# +# 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 . os="$("$__explorer/os")" From 6a6fdac25dc56a86f9d4db9b2c1f33d95aefac8c Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 31 Jan 2018 10:37:30 +0100 Subject: [PATCH 0725/1332] add error-message if OS is unsuppored; fix indentation --- .../__package_update_index/explorer/currage | 39 ++++++------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage index 543d1b29..c2742b6d 100644 --- a/cdist/conf/type/__package_update_index/explorer/currage +++ b/cdist/conf/type/__package_update_index/explorer/currage @@ -1,32 +1,17 @@ -#!/bin/sh -# -# 2018 Thomas Eckert (tom at it-eckert.de) -# -# 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 . +#!/bin/sh -e os="$("$__explorer/os")" case "$os" in - debian|ubuntu|devuan) - if [ -f "/var/cache/apt/pkgcache.bin" ]; then - echo $(($(date +"%s")-$(stat --format '%Y' /var/cache/apt/pkgcache.bin))) - else - echo 0 - fi - ;; - *) ## not supported $os - ;; + debian|ubuntu|devuan) + if [ -f "/var/cache/apt/pkgcache.bin" ]; then + echo $(($(date +"%s")-$(stat --format '%Y' /var/cache/apt/pkgcache.bin))) + else + echo 0 + fi + ;; + *) echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; esac From fa91dbfcdbb57673ca87090b8a3834d6cbffd816 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 31 Jan 2018 11:08:39 +0100 Subject: [PATCH 0726/1332] (re-) copyright msg --- .../__package_update_index/explorer/currage | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage index c2742b6d..cd042bd5 100644 --- a/cdist/conf/type/__package_update_index/explorer/currage +++ b/cdist/conf/type/__package_update_index/explorer/currage @@ -1,4 +1,21 @@ -#!/bin/sh -e +#!/bin/sh +# +# 2018 Thomas Eckert (tom at it-eckert.de) +# +# 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 . os="$("$__explorer/os")" From 2069650e74a523ee32f2017b5dcdfc8038e6e007 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Wed, 31 Jan 2018 12:03:21 +0000 Subject: [PATCH 0727/1332] Allow filling __issue from stdin closes #130 --- cdist/conf/type/__issue/manifest | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdist/conf/type/__issue/manifest b/cdist/conf/type/__issue/manifest index 06eb120a..0f0b3d83 100755 --- a/cdist/conf/type/__issue/manifest +++ b/cdist/conf/type/__issue/manifest @@ -25,6 +25,9 @@ os="$(cat "$__global/explorer/os")" if [ -f "$__object/parameter/source" ]; then source="$(cat "$__object/parameter/source")" + if [ "$source" = "-" ]; then + source="${__object}/stdin" + fi else case "$os" in archlinux|redhat) From bfde7a6cfaef95cb3a4b87b74da1ad076d950843 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Wed, 31 Jan 2018 12:10:37 +0000 Subject: [PATCH 0728/1332] Allow __motd to read from stdin --- cdist/conf/type/__motd/manifest | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdist/conf/type/__motd/manifest b/cdist/conf/type/__motd/manifest index 0e2e8097..cd741cf4 100755 --- a/cdist/conf/type/__motd/manifest +++ b/cdist/conf/type/__motd/manifest @@ -22,6 +22,9 @@ # Select motd source if [ -f "$__object/parameter/source" ]; then source="$(cat "$__object/parameter/source")" + if [ "$source" = "-" ]; then + source="${__object}/stdin" + fi else source="$__type/files/motd" fi From fdc7060f4839853d712e16ee1759831c30c54ac4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 31 Jan 2018 13:56:31 +0100 Subject: [PATCH 0729/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 8f1de875..629d5897 100644 --- a/docs/changelog +++ b/docs/changelog @@ -14,6 +14,8 @@ next: * Core: Save output streams (Steven Armstrong, Darko Poljak) * Documentation: Add local cache overview (Darko Poljak) * Type __systemd_unit: Fix handling stdin (Jonas Weber) + * Type __package_apt: Add --purge-if-absent parameter (Jonas Weber) + * Type __package_update_index: Add --maxage parameter for apt and add message if index was updated(Thomas Eckert) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From fe8004eca2e7c3b89f968804f47a014e85b34f81 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 31 Jan 2018 20:11:39 +0100 Subject: [PATCH 0730/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 629d5897..3d51424b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -16,6 +16,8 @@ next: * Type __systemd_unit: Fix handling stdin (Jonas Weber) * Type __package_apt: Add --purge-if-absent parameter (Jonas Weber) * Type __package_update_index: Add --maxage parameter for apt and add message if index was updated(Thomas Eckert) + * Type __motd: Support reading from stdin (Jonas Weber) + * Type __issue: Support reading from stdin (Jonas Weber) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From d6ff07715681fa8600d386daf1128518791102bc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 31 Jan 2018 09:48:16 +0100 Subject: [PATCH 0731/1332] __package_apt ignores --version parameter #615 --- cdist/conf/type/__package_apt/explorer/state | 3 ++- cdist/conf/type/__package_apt/gencode-remote | 20 +++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__package_apt/explorer/state b/cdist/conf/type/__package_apt/explorer/state index 04926b60..658429ac 100755 --- a/cdist/conf/type/__package_apt/explorer/state +++ b/cdist/conf/type/__package_apt/explorer/state @@ -31,7 +31,8 @@ fi packages="$(apt-cache showpkg "$name" | sed -e "1,/Reverse Provides:/d" | cut -d ' ' -f 1) $name" for p in $packages; do if [ -n "$(dpkg -s "$p" 2>/dev/null | grep "^Status: install ok installed$")" ]; then - echo "present $p" + version=$(dpkg -s "$p" 2>/dev/null | grep "^Version:" | cut -d ' ' -f 2) + echo "present $p $version" exit 0 fi done diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index 1a86e72c..d9cc52b7 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -29,6 +29,13 @@ fi state_should="$(cat "$__object/parameter/state")" +version_param="$__object/parameter/version" + +version="" +if [ -f "$version_param" ]; then + version="$(cat "$version_param")" +fi + if [ -f "$__object/parameter/target-release" ]; then target_release="--target-release $(cat "$__object/parameter/target-release")" else @@ -47,18 +54,29 @@ state_is="$(cat "$__object/explorer/state")" case "$state_is" in present*) name="$(echo "$state_is" | cut -d ' ' -f 2)" + version_is="$(echo "$state_is" | cut -d ' ' -f 3)" state_is="present" ;; + *) + version_is="" + ;; esac # Hint if we need to avoid questions at some point: # DEBIAN_PRIORITY=critical can reduce the number of questions aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes --no-install-recommends -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\"" -[ "$state_is" = "$state_should" ] && exit 0 +if [ "$state_is" = "$state_should" ]; then + if [ -z "$version" ] || [ "$version" = "$version_is" ]; then + exit 0; + fi +fi case "$state_should" in present) + if [ -n "$version" ]; then + name="${name}=${version}" + fi echo $aptget install $target_release \"$name\" ;; absent) From fe7da4d8b34a3326e0e9ed980288c7252b2b83a4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 31 Jan 2018 20:21:48 +0100 Subject: [PATCH 0732/1332] Update man page. --- cdist/conf/type/__package_apt/man.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cdist/conf/type/__package_apt/man.rst b/cdist/conf/type/__package_apt/man.rst index 991962e5..a3a70d91 100644 --- a/cdist/conf/type/__package_apt/man.rst +++ b/cdist/conf/type/__package_apt/man.rst @@ -28,10 +28,19 @@ state target-release Passed on to apt-get install, see apt-get(8). Essentially allows you to retrieve packages from a different release + +version + The version of the package to install. Default is to install the version + chosen by the local package manager. + + +BOOLEAN PARAMETERS +------------------ purge-if-absent If this parameter is given when state is `absent`, the package is purged from the system (using `--purge`). + EXAMPLES -------- From c76637242f13d60a16bbdba4ee4226211349b86b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 31 Jan 2018 20:23:52 +0100 Subject: [PATCH 0733/1332] ++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 3d51424b..e00d01bc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -18,6 +18,7 @@ next: * Type __package_update_index: Add --maxage parameter for apt and add message if index was updated(Thomas Eckert) * Type __motd: Support reading from stdin (Jonas Weber) * Type __issue: Support reading from stdin (Jonas Weber) + * Type __package_apt: Add support for --version parameter (Darko Poljak) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From 47399bfa9f5f32c26040e1b3030a65a70b93c40f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 5 Feb 2018 13:57:53 +0100 Subject: [PATCH 0734/1332] Add --renew-hook param to letsencrypt_cert type. --- cdist/conf/type/__letsencrypt_cert/man.rst | 13 +++++++++++-- cdist/conf/type/__letsencrypt_cert/manifest | 9 ++++++++- .../__letsencrypt_cert/parameter/optional_multiple | 1 + docs/changelog | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/optional_multiple diff --git a/cdist/conf/type/__letsencrypt_cert/man.rst b/cdist/conf/type/__letsencrypt_cert/man.rst index 14dbac7b..9b487d01 100644 --- a/cdist/conf/type/__letsencrypt_cert/man.rst +++ b/cdist/conf/type/__letsencrypt_cert/man.rst @@ -25,23 +25,32 @@ OPTIONAL PARAMETERS ------------------- None. + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- +renew-hook + Renew hook command directly passed to certbot in cron job. + EXAMPLES -------- .. code-block:: sh - __letsencrypt_cert example.com --webroot /data/letsencrypt/root + __letsencrypt_cert example.com --admin-email root@example.com --webroot /data/letsencrypt/root + + __letsencrypt_cert example.com --admin-email root@example.com --webroot /data/letsencrypt/root --renew-hook "service nginx reload" AUTHORS ------- Nico Schottelius Kamila Součková +Darko Poljak COPYING ------- -Copyright \(C) 2017 Nico Schottelius, Kamila Součková. You can redistribute it +Copyright \(C) 2017 Nico Schottelius, Kamila Součková, Darko Poljak. 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/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest index c9a688ca..800e5e18 100644 --- a/cdist/conf/type/__letsencrypt_cert/manifest +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -64,9 +64,16 @@ case "$os" in ;; esac +renew_hook_param="$__object/parameter/renew-hook" +renew_hook="" +if [ -f "$renew_hook_param" ]; then + while read hook; do + renew_hook="$renew_hook --renew-hook \"$hook\"" + done < "$renew_hook_param" +fi __cron letsencrypt-certbot \ --user root \ - --command "$certbot_fullpath renew -q" \ + --command "$certbot_fullpath renew -q $renew_hook" \ --hour 0 \ --minute 47 diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/optional_multiple b/cdist/conf/type/__letsencrypt_cert/parameter/optional_multiple new file mode 100644 index 00000000..3384c74f --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/parameter/optional_multiple @@ -0,0 +1 @@ +renew-hook diff --git a/docs/changelog b/docs/changelog index e00d01bc..d030d43a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -19,6 +19,7 @@ next: * Type __motd: Support reading from stdin (Jonas Weber) * Type __issue: Support reading from stdin (Jonas Weber) * Type __package_apt: Add support for --version parameter (Darko Poljak) + * Type __letsencrypt_cert: Add --renew-hook parameter(Darko Poljak) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From a993e0f5a98a1a9f6fb6768043412e36523a1a63 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 7 Feb 2018 18:12:15 +0100 Subject: [PATCH 0735/1332] Support disabling saving output streams --- cdist/argparse.py | 4 + cdist/config.py | 6 +- cdist/configuration.py | 10 +- cdist/core/code.py | 32 ++-- cdist/core/manifest.py | 36 +++-- cdist/exec/local.py | 7 +- cdist/exec/remote.py | 22 +-- .../test/capture_output_disabled/__init__.py | 140 ++++++++++++++++++ .../fixtures/conf/manifest/init | 4 + .../gencode-local | 6 + .../gencode-remote | 6 + .../__write_to_stdout_and_stderr/manifest | 4 + .../__write_to_stdout_and_stderr/singleton | 0 cdist/test/configuration/__init__.py | 113 ++++++++++++++ docs/src/cdist-cache.rst | 6 +- docs/src/cdist-configuration.rst | 5 + docs/src/cdist-saving-output-streams.rst | 88 +++++++++++ docs/src/index.rst | 1 + docs/src/man1/cdist.rst | 13 +- 19 files changed, 460 insertions(+), 43 deletions(-) create mode 100644 cdist/test/capture_output_disabled/__init__.py create mode 100755 cdist/test/capture_output_disabled/fixtures/conf/manifest/init create mode 100755 cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-local create mode 100755 cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-remote create mode 100755 cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/manifest create mode 100644 cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/singleton create mode 100644 docs/src/cdist-saving-output-streams.rst diff --git a/cdist/argparse.py b/cdist/argparse.py index 5bce1b76..2ec28121 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -251,6 +251,10 @@ def get_parsers(): 'default.'), action='store', dest='parallel', const=multiprocessing.cpu_count()) + parser['config_args'].add_argument( + '-S', '--disable-saving-output-streams', + help='Disable saving output streams.', + action='store_false', dest='save_output_streams', default=True) parser['config_args'].add_argument( '-s', '--sequential', help='Operate on multiple hosts sequentially (default).', diff --git a/cdist/config.py b/cdist/config.py index dc73830c..be39de22 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -345,7 +345,8 @@ class Config(object): cache_path_pattern=args.cache_path_pattern, quiet_mode=args.quiet, configuration=configuration, - exec_path=sys.argv[0]) + exec_path=sys.argv[0], + save_output_streams=args.save_output_streams) remote = cdist.exec.remote.Remote( target_host=target_host, @@ -356,7 +357,8 @@ class Config(object): archiving_mode=args.use_archiving, configuration=configuration, stdout_base_path=local.stdout_base_path, - stderr_base_path=local.stderr_base_path) + stderr_base_path=local.stderr_base_path, + save_output_streams=args.save_output_streams) cleanup_cmds = [] if cleanup_cmd: diff --git a/cdist/configuration.py b/cdist/configuration.py index 8600cb0c..2a253e7f 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -248,6 +248,7 @@ _ARG_OPTION_MAPPING = { 'parallel': 'parallel', 'verbose': 'verbosity', 'use_archiving': 'archiving', + 'save_output_streams': 'save_output_streams', } @@ -285,6 +286,7 @@ class Configuration(metaclass=Singleton): 'parallel': JobsOption('parallel'), 'verbosity': VerbosityOption(), 'archiving': ArchivingOption(), + 'save_output_streams': BooleanOption('save_output_streams'), }, } @@ -328,7 +330,10 @@ class Configuration(metaclass=Singleton): config_files=default_config_files, singleton=True): self.command_line_args = command_line_args self.args = self._convert_args(command_line_args) - self.env = env + if env is None: + self.env = {} + else: + self.env = env self.config_files = config_files self.config = self._get_config() @@ -403,7 +408,8 @@ class Configuration(metaclass=Singleton): for option in self.ARG_OPTION_MAPPING: if option in args: dst_opt = self.ARG_OPTION_MAPPING[option] - if args[option]: + option_object = self.CONFIG_FILE_OPTIONS['GLOBAL'][dst_opt] + if args[option] or isinstance(option_object, BooleanOption): d[dst_opt] = args[option] return d diff --git a/cdist/core/code.py b/cdist/core/code.py index 65d095cf..670029ed 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -127,13 +127,18 @@ class Code(object): '__object_name': cdist_object.name, }) message_prefix = cdist_object.name - stderr_path = os.path.join(cdist_object.stderr_path, - 'gencode-' + which) - with open(stderr_path, 'ba+') as stderr: + if self.local.save_output_streams: + stderr_path = os.path.join(cdist_object.stderr_path, + 'gencode-' + which) + with open(stderr_path, 'ba+') as stderr: + return self.local.run_script(script, env=env, + return_output=True, + message_prefix=message_prefix, + stderr=stderr) + else: return self.local.run_script(script, env=env, return_output=True, - message_prefix=message_prefix, - stderr=stderr) + message_prefix=message_prefix) def run_gencode_local(self, cdist_object): """Run the gencode-local script for the given cdist object.""" @@ -157,12 +162,17 @@ class Code(object): which_exec = getattr(self, which) script = os.path.join(which_exec.object_path, getattr(cdist_object, 'code_%s_path' % which)) - stderr_path = os.path.join(cdist_object.stderr_path, 'code-' + which) - stdout_path = os.path.join(cdist_object.stdout_path, 'code-' + which) - with open(stderr_path, 'ba+') as stderr, \ - open(stdout_path, 'ba+') as stdout: - return which_exec.run_script(script, env=env, stdout=stdout, - stderr=stderr) + if which_exec.save_output_streams: + stderr_path = os.path.join(cdist_object.stderr_path, + 'code-' + which) + stdout_path = os.path.join(cdist_object.stdout_path, + 'code-' + which) + with open(stderr_path, 'ba+') as stderr, \ + open(stdout_path, 'ba+') as stdout: + return which_exec.run_script(script, env=env, stdout=stdout, + stderr=stderr) + else: + return which_exec.run_script(script, env=env) def run_code_local(self, cdist_object): """Run the code-local script for the given cdist object.""" diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 12b5b005..938ad8b8 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -154,15 +154,21 @@ class Manifest(object): message_prefix = "initialmanifest" self.log.verbose("Running initial manifest " + initial_manifest) which = "init" - stderr_path = os.path.join(self.local.stderr_base_path, which) - stdout_path = os.path.join(self.local.stdout_base_path, which) - with open(stderr_path, 'ba+') as stderr, \ - open(stdout_path, 'ba+') as stdout: + if self.local.save_output_streams: + stderr_path = os.path.join(self.local.stderr_base_path, which) + stdout_path = os.path.join(self.local.stdout_base_path, which) + with open(stderr_path, 'ba+') as stderr, \ + open(stdout_path, 'ba+') as stdout: + self.local.run_script( + initial_manifest, + env=self.env_initial_manifest(initial_manifest), + message_prefix=message_prefix, + stdout=stdout, stderr=stderr) + else: self.local.run_script( initial_manifest, env=self.env_initial_manifest(initial_manifest), - message_prefix=message_prefix, - stdout=stdout, stderr=stderr) + message_prefix=message_prefix) def env_type_manifest(self, cdist_object): type_manifest = os.path.join(self.local.type_path, @@ -188,12 +194,18 @@ class Manifest(object): if os.path.isfile(type_manifest): self.log.verbose("Running type manifest %s for object %s", type_manifest, cdist_object.name) - stderr_path = os.path.join(cdist_object.stderr_path, which) - stdout_path = os.path.join(cdist_object.stdout_path, which) - with open(stderr_path, 'ba+') as stderr, \ - open(stdout_path, 'ba+') as stdout: + if self.local.save_output_streams: + stderr_path = os.path.join(cdist_object.stderr_path, which) + stdout_path = os.path.join(cdist_object.stdout_path, which) + with open(stderr_path, 'ba+') as stderr, \ + open(stdout_path, 'ba+') as stdout: + self.local.run_script( + type_manifest, + env=self.env_type_manifest(cdist_object), + message_prefix=message_prefix, + stdout=stdout, stderr=stderr) + else: self.local.run_script( type_manifest, env=self.env_type_manifest(cdist_object), - message_prefix=message_prefix, - stdout=stdout, stderr=stderr) + message_prefix=message_prefix) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index eec79399..a50fe072 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -56,7 +56,8 @@ class Local(object): add_conf_dirs=None, cache_path_pattern=None, quiet_mode=False, - configuration=None): + configuration=None, + save_output_streams=True): self.target_host = target_host if target_host_tags is None: @@ -75,6 +76,7 @@ class Local(object): self.configuration = configuration else: self.configuration = {} + self.save_output_streams = save_output_streams self._init_log() self._init_permissions() @@ -213,7 +215,7 @@ class Local(object): "list or tuple argument expected, got: %s" % command) quiet = self.quiet_mode or quiet_mode - do_save_output = save_output and not quiet + do_save_output = save_output and not quiet and self.save_output_streams close_stdout = False close_stderr = False @@ -256,7 +258,6 @@ class Local(object): if do_save_output: util.log_std_fd(self.log, command, stderr, 'Local stderr') util.log_std_fd(self.log, command, stdout, 'Local stdout') - return output except subprocess.CalledProcessError as e: util.handle_called_process_error(e, command) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 8fcd0981..b75905ba 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -65,7 +65,8 @@ class Remote(object): archiving_mode=None, configuration=None, stdout_base_path=None, - stderr_base_path=None): + stderr_base_path=None, + save_output_streams=True): self.target_host = target_host self._exec = remote_exec self._copy = remote_copy @@ -80,6 +81,7 @@ class Remote(object): self.configuration = configuration else: self.configuration = {} + self.save_output_streams = save_output_streams self.stdout_base_path = stdout_base_path self.stderr_base_path = stderr_base_path @@ -309,12 +311,13 @@ class Remote(object): close_stdout = False close_stderr = False - if not return_output and stdout is None: - stdout = util.get_std_fd(self.stdout_base_path, 'remote') - close_stdout = True - if stderr is None: - stderr = util.get_std_fd(self.stderr_base_path, 'remote') - close_stderr = True + if self.save_output_streams: + if not return_output and stdout is None: + stdout = util.get_std_fd(self.stdout_base_path, 'remote') + close_stdout = True + if stderr is None: + stderr = util.get_std_fd(self.stderr_base_path, 'remote') + close_stderr = True # export target_host, target_hostname, target_fqdn # for use in __remote_{exec,copy} scripts @@ -335,8 +338,9 @@ class Remote(object): stderr=stderr) output = None - util.log_std_fd(self.log, command, stderr, 'Remote stderr') - util.log_std_fd(self.log, command, stdout, 'Remote stdout') + if self.save_output_streams: + util.log_std_fd(self.log, command, stderr, 'Remote stderr') + util.log_std_fd(self.log, command, stdout, 'Remote stdout') return output except subprocess.CalledProcessError as e: diff --git a/cdist/test/capture_output_disabled/__init__.py b/cdist/test/capture_output_disabled/__init__.py new file mode 100644 index 00000000..828e80f1 --- /dev/null +++ b/cdist/test/capture_output_disabled/__init__.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +# +# 2018 Darko Poljak (darko.poljak 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 . +# +# + +import os +import shutil + +import cdist +from cdist import core +from cdist import test +from cdist.exec import local +from cdist.exec import remote +from cdist.core import code +from cdist.core import manifest + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +conf_dir = op.join(fixtures, 'conf') + + +class CaptureOutputDisabledTestCase(test.CdistTestCase): + + def setUp(self): + # logging.root.setLevel(logging.TRACE) + save_output_streams = False + self.temp_dir = self.mkdtemp() + + self.local_dir = os.path.join(self.temp_dir, "local") + self.hostdir = cdist.str_hash(self.target_host[0]) + self.host_base_path = os.path.join(self.local_dir, self.hostdir) + os.makedirs(self.host_base_path) + self.local = local.Local( + target_host=self.target_host, + target_host_tags=None, + base_root_path=self.host_base_path, + host_dir_name=self.hostdir, + exec_path=cdist.test.cdist_exec_path, + add_conf_dirs=[conf_dir], + save_output_streams=save_output_streams) + self.local.create_files_dirs() + + self.remote_dir = self.mkdtemp() + remote_exec = self.remote_exec + remote_copy = self.remote_copy + self.remote = remote.Remote( + target_host=self.target_host, + remote_exec=remote_exec, + remote_copy=remote_copy, + base_path=self.remote_dir, + stdout_base_path=self.local.stdout_base_path, + stderr_base_path=self.local.stderr_base_path, + save_output_streams=save_output_streams) + self.remote.create_files_dirs() + + self.code = code.Code(self.target_host, self.local, self.remote) + + self.manifest = manifest.Manifest(self.target_host, self.local) + + self.cdist_type = core.CdistType(self.local.type_path, + '__write_to_stdout_and_stderr') + self.cdist_object = core.CdistObject(self.cdist_type, + self.local.object_path, + self.local.object_marker_name, + '') + self.cdist_object.create() + self.output_dirs = { + 'object': { + 'stdout': os.path.join(self.cdist_object.absolute_path, + 'stdout'), + 'stderr': os.path.join(self.cdist_object.absolute_path, + 'stderr'), + }, + 'init': { + 'stdout': os.path.join(self.local.base_path, 'stdout'), + 'stderr': os.path.join(self.local.base_path, 'stderr'), + }, + } + + def tearDown(self): + shutil.rmtree(self.local_dir) + shutil.rmtree(self.remote_dir) + shutil.rmtree(self.temp_dir) + + def _test_output(self, which, target, streams=('stdout', 'stderr')): + for stream in streams: + stream_path = os.path.join(self.output_dirs[target][stream], which) + if os.path.exists(stream_path): + with open(stream_path, 'r') as fd: + _is = fd.read() + self.assertEqual("", _is) + # else ok when not exists + + def test_capture_code_output_disabled(self): + self.cdist_object.code_local = self.code.run_gencode_local( + self.cdist_object) + self._test_output('gencode-local', 'object', ('stderr',)) + + self.code.run_code_local(self.cdist_object) + self._test_output('code-local', 'object') + + self.cdist_object.code_remote = self.code.run_gencode_remote( + self.cdist_object) + self._test_output('gencode-remote', 'object', ('stderr',)) + + self.code.transfer_code_remote(self.cdist_object) + self.code.run_code_remote(self.cdist_object) + self._test_output('code-remote', 'object') + + def test_capture_manifest_output_disabled(self): + self.manifest.run_type_manifest(self.cdist_object) + self._test_output('manifest', 'object') + + def test_capture_init_manifest_output_disabled(self): + initial_manifest = os.path.join(conf_dir, 'manifest', 'init') + self.manifest.run_initial_manifest(initial_manifest) + self._test_output('init', 'init') + + +if __name__ == "__main__": + import unittest + + unittest.main() diff --git a/cdist/test/capture_output_disabled/fixtures/conf/manifest/init b/cdist/test/capture_output_disabled/fixtures/conf/manifest/init new file mode 100755 index 00000000..68d7da97 --- /dev/null +++ b/cdist/test/capture_output_disabled/fixtures/conf/manifest/init @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "init: stdout" +echo "init: stderr" >&2 diff --git a/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-local b/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-local new file mode 100755 index 00000000..1946dbd3 --- /dev/null +++ b/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-local @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "gencode-local: stderr" >&2 + +echo "echo \"code-local: stdout\"" +echo "echo \"code-local: stderr\" >&2" diff --git a/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-remote b/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-remote new file mode 100755 index 00000000..f713b932 --- /dev/null +++ b/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/gencode-remote @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "gencode-remote: stderr" >&2 + +echo "echo \"code-remote: stdout\"" +echo "echo \"code-remote: stderr\" >&2" diff --git a/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/manifest b/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/manifest new file mode 100755 index 00000000..4f122f25 --- /dev/null +++ b/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/manifest @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "manifest: stdout" +echo "manifest: stderr" >&2 diff --git a/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/singleton b/cdist/test/capture_output_disabled/fixtures/conf/type/__write_to_stdout_and_stderr/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index b44fd17c..4ce3d29d 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -300,6 +300,7 @@ class ConfigurationTestCase(test.CdistTestCase): expected = { 'conf_dir': ['/usr/local/cdist1', ], 'verbosity': 3, + 'beta': False, } args_dict = vars(args) d = config._read_args_config(args_dict) @@ -1167,6 +1168,118 @@ class ConfigurationTestCase(test.CdistTestCase): configuration = cc.Configuration(args, env=env, config_files=()) + def test_configuration_disable_saving_output_streams1(self): + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'save_output_streams': 'True', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'save_output_streams': True, + 'verbosity': 0, + }, + } + + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + args = argparse.Namespace() + args.save_output_streams = True + configuration = cc.Configuration(args, env=None, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration_disable_saving_output_streams2(self): + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'save_output_streams': 'False', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'save_output_streams': True, + 'verbosity': 0, + }, + } + + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + args = argparse.Namespace() + args.save_output_streams = True + configuration = cc.Configuration(args, env=None, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration_disable_saving_output_streams3(self): + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'save_output_streams': 'False', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'save_output_streams': False, + 'verbosity': 0, + }, + } + + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + args = argparse.Namespace() + args.save_output_streams = False + configuration = cc.Configuration(args, env=None, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration_disable_saving_output_streams4(self): + config = configparser.ConfigParser() + config['GLOBAL'] = { + 'save_output_streams': 'True', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'save_output_streams': False, + 'verbosity': 0, + }, + } + + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + args = argparse.Namespace() + args.save_output_streams = False + configuration = cc.Configuration(args, env=None, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + if __name__ == "__main__": import unittest diff --git a/docs/src/cdist-cache.rst b/docs/src/cdist-cache.rst index b4335db9..0e5361ee 100644 --- a/docs/src/cdist-cache.rst +++ b/docs/src/cdist-cache.rst @@ -87,10 +87,12 @@ state this type execution state ('done' when finished) stderr - directory containing type's gencode-* and code-* stderr stream outputs + directory containing type's manifest, gencode-* and code-* stderr stream + outputs stdin this type stdin content stdout - directory containing type's gencode-* and code-* stdout stream outputs. + directory containing type's manifest, gencode-* and code-* stdout stream + outputs. diff --git a/docs/src/cdist-configuration.rst b/docs/src/cdist-configuration.rst index e53c818f..a66ddf7c 100644 --- a/docs/src/cdist-configuration.rst +++ b/docs/src/cdist-configuration.rst @@ -88,6 +88,11 @@ The possible keywords and their meanings are as follows: :strong:`remote_shell` Shell command at remote host used for remote execution. +:strong:`save_output_streams` + Enable/disable saving output streams (enabled by default). + It recognizes boolean values from 'yes'/'no', 'on'/'off', 'true'/'false' + and '1'/'0'. + :strong:`verbosity` Set verbosity level. Valid values are: 'ERROR', 'WARNING', 'INFO', 'VERBOSE', 'DEBUG', 'TRACE' and 'OFF'. diff --git a/docs/src/cdist-saving-output-streams.rst b/docs/src/cdist-saving-output-streams.rst new file mode 100644 index 00000000..28067cac --- /dev/null +++ b/docs/src/cdist-saving-output-streams.rst @@ -0,0 +1,88 @@ +Saving output streams +===================== + +Description +----------- +Since version 4.8.0 cdist, by default, saves output streams to local cache. +Saving output streams is implemented because important information was lost +during a config run, hidden in all other output. +Now all created output is bound to the context where it was produced. + +Saving output streams include stdout and stderr of init manifest, remote +commands and for each object stdout and stderr of manifest, gencode-* and code-*. +Output stream files are created only if some output is produced. For more info +on these cache files see `Local cache overview `_. + +Also, in case of an error, cdist can now exit and show all information it has +about the error. + +For example: + +.. code-block:: sh + + $ ./bin/cdist config -v -i ~/.cdist/manifest/init-output-streams $(cat ~/ungleich/data/opennebula-debian9-test ) + INFO: 185.203.112.42: Starting configuration run + INFO: 185.203.112.42: Processing __myline/test + ERROR: 185.203.112.42: Command failed: '/bin/sh -e /tmp/tmpow6cwemh/75ee6a79e32da093da23fe4a13dd104b/data/object/__myline/test/.cdist-kisrqlpw/code-local' + return code: 1 + ---- BEGIN stdout ---- + ---- END stdout ---- + + Error processing object '__myline/test' + ======================================== + name: __myline/test + path: /tmp/tmpow6cwemh/75ee6a79e32da093da23fe4a13dd104b/data/object/__myline/test/.cdist-kisrqlpw + source: /home/darko/.cdist/manifest/init-output-streams + type: /tmp/tmpow6cwemh/75ee6a79e32da093da23fe4a13dd104b/data/conf/type/__myline + + ---- BEGIN manifest:stderr ---- + myline manifest stderr + + ---- END manifest:stderr ---- + + ---- BEGIN gencode-remote:stderr ---- + test gencode-remote error + + ---- END gencode-remote:stderr ---- + + ---- BEGIN code-local:stderr ---- + error + + ---- END code-local:stderr ---- + + ERROR: cdist: Failed to configure the following hosts: 185.203.112.42 + +Upon successful run execution state is saved to local cache and temporary +directory is removed. +In case of an error temporary directory is not removed and can be further +discovered. + +There is also an option :strong:`-S/--disable-saving-output-streams` for +disabling saving output streams. In this case error reporting can look +like this: + +.. code-block:: sh + + $ ./bin/cdist config -v -S -i ~/.cdist/manifest/init-output-streams $(cat ~/ungleich/data/opennebula-debian9-test ) + INFO: 185.203.112.42: Starting configuration run + test stdout output streams + test stderr output streams + myline manifest stdout + myline manifest stderr + test gencode-remote error + INFO: 185.203.112.42: Processing __myline/test + error + ERROR: 185.203.112.42: Command failed: '/bin/sh -e /tmp/tmpzomy0wis/75ee6a79e32da093da23fe4a13dd104b/data/object/__myline/test/.cdist-n566pqut/code-local' + return code: 1 + ---- BEGIN stdout ---- + ---- END stdout ---- + + Error processing object '__myline/test' + ======================================== + name: __myline/test + path: /tmp/tmpzomy0wis/75ee6a79e32da093da23fe4a13dd104b/data/object/__myline/test/.cdist-n566pqut + source: /home/darko/.cdist/manifest/init-output-streams + type: /tmp/tmpzomy0wis/75ee6a79e32da093da23fe4a13dd104b/data/conf/type/__myline + + + ERROR: cdist: Failed to configure the following hosts: 185.203.112.42 diff --git a/docs/src/index.rst b/docs/src/index.rst index efbc3cb9..5d0bb537 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -31,6 +31,7 @@ Contents: cdist-best-practice cdist-stages cdist-cache + cdist-saving-output-streams cdist-remote-exec-copy cdist-hacker cdist-troubleshooting diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index ea66c37e..8c6ca549 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -21,7 +21,7 @@ SYNOPSIS [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] - [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] + [-f HOSTFILE] [-p [HOST_MAX]] [-S] [-s] [-t] [host [host ...]] cdist install [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] @@ -29,7 +29,7 @@ SYNOPSIS [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] - [-f HOSTFILE] [-p [HOST_MAX]] [-s] [-t] + [-f HOSTFILE] [-p [HOST_MAX]] [-S] [-s] [-t] [host [host ...]] cdist inventory [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] @@ -200,6 +200,10 @@ Install command is currently in beta. Directory to save cdist output in on the target host. +.. option:: -S, --disable-saving-output-streams + + Disable saving output streams. + .. option:: -s, --sequential Operate on multiple hosts sequentially (default). @@ -561,6 +565,11 @@ The possible keywords and their meanings are as follows: :strong:`remote_shell` Shell command at remote host used for remote execution. +:strong:`save_output_streams` + Enable/disable saving output streams (enabled by default). + It recognizes boolean values from 'yes'/'no', 'on'/'off', 'true'/'false' + and '1'/'0'. + :strong:`verbosity` Set verbosity level. Valid values are: 'ERROR', 'WARNING', 'INFO', 'VERBOSE', 'DEBUG', 'TRACE' and 'OFF'. From 7fcfe8cff5b39bfd79ae27a6e2ea403b29ead820 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 7 Feb 2018 18:12:02 +0100 Subject: [PATCH 0736/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index d030d43a..59fa8c57 100644 --- a/docs/changelog +++ b/docs/changelog @@ -20,6 +20,7 @@ next: * Type __issue: Support reading from stdin (Jonas Weber) * Type __package_apt: Add support for --version parameter (Darko Poljak) * Type __letsencrypt_cert: Add --renew-hook parameter(Darko Poljak) + * Core: Support disabling saving output streams (Darko Poljak) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From eb94d7a8bb83f3602d23f881a8d7f61df4af4fa7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 12 Feb 2018 12:13:38 +0100 Subject: [PATCH 0737/1332] Remove update index type dep, call update index after adding new source. (#623) --- cdist/conf/type/__apt_source/gencode-remote | 28 +++++++++++++++++++++ cdist/conf/type/__apt_source/man.rst | 5 ++-- cdist/conf/type/__apt_source/manifest | 4 +-- 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100755 cdist/conf/type/__apt_source/gencode-remote diff --git a/cdist/conf/type/__apt_source/gencode-remote b/cdist/conf/type/__apt_source/gencode-remote new file mode 100755 index 00000000..1e8592c6 --- /dev/null +++ b/cdist/conf/type/__apt_source/gencode-remote @@ -0,0 +1,28 @@ +#!/bin/sh -e +# +# 2018 Steven Armstrong (steven-cdist at armstrong.cc) +# +# 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" +destination="/etc/apt/sources.list.d/${name}.list" + +if grep -q "^__file${destination}" "$__messages_in"; then + printf 'apt-get update || apt-get update\n' +fi + diff --git a/cdist/conf/type/__apt_source/man.rst b/cdist/conf/type/__apt_source/man.rst index 8aa6c144..d1acb388 100644 --- a/cdist/conf/type/__apt_source/man.rst +++ b/cdist/conf/type/__apt_source/man.rst @@ -8,7 +8,8 @@ cdist-type__apt_source - Manage apt sources DESCRIPTION ----------- -This cdist type allows you to manage apt sources. +This cdist type allows you to manage apt sources. It invokes index update +internally when needed so call of index updating type is not needed. REQUIRED PARAMETERS @@ -63,7 +64,7 @@ Steven Armstrong COPYING ------- -Copyright \(C) 2011-2014 Steven Armstrong. You can redistribute it +Copyright \(C) 2011-2018 Steven Armstrong. 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_source/manifest b/cdist/conf/type/__apt_source/manifest index 7957bf8c..35f15909 100755 --- a/cdist/conf/type/__apt_source/manifest +++ b/cdist/conf/type/__apt_source/manifest @@ -1,6 +1,6 @@ #!/bin/sh -e # -# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2018 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -50,5 +50,3 @@ __file "/etc/apt/sources.list.d/${name}.list" \ --source "$__object/files/source.list" \ --owner root --group root --mode 0644 \ --state "$state" - -require="$__object_name" __apt_update_index From 0ae61c8aadaa8071c8eaf87be2a0fe3adade6e7e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 12 Feb 2018 12:13:53 +0100 Subject: [PATCH 0738/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 59fa8c57..1d21514f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -21,6 +21,7 @@ next: * Type __package_apt: Add support for --version parameter (Darko Poljak) * Type __letsencrypt_cert: Add --renew-hook parameter(Darko Poljak) * Core: Support disabling saving output streams (Darko Poljak) + * Type __apt_source: Remove update index dependency; call index update in gencode-remote (Darko Poljak) 4.7.3: 2017-11-10 * Type __ccollect_source: Add create destination parameter (Dominique Roux) From 0074bb05645302e6cc34e227933d5f72eb281785 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 14 Feb 2018 20:07:44 +0100 Subject: [PATCH 0739/1332] Fix minor docs formatting. --- cdist/conf/type/__letsencrypt_cert/man.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__letsencrypt_cert/man.rst b/cdist/conf/type/__letsencrypt_cert/man.rst index 9b487d01..bb1e5d05 100644 --- a/cdist/conf/type/__letsencrypt_cert/man.rst +++ b/cdist/conf/type/__letsencrypt_cert/man.rst @@ -43,9 +43,9 @@ EXAMPLES AUTHORS ------- -Nico Schottelius -Kamila Součková -Darko Poljak +| Nico Schottelius +| Kamila Součková +| Darko Poljak COPYING From 7d06a3e7d12935d57719913cf864e7851531013a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 14 Feb 2018 20:09:00 +0100 Subject: [PATCH 0740/1332] Release 4.8.0 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 1d21514f..65780d5d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) * Explorer memory: Support OpenBSD (Philippe Gregoire) * Type __install_config: re-export cdist log level during installation (Steven Armstrong) From 9a832d88b57b33e2e21b3e532b7fab027c291b1e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Feb 2018 15:45:31 +0100 Subject: [PATCH 0741/1332] Add option for directly downloading on target host. --- .../type/__consul/files/versions/1.0.6/cksum | 1 + .../type/__consul/files/versions/1.0.6/source | 1 + cdist/conf/type/__consul/gencode-remote | 59 +++++++++++++++++++ cdist/conf/type/__consul/man.rst | 15 ++++- cdist/conf/type/__consul/manifest | 23 +++++--- cdist/conf/type/__consul/parameter/boolean | 1 + .../type/__consul/parameter/default/version | 2 +- 7 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 cdist/conf/type/__consul/files/versions/1.0.6/cksum create mode 100644 cdist/conf/type/__consul/files/versions/1.0.6/source create mode 100755 cdist/conf/type/__consul/gencode-remote create mode 100644 cdist/conf/type/__consul/parameter/boolean diff --git a/cdist/conf/type/__consul/files/versions/1.0.6/cksum b/cdist/conf/type/__consul/files/versions/1.0.6/cksum new file mode 100644 index 00000000..b70b55f4 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/1.0.6/cksum @@ -0,0 +1 @@ +4120550353 48801129 consul diff --git a/cdist/conf/type/__consul/files/versions/1.0.6/source b/cdist/conf/type/__consul/files/versions/1.0.6/source new file mode 100644 index 00000000..769d3134 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/1.0.6/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/1.0.6/consul_1.0.6_linux_amd64.zip diff --git a/cdist/conf/type/__consul/gencode-remote b/cdist/conf/type/__consul/gencode-remote new file mode 100755 index 00000000..5b3f5573 --- /dev/null +++ b/cdist/conf/type/__consul/gencode-remote @@ -0,0 +1,59 @@ +#!/bin/sh -e +# +# 2018 Darko Poljak (darko.poljak 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 . +# + +#set -x + +if [ ! -f "$__object/parameter/direct" ]; then + # Nothing here, staged file is used. + exit 0 +fi + +state=$(cat "$__object/parameter/state") +destination="/usr/local/bin/consul" + +if [ "$state" = "absent" ]; then + printf 'rm -f "%s"' "$destination" + exit 0 +fi + +versions_dir="$__type/files/versions" +version="$(cat "$__object/parameter/version")" +version_dir="$versions_dir/$version" + +source=$(cat "$version_dir/source") +source_file_name="${source##*/}" +cksum_should=$(cat "$version_dir/cksum" | cut -d' ' -f1,2) + +cat << eof + tmpdir=\$(mktemp -d --tmpdir="/tmp" "${__type##*/}.XXXXXXXXXX") + curl -s -L "$source" > "\$tmpdir/$source_file_name" + unzip -p "\$tmpdir/$source_file_name" > "$destination" + rm -rf "\$tmpdir" + + cksum_is=\$(cksum "$destination" | cut -d' ' -f1,2) + if [ "\$cksum_is" = "$cksum_should" ]; then + chown root:root "$destination" + chmod 755 "$destination" + else + rm -f "$destination" + echo "Failed to verify checksum for $__object_name" >&2 + exit 1 + fi +eof diff --git a/cdist/conf/type/__consul/man.rst b/cdist/conf/type/__consul/man.rst index 19ceb535..09e547f9 100644 --- a/cdist/conf/type/__consul/man.rst +++ b/cdist/conf/type/__consul/man.rst @@ -10,7 +10,8 @@ DESCRIPTION ----------- Downloads and installs the consul binary from https://dl.bintray.com/mitchellh/consul. Note that the consul binary is downloaded on the server (the machine running -cdist) and then deployed to the target host using the __file type. +cdist) and then deployed to the target host using the __file type unless --direct +parameter is used. REQUIRED PARAMETERS @@ -28,6 +29,12 @@ version supported versions. Defaults to the latest known version. +BOOLEAN PARAMETERS +------------------ +direct + Download and deploy consul binary directly on the target machine. + + EXAMPLES -------- @@ -36,6 +43,9 @@ EXAMPLES # just install using defaults __consul + # install by downloading consul binary directly on the target machine + __consul --direct + # specific version __consul \ --version 0.4.1 @@ -43,7 +53,8 @@ EXAMPLES AUTHORS ------- -Steven Armstrong +| Steven Armstrong +| Darko Poljak COPYING diff --git a/cdist/conf/type/__consul/manifest b/cdist/conf/type/__consul/manifest index cd79e5d9..0dd50f53 100755 --- a/cdist/conf/type/__consul/manifest +++ b/cdist/conf/type/__consul/manifest @@ -2,6 +2,7 @@ # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # 2016 Nico Schottelius (nico-cdist at schottelius.org) +# 2018 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -44,12 +45,16 @@ if [ ! -d "$version_dir" ]; then exit 1 fi -__staged_file /usr/local/bin/consul \ - --source "$(cat "$version_dir/source")" \ - --cksum "$(cat "$version_dir/cksum")" \ - --fetch-command 'curl -s -L "%s"' \ - --prepare-command 'unzip -p "%s"' \ - --state "$(cat "$__object/parameter/state")" \ - --group root \ - --owner root \ - --mode 755 +if [ -f "$__object/parameter/direct" ]; then + __package unzip +else + __staged_file /usr/local/bin/consul \ + --source "$(cat "$version_dir/source")" \ + --cksum "$(cat "$version_dir/cksum")" \ + --fetch-command 'curl -s -L "%s"' \ + --prepare-command 'unzip -p "%s"' \ + --state "$(cat "$__object/parameter/state")" \ + --group root \ + --owner root \ + --mode 755 +fi diff --git a/cdist/conf/type/__consul/parameter/boolean b/cdist/conf/type/__consul/parameter/boolean new file mode 100644 index 00000000..aa81b5e0 --- /dev/null +++ b/cdist/conf/type/__consul/parameter/boolean @@ -0,0 +1 @@ +direct diff --git a/cdist/conf/type/__consul/parameter/default/version b/cdist/conf/type/__consul/parameter/default/version index d2b13eb6..af0b7ddb 100644 --- a/cdist/conf/type/__consul/parameter/default/version +++ b/cdist/conf/type/__consul/parameter/default/version @@ -1 +1 @@ -0.6.4 +1.0.6 From 19206e7693a279b1913216770c0fbb8c22a62641 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Feb 2018 15:45:39 +0100 Subject: [PATCH 0742/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 65780d5d..fa1d8848 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __consul: Add option for directly downloading on target host (Darko Poljak) + 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) * Explorer memory: Support OpenBSD (Philippe Gregoire) From 4d39b6af51769788b56abfc663ba33d079a8dcc9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Feb 2018 20:33:36 +0100 Subject: [PATCH 0743/1332] Add -4 and -6 params to force IPv4, IPv6 addresses respectively. --- cdist/argparse.py | 10 ++++++++++ cdist/config.py | 28 +++++++++++++++++++++++++--- cdist/util/ipaddr.py | 8 ++++---- docs/src/man1/cdist.rst | 18 ++++++++++++++---- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 2ec28121..a9f3ad9f 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -224,6 +224,16 @@ def get_parsers(): # Config parser['config_args'] = argparse.ArgumentParser(add_help=False) + parser['config_args'].add_argument( + '-4', '--force-ipv4', + help=('Force to use IPv4 addresses only. No influence for custom' + ' remote commands.'), + action='store_const', dest='force_ipv', const=4) + parser['config_args'].add_argument( + '-6', '--force-ipv6', + help=('Force to use IPv6 addresses only. No influence for custom' + ' remote commands.'), + action='store_const', dest='force_ipv', const=6) parser['config_args'].add_argument( '-A', '--all-tagged', help=('Use all hosts present in tags db. Currently in beta.'), diff --git a/cdist/config.py b/cdist/config.py index be39de22..63566594 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -32,6 +32,7 @@ import multiprocessing from cdist.mputil import mp_pool_run, mp_sig_handler import atexit import shutil +import socket import cdist import cdist.hostsource import cdist.exec.local @@ -110,6 +111,13 @@ class Config(object): args.remote_exec_pattern = None args.remote_copy_pattern = None + # Determine forcing IPv4/IPv6 options if any, only for + # default remote commands. + if args.force_ipv: + force_addr_opt = " -{}".format(args.force_ipv) + else: + force_addr_opt = "" + args_dict = vars(args) # if remote-exec and/or remote-copy args are None then user # didn't specify command line options nor env vars: @@ -118,9 +126,11 @@ class Config(object): args_dict['remote_exec'] is None): mux_opts = inspect_ssh_mux_opts() if args_dict['remote_exec'] is None: - args.remote_exec_pattern = cdist.REMOTE_EXEC + mux_opts + args.remote_exec_pattern = (cdist.REMOTE_EXEC + + force_addr_opt + mux_opts) if args_dict['remote_copy'] is None: - args.remote_copy_pattern = cdist.REMOTE_COPY + mux_opts + args.remote_copy_pattern = (cdist.REMOTE_COPY + + force_addr_opt + mux_opts) if mux_opts: cleanup_pattern = cdist.REMOTE_CMDS_CLEANUP_PATTERN else: @@ -313,6 +323,16 @@ class Config(object): remote_cmds_cleanup = "" return (remote_exec, remote_copy, remote_cmds_cleanup, ) + @staticmethod + def _address_family(args): + if args.force_ipv == 4: + family = socket.AF_INET + elif args.force_ipv == 6: + family = socket.AF_INET6 + else: + family = 0 + return family + @classmethod def onehost(cls, host, host_tags, host_base_path, host_dir_name, args, parallel, configuration, remove_remote_files_dirs=False): @@ -331,7 +351,9 @@ class Config(object): log.debug("remote_copy for host \"{}\": {}".format( host, remote_copy)) - target_host = ipaddr.resolve_target_addresses(host) + family = cls._address_family(args) + log.debug("address family: {}".format(family)) + target_host = ipaddr.resolve_target_addresses(host, family) log.debug("target_host for host \"{}\": {}".format( host, target_host)) diff --git a/cdist/util/ipaddr.py b/cdist/util/ipaddr.py index 0bcb0a83..9b730225 100644 --- a/cdist/util/ipaddr.py +++ b/cdist/util/ipaddr.py @@ -23,13 +23,13 @@ import socket import logging -def resolve_target_addresses(host): - host_name = resolve_target_host_name(host) +def resolve_target_addresses(host, family=0): + host_name = resolve_target_host_name(host, family) host_fqdn = resolve_target_fqdn(host) return (host, host_name, host_fqdn) -def resolve_target_host_name(host): +def resolve_target_host_name(host, family=0): log = logging.getLogger(host) try: # getaddrinfo returns a list of 5-tuples: @@ -38,7 +38,7 @@ def resolve_target_host_name(host): # (address, port) for AF_INET, # (address, port, flow_info, scopeid) for AF_INET6 ip_addr = socket.getaddrinfo( - host, None, type=socket.SOCK_STREAM)[0][4][0] + host, None, family=family, type=socket.SOCK_STREAM)[0][4][0] # gethostbyaddr returns triple # (hostname, aliaslist, ipaddrlist) host_name = socket.gethostbyaddr(ip_addr)[0] diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 8c6ca549..c76520a6 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -20,16 +20,16 @@ SYNOPSIS [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] - [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] - [-f HOSTFILE] [-p [HOST_MAX]] [-S] [-s] [-t] + [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-4] [-6] + [-A] [-a] [-f HOSTFILE] [-p [HOST_MAX]] [-S] [-s] [-t] [host [host ...]] cdist install [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] - [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-A] [-a] - [-f HOSTFILE] [-p [HOST_MAX]] [-S] [-s] [-t] + [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-4] [-6] + [-A] [-a] [-f HOSTFILE] [-p [HOST_MAX]] [-S] [-s] [-t] [host [host ...]] cdist inventory [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] @@ -118,6 +118,16 @@ CONFIG/INSTALL Configure/install one or more hosts. Install command is currently in beta. +.. option:: -4, --force-ipv4 + + Force to use IPv4 addresses only. No influence for + custom remote commands. + +.. option:: -6, --force-ipv6 + + Force to use IPv6 addresses only. No influence for + custom remote commands. + .. option:: -A, --all-tagged Use all hosts present in tags db. Currently in beta. From 50b1867f4dca92133c4b3e82ff0bee7749fd1af6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Feb 2018 21:19:29 +0100 Subject: [PATCH 0744/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index fa1d8848..7baf10e5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Type __consul: Add option for directly downloading on target host (Darko Poljak) + * Core: Add -4 and -6 params to force IPv4, IPv6 addresses respectively (Darko Poljak) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From 48a0fb5bd0e7895490dc2d0c3b7614b7e012974c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Feb 2018 21:34:54 +0100 Subject: [PATCH 0745/1332] Add message when adding consule directly on target. --- cdist/conf/type/__consul/gencode-remote | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__consul/gencode-remote b/cdist/conf/type/__consul/gencode-remote index 5b3f5573..67dbf408 100755 --- a/cdist/conf/type/__consul/gencode-remote +++ b/cdist/conf/type/__consul/gencode-remote @@ -51,6 +51,7 @@ cat << eof if [ "\$cksum_is" = "$cksum_should" ]; then chown root:root "$destination" chmod 755 "$destination" + echo "__consul/usr/local/bin/consul" >> "$__messages_out" else rm -f "$destination" echo "Failed to verify checksum for $__object_name" >&2 From c0dc26a5771a5c136724f5046fda979f2e256d31 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Feb 2018 22:03:28 +0100 Subject: [PATCH 0746/1332] Fix consul message. --- cdist/conf/type/__consul/gencode-remote | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul/gencode-remote b/cdist/conf/type/__consul/gencode-remote index 67dbf408..f4378bd9 100755 --- a/cdist/conf/type/__consul/gencode-remote +++ b/cdist/conf/type/__consul/gencode-remote @@ -51,10 +51,11 @@ cat << eof if [ "\$cksum_is" = "$cksum_should" ]; then chown root:root "$destination" chmod 755 "$destination" - echo "__consul/usr/local/bin/consul" >> "$__messages_out" else rm -f "$destination" echo "Failed to verify checksum for $__object_name" >&2 exit 1 fi eof + +echo "__consul/usr/local/bin/consul" >> "$__messages_out" From 94c9d11cb8b72d2723da27394ae5bb41713920be Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 20 Feb 2018 10:20:54 +0100 Subject: [PATCH 0747/1332] fix messaging for __package_update_index The message was printed unconditionally, even if no `apt-get update` had been running. --- cdist/conf/type/__package_update_index/gencode-remote | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index d84e7953..37bfe7ab 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -54,11 +54,12 @@ case "$type" in ## check if we need to update: if [ $currage -ge $maxage ]; then echo "apt-get --quiet update" + echo "apt-cache updated (age was: $currage)" >> "$__messages_out" fi else echo "apt-get --quiet update" + echo "apt-cache updated (age was: $currage)" >> "$__messages_out" fi - echo "apt-cache updated (age was: $currage)" >> "$__messages_out" ;; pacman) echo "pacman --noprogressbar --sync --refresh" ;; *) From a545b10538a8d4341274cfb54f6ee83067f3b59b Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 20 Feb 2018 16:46:26 +0100 Subject: [PATCH 0748/1332] add `--state`-parameter and messaging to __package_dpkg - `--state` allows to remove a deb-package, if `--purge-if-absent` is specified the package is purged instead of "only" removed - messaging was added - man-page updated accordingly --- .../type/__package_dpkg/explorer/pkg_state | 11 ++++ cdist/conf/type/__package_dpkg/gencode-remote | 23 ++++++- cdist/conf/type/__package_dpkg/man.rst | 60 ++++++++++++++++++- cdist/conf/type/__package_dpkg/manifest | 10 +++- .../type/__package_dpkg/parameter/boolean | 1 + .../__package_dpkg/parameter/default/state | 1 + .../type/__package_dpkg/parameter/optional | 1 + 7 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 cdist/conf/type/__package_dpkg/explorer/pkg_state create mode 100644 cdist/conf/type/__package_dpkg/parameter/boolean create mode 100644 cdist/conf/type/__package_dpkg/parameter/default/state create mode 100644 cdist/conf/type/__package_dpkg/parameter/optional diff --git a/cdist/conf/type/__package_dpkg/explorer/pkg_state b/cdist/conf/type/__package_dpkg/explorer/pkg_state new file mode 100644 index 00000000..d7487ed8 --- /dev/null +++ b/cdist/conf/type/__package_dpkg/explorer/pkg_state @@ -0,0 +1,11 @@ +#!/bin/sh -e + +package=$( basename "$__object_id" ) + +dpkg_status="$(dpkg-query --show --showformat='${db:Status-Abbrev} ${binary:Package}_${Version}_${Architecture}.deb\n' "${package%%_*}" 2>/dev/null || true)" + +if echo "$dpkg_status" | grep -q '^ii'; then + echo "${dpkg_status##* }" +fi + + diff --git a/cdist/conf/type/__package_dpkg/gencode-remote b/cdist/conf/type/__package_dpkg/gencode-remote index 90921ae3..63bdff64 100755 --- a/cdist/conf/type/__package_dpkg/gencode-remote +++ b/cdist/conf/type/__package_dpkg/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh -e # # 2013 Tomas Pospisek (tpo_deb sourcepole.ch) +# 2018 Thomas Eckert (tom at it-eckert.de) # # This file is based on cdist's __file/gencode-local and part of cdist. # @@ -26,5 +27,25 @@ # to conflict with dpkg's --force options). But currently we don't # do any checks or --force'ing. # +state=$( cat "$__object/parameter/state" ) +package=$( basename "$__object_id" ) +state_is="$(cat "$__object/explorer/pkg_state")" +state_should="" -echo "dpkg -i /var/cache/apt/archives/$__object_id" +[ "$state" = "absent" ] || state_should="$package" +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state" in + present) + echo "dpkg --install /var/cache/apt/archives/$__object_id" + echo "installed" >> "$__messages_out" + ;; + absent) + [ -f "$__object/parameter/purge-if-absent" ] \ + && action="--purge" \ + || action="--remove" + echo "dpkg $action $__object_id" + echo "removed ($action)" >> "$__messages_out" + ;; + *) echo "ERROR: unknown state '$state'" >&2 ;; +esac diff --git a/cdist/conf/type/__package_dpkg/man.rst b/cdist/conf/type/__package_dpkg/man.rst index df2d86a7..2b20c1ad 100644 --- a/cdist/conf/type/__package_dpkg/man.rst +++ b/cdist/conf/type/__package_dpkg/man.rst @@ -12,30 +12,84 @@ This type is used on Debian and variants (like Ubuntu) to install packages that are provided locally as \*.deb files. The object given to this type must be the name of the deb package. +The filename of the deb package has to follow Debian naming conventions, i.e. +`${binary:Package}_${Version}_${Architecture}.deb` (see `dpkg-query(1)` for +details). +OPTIONAL PARAMETERS +------------------- +state + `present` or `absent`, defaults to `present`. + REQUIRED PARAMETERS ------------------- source path to the \*.deb package + +BOOLEAN PARAMETERS +------------------- +purge-if-absent + use `--purge` instead of just `--remove` for state=absent. + + +BOOLEAN PARAMETERS +------------------ +purge-if-absent + If this parameter is given when state is `absent`, the package is + purged from the system (using `--purge`). + + +EXPLORER +-------- +pkg_state + Returns the full package name if package is installed, empty otherwise. + + +MESSAGES +-------- +installed + The deb-file was installed. + +removed (--remove) + The package was removed, keeping config. + +removed (--purge) + The package was removed including config (purged). + + EXAMPLES -------- .. code-block:: sh # Install foo and bar packages - __package_dpkg --source /tmp/foo_0.1_all.deb foo_0.1_all.deb - __package_dpkg --source $__type/files/bar_1.4.deb bar_1.4.deb + __package_dpkg foo_0.1_all.deb --source /tmp/foo_0.1_all.deb + __package_dpkg bar_1.4.deb --source $__type/files/bar_1.4.deb + + # uninstall baz: + __package_dpkg baz_1.4_amd64.deb \ + --source $__type/files/baz_1.4_amd64.deb \ + --state "absent" + # uninstall baz and also purge config-files: + __package_dpkg baz_1.4_amd64.deb \ + --source $__type/files/baz_1.4_amd64.deb \ + --purge-if-absent \ + --state "absent" SEE ALSO -------- :strong:`cdist-type__package`\ (7) +:strong:`dpkg-query`\ (1) + AUTHORS ------- -Tomas Pospisek +| Tomas Pospisek +| Thomas Eckert + COPYING ------- diff --git a/cdist/conf/type/__package_dpkg/manifest b/cdist/conf/type/__package_dpkg/manifest index 9f0c1a97..6d228d8e 100755 --- a/cdist/conf/type/__package_dpkg/manifest +++ b/cdist/conf/type/__package_dpkg/manifest @@ -25,10 +25,16 @@ # do any checks or --force'ing. +state=$( cat "$__object/parameter/state" ) package_path=$( cat "$__object/parameter/source" ) package=$( basename "$__object_id" ) +state_is="$(cat "$__object/explorer/pkg_state")" +state_should="" + +[ "$state" = "absent" ] || state_should="$package" +[ "$state_is" = "$state_should" ] && exit 0 __file "/var/cache/apt/archives/$package" \ - --source "$package_path" \ - --state present + --source "$package_path" \ + --state "$state" diff --git a/cdist/conf/type/__package_dpkg/parameter/boolean b/cdist/conf/type/__package_dpkg/parameter/boolean new file mode 100644 index 00000000..f9a0f6b0 --- /dev/null +++ b/cdist/conf/type/__package_dpkg/parameter/boolean @@ -0,0 +1 @@ +purge-if-absent diff --git a/cdist/conf/type/__package_dpkg/parameter/default/state b/cdist/conf/type/__package_dpkg/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__package_dpkg/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__package_dpkg/parameter/optional b/cdist/conf/type/__package_dpkg/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__package_dpkg/parameter/optional @@ -0,0 +1 @@ +state From 1f93e7291e3da06c412a2a5d1005ed7b59e4b7ef Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 21 Feb 2018 10:00:25 +0100 Subject: [PATCH 0749/1332] Fix consul message and document messaging. --- cdist/conf/type/__consul/gencode-remote | 2 +- cdist/conf/type/__consul/man.rst | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul/gencode-remote b/cdist/conf/type/__consul/gencode-remote index f4378bd9..4426ea2b 100755 --- a/cdist/conf/type/__consul/gencode-remote +++ b/cdist/conf/type/__consul/gencode-remote @@ -58,4 +58,4 @@ cat << eof fi eof -echo "__consul/usr/local/bin/consul" >> "$__messages_out" +echo "/usr/local/bin/consul created" >> "$__messages_out" diff --git a/cdist/conf/type/__consul/man.rst b/cdist/conf/type/__consul/man.rst index 09e547f9..401f0c26 100644 --- a/cdist/conf/type/__consul/man.rst +++ b/cdist/conf/type/__consul/man.rst @@ -35,6 +35,14 @@ direct Download and deploy consul binary directly on the target machine. +MESSAGES +-------- +If consul binary is created using __staged_file then underlaying __file type messages are emitted. + +If consul binary is created by direct method then the following messages are emitted: +/usr/local/bin/consul created + consul binary was created + EXAMPLES -------- From ec85527c1aa9f959085d051f2448208138c94d7c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 21 Feb 2018 10:05:48 +0100 Subject: [PATCH 0750/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 7baf10e5..8ce7cf0e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __consul: Add option for directly downloading on target host (Darko Poljak) * Core: Add -4 and -6 params to force IPv4, IPv6 addresses respectively (Darko Poljak) + * Type __package_update_index: Fix messaging (Thomas Eckert) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From 3208ab614e6c8bd2de3397a14ee66313e4d42b20 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 21 Feb 2018 11:16:23 +0100 Subject: [PATCH 0751/1332] review notes (duplicate boolean section, comma separate "see also" items) --- cdist/conf/type/__package_dpkg/man.rst | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cdist/conf/type/__package_dpkg/man.rst b/cdist/conf/type/__package_dpkg/man.rst index 2b20c1ad..828d8cdd 100644 --- a/cdist/conf/type/__package_dpkg/man.rst +++ b/cdist/conf/type/__package_dpkg/man.rst @@ -28,12 +28,6 @@ source path to the \*.deb package -BOOLEAN PARAMETERS -------------------- -purge-if-absent - use `--purge` instead of just `--remove` for state=absent. - - BOOLEAN PARAMETERS ------------------ purge-if-absent @@ -81,8 +75,7 @@ EXAMPLES SEE ALSO -------- -:strong:`cdist-type__package`\ (7) -:strong:`dpkg-query`\ (1) +:strong:`cdist-type__package`\ (7), :strong:`dpkg-query`\ (1) AUTHORS From a5dc6214e125240a70cd45ed96b487d792348ee8 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 21 Feb 2018 15:01:08 +0100 Subject: [PATCH 0752/1332] `dpkg {-r|-P}` needs the package-, not the filename --- cdist/conf/type/__package_dpkg/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_dpkg/gencode-remote b/cdist/conf/type/__package_dpkg/gencode-remote index 63bdff64..1c271748 100755 --- a/cdist/conf/type/__package_dpkg/gencode-remote +++ b/cdist/conf/type/__package_dpkg/gencode-remote @@ -44,7 +44,7 @@ case "$state" in [ -f "$__object/parameter/purge-if-absent" ] \ && action="--purge" \ || action="--remove" - echo "dpkg $action $__object_id" + echo "dpkg $action ${__object_id%%_*}" echo "removed ($action)" >> "$__messages_out" ;; *) echo "ERROR: unknown state '$state'" >&2 ;; From 7cbdc55a8c28238f0f3582d461498ee543aef6f3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 21 Feb 2018 21:18:59 +0100 Subject: [PATCH 0753/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8ce7cf0e..bea3eb38 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __consul: Add option for directly downloading on target host (Darko Poljak) * Core: Add -4 and -6 params to force IPv4, IPv6 addresses respectively (Darko Poljak) * Type __package_update_index: Fix messaging (Thomas Eckert) + * Type __package_dpkg: Add state parameter and messaging (Thomas Eckert) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From b870b6e43a0b83c2a3a192cff6846b9248e23e1c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 25 Feb 2018 09:51:51 +0100 Subject: [PATCH 0754/1332] bugfix: __consul fails if consul is already running #633 --- cdist/conf/type/__consul/gencode-remote | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__consul/gencode-remote b/cdist/conf/type/__consul/gencode-remote index 4426ea2b..22e9eea1 100755 --- a/cdist/conf/type/__consul/gencode-remote +++ b/cdist/conf/type/__consul/gencode-remote @@ -44,15 +44,17 @@ cksum_should=$(cat "$version_dir/cksum" | cut -d' ' -f1,2) cat << eof tmpdir=\$(mktemp -d --tmpdir="/tmp" "${__type##*/}.XXXXXXXXXX") curl -s -L "$source" > "\$tmpdir/$source_file_name" - unzip -p "\$tmpdir/$source_file_name" > "$destination" + unzip -p "\$tmpdir/$source_file_name" > "${destination}.tmp" rm -rf "\$tmpdir" - cksum_is=\$(cksum "$destination" | cut -d' ' -f1,2) + cksum_is=\$(cksum "${destination}.tmp" | cut -d' ' -f1,2) if [ "\$cksum_is" = "$cksum_should" ]; then + rm -f "${destination}" + mv "${destination}.tmp" "${destination}" chown root:root "$destination" chmod 755 "$destination" else - rm -f "$destination" + rm -f "${destination}.tmp" echo "Failed to verify checksum for $__object_name" >&2 exit 1 fi From cf36aece7df7661ac96a30928c6b4e3c5cdf9853 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 25 Feb 2018 23:48:53 +0100 Subject: [PATCH 0755/1332] [BETA] bug: error info lost with parallel (option -j) #632 --- cdist/config.py | 110 +++++++++++++++++++++-------------------- cdist/core/explorer.py | 30 ++++++----- 2 files changed, 74 insertions(+), 66 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 63566594..38e225a5 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -486,30 +486,27 @@ class Config(object): objects_changed = False for cdist_object in self.object_list(): - try: - if cdist_object.requirements_unfinished( - cdist_object.requirements): - """We cannot do anything for this poor object""" - continue + if cdist_object.requirements_unfinished( + cdist_object.requirements): + """We cannot do anything for this poor object""" + continue - if cdist_object.state == core.CdistObject.STATE_UNDEF: - """Prepare the virgin object""" + if cdist_object.state == core.CdistObject.STATE_UNDEF: + """Prepare the virgin object""" - self.object_prepare(cdist_object) - objects_changed = True + self.object_prepare(cdist_object) + objects_changed = True - if cdist_object.requirements_unfinished( - cdist_object.autorequire): - """The previous step created objects we depend on - - wait for them - """ - continue + if cdist_object.requirements_unfinished( + cdist_object.autorequire): + """The previous step created objects we depend on - + wait for them + """ + continue - if cdist_object.state == core.CdistObject.STATE_PREPARED: - self.object_run(cdist_object) - objects_changed = True - except cdist.Error as e: - raise cdist.CdistObjectError(cdist_object, e) + if cdist_object.state == core.CdistObject.STATE_PREPARED: + self.object_run(cdist_object) + objects_changed = True return objects_changed @@ -694,42 +691,49 @@ class Config(object): def object_prepare(self, cdist_object, transfer_type_explorers=True): """Prepare object: Run type explorer + manifest""" - self.log.verbose("Preparing object {}".format(cdist_object.name)) - self.log.verbose( - "Running manifest and explorers for " + cdist_object.name) - self.explorer.run_type_explorers(cdist_object, transfer_type_explorers) - self.manifest.run_type_manifest(cdist_object) - cdist_object.state = core.CdistObject.STATE_PREPARED + try: + self.log.verbose("Preparing object {}".format(cdist_object.name)) + self.log.verbose( + "Running manifest and explorers for " + cdist_object.name) + self.explorer.run_type_explorers(cdist_object, + transfer_type_explorers) + self.manifest.run_type_manifest(cdist_object) + cdist_object.state = core.CdistObject.STATE_PREPARED + except cdist.Error as e: + raise cdist.CdistObjectError(cdist_object, e) def object_run(self, cdist_object): """Run gencode and code for an object""" + try: + self.log.verbose("Running object " + cdist_object.name) + if cdist_object.state == core.CdistObject.STATE_DONE: + raise cdist.Error(("Attempting to run an already finished " + "object: %s"), cdist_object) - self.log.verbose("Running object " + cdist_object.name) - if cdist_object.state == core.CdistObject.STATE_DONE: - raise cdist.Error(("Attempting to run an already finished " - "object: %s"), cdist_object) + # Generate + self.log.debug("Generating code for %s" % (cdist_object.name)) + cdist_object.code_local = self.code.run_gencode_local(cdist_object) + cdist_object.code_remote = self.code.run_gencode_remote( + cdist_object) + if cdist_object.code_local or cdist_object.code_remote: + cdist_object.changed = True - # Generate - self.log.debug("Generating code for %s" % (cdist_object.name)) - cdist_object.code_local = self.code.run_gencode_local(cdist_object) - cdist_object.code_remote = self.code.run_gencode_remote(cdist_object) - if cdist_object.code_local or cdist_object.code_remote: - cdist_object.changed = True + # Execute + if cdist_object.code_local or cdist_object.code_remote: + self.log.info("Processing %s" % (cdist_object.name)) + if not self.dry_run: + if cdist_object.code_local: + self.log.trace("Executing local code for %s" + % (cdist_object.name)) + self.code.run_code_local(cdist_object) + if cdist_object.code_remote: + self.log.trace("Executing remote code for %s" + % (cdist_object.name)) + self.code.transfer_code_remote(cdist_object) + self.code.run_code_remote(cdist_object) - # Execute - if cdist_object.code_local or cdist_object.code_remote: - self.log.info("Processing %s" % (cdist_object.name)) - if not self.dry_run: - if cdist_object.code_local: - self.log.trace("Executing local code for %s" - % (cdist_object.name)) - self.code.run_code_local(cdist_object) - if cdist_object.code_remote: - self.log.trace("Executing remote code for %s" - % (cdist_object.name)) - self.code.transfer_code_remote(cdist_object) - self.code.run_code_remote(cdist_object) - - # Mark this object as done - self.log.trace("Finishing run of " + cdist_object.name) - cdist_object.state = core.CdistObject.STATE_DONE + # Mark this object as done + self.log.trace("Finishing run of " + cdist_object.name) + cdist_object.state = core.CdistObject.STATE_DONE + except cdist.Error as e: + raise cdist.CdistObjectError(cdist_object, e) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index c4708eac..072ca692 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -24,6 +24,7 @@ import logging import os import glob import multiprocessing +import cdist from cdist.mputil import mp_pool_run from . import util @@ -213,19 +214,22 @@ class Explorer(object): def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" - if cdist_type.explorers: - if cdist_type.name in self._type_explorers_transferred: - self.log.trace("Skipping retransfer of type explorers for: %s", - cdist_type) - else: - source = os.path.join(self.local.type_path, - cdist_type.explorer_path) - destination = os.path.join(self.remote.type_path, - cdist_type.explorer_path) - self.remote.mkdir(destination) - self.remote.transfer(source, destination) - self.remote.run(["chmod", "0700", "%s/*" % (destination)]) - self._type_explorers_transferred.append(cdist_type.name) + try: + if cdist_type.explorers: + if cdist_type.name in self._type_explorers_transferred: + self.log.trace(("Skipping retransfer of type explorers " + "for: %s"), cdist_type) + else: + source = os.path.join(self.local.type_path, + cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, + cdist_type.explorer_path) + self.remote.mkdir(destination) + self.remote.transfer(source, destination) + self.remote.run(["chmod", "0700", "%s/*" % (destination)]) + self._type_explorers_transferred.append(cdist_type.name) + except cdist.Error as e: + raise cdist.CdistObjectError(cdist_object, e) def transfer_object_parameters(self, cdist_object): """Transfer the parameters for the given object to the remote side.""" From 2b5f1a01480a3e5ff4af0dc307387299a64db3a4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 27 Feb 2018 23:07:52 +0100 Subject: [PATCH 0756/1332] Fix a case when HOME is set but empty --- cdist/__init__.py | 9 +++++++-- docs/changelog | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index 1e2c9255..a8f6600f 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -175,6 +175,11 @@ def str_hash(s): def home_dir(): if 'HOME' in os.environ: - return os.path.join(os.environ['HOME'], ".cdist") + home = os.environ['HOME'] + if home: + rv = os.path.join(home, ".cdist") + else: + rv = None else: - return None + rv = None + return rv diff --git a/docs/changelog b/docs/changelog index bea3eb38..01c1d911 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Core: Add -4 and -6 params to force IPv4, IPv6 addresses respectively (Darko Poljak) * Type __package_update_index: Fix messaging (Thomas Eckert) * Type __package_dpkg: Add state parameter and messaging (Thomas Eckert) + * Core: Fix a case when HOME is set but empty (Darko Poljak) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From 3fb7e33305f55875424ea8521b2ba2e3893b3793 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Feb 2018 23:26:04 +0100 Subject: [PATCH 0757/1332] Bugfix: non-existent manifest not handled gracefully #639 --- cdist/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index a8f6600f..370a1e04 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -97,7 +97,7 @@ class CdistEntityError(Error): def stderr(self): output = [] for stderr_name, stderr_path in self.stderr_paths: - if os.path.getsize(stderr_path) > 0: + if os.path.exists(stderr_path) and os.path.getsize(stderr_path) > 0: label_begin = '---- BEGIN ' + stderr_name + ':stderr ----' label_end = '---- END ' + stderr_name + ':stderr ----' output.append('\n' + label_begin) From 7ccc959ebdf58d186d260bfd36966ab942117865 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Feb 2018 23:29:45 +0100 Subject: [PATCH 0758/1332] Bugfix: --beta on the commandline does not seem to work #635 Fix argparse parsers. --- cdist/argparse.py | 7 ++----- docs/src/man1/cdist.rst | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index a9f3ad9f..66a87094 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -131,7 +131,7 @@ def get_parsers(): # Main subcommand parser parser['main'] = argparse.ArgumentParser( - description='cdist ' + cdist.VERSION, parents=[parser['loglevel']]) + description='cdist ' + cdist.VERSION) parser['main'].add_argument( '-V', '--version', help='Show version.', action='version', version='%(prog)s ' + cdist.VERSION) @@ -289,10 +289,7 @@ def get_parsers(): parser['install'].set_defaults(func=cdist.install.Install.commandline) # Inventory - parser['inventory'] = parser['sub'].add_parser( - 'inventory', parents=[parser['loglevel'], parser['beta'], - parser['common'], - parser['inventory_common']]) + parser['inventory'] = parser['sub'].add_parser('inventory') parser['invsub'] = parser['inventory'].add_subparsers( title="Inventory commands", dest="subcommand") diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index c76520a6..90168f86 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -11,8 +11,7 @@ SYNOPSIS :: - cdist [-h] [-l LOGLEVEL] [-q] [-v] [-V] - {banner,config,install,inventory,shell} ... + cdist [-h] [-V] {banner,config,install,inventory,shell} ... cdist banner [-h] [-l LOGLEVEL] [-q] [-v] @@ -32,9 +31,7 @@ SYNOPSIS [-A] [-a] [-f HOSTFILE] [-p [HOST_MAX]] [-S] [-s] [-t] [host [host ...]] - cdist inventory [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] - [-I INVENTORY_DIR] - {add-host,add-tag,del-host,del-tag,list} ... + cdist inventory [-h] {add-host,add-tag,del-host,del-tag,list} ... cdist inventory add-host [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] [-I INVENTORY_DIR] From be2beba36c7da237010c52e4988289fed32f711c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Feb 2018 23:33:53 +0100 Subject: [PATCH 0759/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 01c1d911..41ff4312 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,8 @@ next: * Type __package_update_index: Fix messaging (Thomas Eckert) * Type __package_dpkg: Add state parameter and messaging (Thomas Eckert) * Core: Fix a case when HOME is set but empty (Darko Poljak) + * Core: Fix non-existent manifest non graceful handling (Darko Poljak) + * Core: Fix main and inventory parent argparse options (Darko Poljak) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From ea702c0c43042e2e27b4d9184de87dd3c16d925e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 28 Feb 2018 23:40:53 +0100 Subject: [PATCH 0760/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 41ff4312..0bf77a31 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Core: Fix a case when HOME is set but empty (Darko Poljak) * Core: Fix non-existent manifest non graceful handling (Darko Poljak) * Core: Fix main and inventory parent argparse options (Darko Poljak) + * Core: Fix lost error info with parallel jobs (option -j) (Darko Poljak) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From 23292e5cad0ce3fad0ed82342bfede3f3fb6c77f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 1 Mar 2018 19:33:22 +0100 Subject: [PATCH 0761/1332] Fix determining beta value through configuration --- cdist/argparse.py | 3 +-- cdist/configuration.py | 7 ++++++- docs/changelog | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 66a87094..fbe2bba6 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -126,8 +126,7 @@ def get_parsers(): parser['beta'].add_argument( '-b', '--beta', help=('Enable beta functionality. '), - action='store_true', dest='beta', - default=False) + action='store_true', dest='beta', default=None) # Main subcommand parser parser['main'] = argparse.ArgumentParser( diff --git a/cdist/configuration.py b/cdist/configuration.py index 2a253e7f..674551b8 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -409,7 +409,12 @@ class Configuration(metaclass=Singleton): if option in args: dst_opt = self.ARG_OPTION_MAPPING[option] option_object = self.CONFIG_FILE_OPTIONS['GLOBAL'][dst_opt] - if args[option] or isinstance(option_object, BooleanOption): + # If option is in args. + # Also if it is boolean but only if not None - this allows + # False to override True. + if (args[option] or + (isinstance(option_object, BooleanOption) and + args[option] is not None)): d[dst_opt] = args[option] return d diff --git a/docs/changelog b/docs/changelog index 0bf77a31..fadad32f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Core: Fix non-existent manifest non graceful handling (Darko Poljak) * Core: Fix main and inventory parent argparse options (Darko Poljak) * Core: Fix lost error info with parallel jobs (option -j) (Darko Poljak) + * Core: Fix determining beta value through configuration (Darko Poljak) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From 2dfbd89c5e3fa2f2cabbbe3471181c492e62412a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 1 Mar 2018 20:00:54 +0100 Subject: [PATCH 0762/1332] Fix determining save_output_streams value through configuration --- cdist/configuration.py | 24 +++++++++++++++++++----- cdist/test/configuration/__init__.py | 2 +- docs/changelog | 1 + 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/cdist/configuration.py b/cdist/configuration.py index 674551b8..ea916107 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -78,6 +78,9 @@ class OptionBase: else: return newval + def should_override(self, currval, newval): + return True + class StringOption(OptionBase): def __init__(self, name): @@ -98,8 +101,12 @@ class StringOption(OptionBase): class BooleanOption(OptionBase): BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES - def __init__(self, name): + # If default_overrides is False then previous config value will not be + # overriden with default_value. + def __init__(self, name, default_overrides=True, default_value=True): super().__init__(name) + self.default_overrides = default_overrides + self.default_value = default_value def get_converter(self): def boolean_converter(val): @@ -113,6 +120,11 @@ class BooleanOption(OptionBase): def translate(self, val): return self.BOOLEAN_STATES[val] + def should_override(self, currval, newval): + if not self.default_overrides: + return newval != self.default_value + return True + class IntOption(OptionBase): def __init__(self, name): @@ -286,7 +298,8 @@ class Configuration(metaclass=Singleton): 'parallel': JobsOption('parallel'), 'verbosity': VerbosityOption(), 'archiving': ArchivingOption(), - 'save_output_streams': BooleanOption('save_output_streams'), + 'save_output_streams': BooleanOption('save_output_streams', + default_overrides=False), }, } @@ -414,7 +427,7 @@ class Configuration(metaclass=Singleton): # False to override True. if (args[option] or (isinstance(option_object, BooleanOption) and - args[option] is not None)): + args[option] is not None)): d[dst_opt] = args[option] return d @@ -434,8 +447,9 @@ class Configuration(metaclass=Singleton): else: currval = None option_object = self.CONFIG_FILE_OPTIONS[section][option] - config[section][option] = option_object.update_value( - currval, newval, update_appends) + if option_object.should_override(currval, newval): + config[section][option] = option_object.update_value( + currval, newval, update_appends) def _update_defaults_for_unset(self, config): defaults = self.REQUIRED_DEFAULT_CONFIG_VALUES diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index 4ce3d29d..e34c30b9 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -1208,7 +1208,7 @@ class ConfigurationTestCase(test.CdistTestCase): expected_config_dict = { 'GLOBAL': { - 'save_output_streams': True, + 'save_output_streams': False, 'verbosity': 0, }, } diff --git a/docs/changelog b/docs/changelog index fadad32f..3c22ae35 100644 --- a/docs/changelog +++ b/docs/changelog @@ -11,6 +11,7 @@ next: * Core: Fix main and inventory parent argparse options (Darko Poljak) * Core: Fix lost error info with parallel jobs (option -j) (Darko Poljak) * Core: Fix determining beta value through configuration (Darko Poljak) + * Core: Fix determining save_output_streams value through configuration (Darko Poljak) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From 378c7f6a89ca98aac4c657051a63a2f1139d2c63 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 1 Mar 2018 20:12:21 +0100 Subject: [PATCH 0763/1332] Support in-distribution config file --- cdist/configuration.py | 5 ++++- docs/changelog | 1 + docs/src/cdist-configuration.rst | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cdist/configuration.py b/cdist/configuration.py index ea916107..5737105a 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -275,7 +275,10 @@ class Configuration(metaclass=Singleton): os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config/cdist')), _config_basename) - default_config_files = (_global_config_file, _local_config_file, ) + _dist_config_file = os.path.join( + os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")), + 'cdist.cfg') + default_config_files = (_global_config_file, _dist_config_file, _local_config_file, ) ENV_VAR_CONFIG_FILE = 'CDIST_CONFIG_FILE' VERBOSITY_VALUES = _VERBOSITY_VALUES diff --git a/docs/changelog b/docs/changelog index 3c22ae35..20bfda0f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -12,6 +12,7 @@ next: * Core: Fix lost error info with parallel jobs (option -j) (Darko Poljak) * Core: Fix determining beta value through configuration (Darko Poljak) * Core: Fix determining save_output_streams value through configuration (Darko Poljak) + * Core: Support in-distribution config file (Darko Poljak) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) diff --git a/docs/src/cdist-configuration.rst b/docs/src/cdist-configuration.rst index a66ddf7c..cf1e373b 100644 --- a/docs/src/cdist-configuration.rst +++ b/docs/src/cdist-configuration.rst @@ -11,6 +11,7 @@ order: #. configuration file specified in CDIST_CONFIG_FILE environment variable #. environment variables #. user's configuration file (first one found of ~/.cdist.cfg, $XDG_CONFIG_HOME/cdist/cdist.cfg, in specified order) + #. in-distribution configuration file (cdist/conf/cdist.cfg) #. system-wide configuration file (/etc/cdist.cfg) if one exists. From b8ed816af450b68a4d7694bff9af23e6661b3f0e Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 5 Mar 2018 12:40:11 +0100 Subject: [PATCH 0764/1332] Add __apt_default_release type (#643) --- cdist/conf/type/__apt_default_release/man.rst | 46 +++++++++++++++++++ .../conf/type/__apt_default_release/manifest | 41 +++++++++++++++++ .../__apt_default_release/parameter/required | 1 + .../conf/type/__apt_default_release/singleton | 0 4 files changed, 88 insertions(+) create mode 100644 cdist/conf/type/__apt_default_release/man.rst create mode 100755 cdist/conf/type/__apt_default_release/manifest create mode 100644 cdist/conf/type/__apt_default_release/parameter/required create mode 100644 cdist/conf/type/__apt_default_release/singleton diff --git a/cdist/conf/type/__apt_default_release/man.rst b/cdist/conf/type/__apt_default_release/man.rst new file mode 100644 index 00000000..0277a06f --- /dev/null +++ b/cdist/conf/type/__apt_default_release/man.rst @@ -0,0 +1,46 @@ +cdist-type__apt_default_release(7) +================================== + +NAME +---- +cdist-type__apt_default_release - Configure the default release for apt + + +DESCRIPTION +----------- +Configure the default release for apt, using the APT::Default-Release +configuration value. + +REQUIRED PARAMETERS +------------------- +release + The value to set APT::Default-Release to. + + This can contain release name, codename or release version. Examples: + 'stable', 'testing', 'unstable', 'stretch', 'buster', '4.0', '5.0*'. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + __apt_default_release --release stretch + + +AUTHORS +------- +Matthijs Kooijman + + +COPYING +------- +Copyright \(C) 2017 Matthijs Kooijman. 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_default_release/manifest b/cdist/conf/type/__apt_default_release/manifest new file mode 100755 index 00000000..1232efb5 --- /dev/null +++ b/cdist/conf/type/__apt_default_release/manifest @@ -0,0 +1,41 @@ +#!/bin/sh -e +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2017 Matthijs Kooijman (matthijs at stdin.nl) +# +# 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 . +# + + +os=$(cat "$__global/explorer/os") +release="$(cat "$__object/parameter/release")" + +case "$os" in + ubuntu|debian|devuan) + __file /etc/apt/apt.conf.d/99-default-release \ + --owner root --group root --mode 644 \ + --source - << DONE +APT::Default-Release "$release"; +DONE + ;; + *) + cat >&2 << DONE +The developer of this type (${__type##*/}) did not think your operating system +($os) would have any use for it. If you think otherwise please submit a patch. +DONE + exit 1 + ;; +esac diff --git a/cdist/conf/type/__apt_default_release/parameter/required b/cdist/conf/type/__apt_default_release/parameter/required new file mode 100644 index 00000000..d7025695 --- /dev/null +++ b/cdist/conf/type/__apt_default_release/parameter/required @@ -0,0 +1 @@ +release diff --git a/cdist/conf/type/__apt_default_release/singleton b/cdist/conf/type/__apt_default_release/singleton new file mode 100644 index 00000000..e69de29b From 2b85e4f14bdfa76533788e19bbe7134d07c456b2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 5 Mar 2018 12:41:42 +0100 Subject: [PATCH 0765/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 20bfda0f..e40d7f64 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,7 @@ next: * Core: Fix determining beta value through configuration (Darko Poljak) * Core: Fix determining save_output_streams value through configuration (Darko Poljak) * Core: Support in-distribution config file (Darko Poljak) + * New type: __apt_default_release (Matthijs Kooijman) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From a9a359d54239c117ae46d89aa59ad6f64be986a2 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 6 Mar 2018 07:33:22 +0100 Subject: [PATCH 0766/1332] Add pre-exists state to __file (#641) This allows checking whether a file exists, but erroring out instead of creating the file if it does not (or is not a regular file). --- cdist/conf/type/__file/gencode-local | 14 ++++++++++++++ cdist/conf/type/__file/gencode-remote | 2 +- cdist/conf/type/__file/man.rst | 9 +++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index aec4e43e..15a9ee0e 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -25,6 +25,20 @@ type="$(cat "$__object/explorer/type")" [ "$state_should" = "exists" -a "$type" = "file" ] && exit 0 # nothing to do +if [ "$state_should" = "pre-exists" ]; then + if [ -f "$__object/parameter/source" ]; then + echo "--source cannot be used with --state pre-exists" + exit 1 + fi + + if [ "$type" = "file" ]; then + exit 0 # nothing to do + else + echo "File \"$destination\" does not exist" + exit 1 + fi +fi + upload_file= create_file= if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index fe1e2212..c90be0be 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -59,7 +59,7 @@ set_mode() { set_attributes= case "$state_should" in - present|exists) + present|exists|pre-exists) # 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 diff --git a/cdist/conf/type/__file/man.rst b/cdist/conf/type/__file/man.rst index 7d9b413b..d06fc275 100644 --- a/cdist/conf/type/__file/man.rst +++ b/cdist/conf/type/__file/man.rst @@ -23,6 +23,10 @@ symlink directory replace it with the source file +One exception is that when state is pre-exists, an error is raised if +the file would have been created otherwise (e.g. it is not present or +not a regular file). + In any case, make sure that the file attributes are as specified. @@ -41,6 +45,9 @@ state the file does not exist exists the file from source but only if it doesn't already exist + pre-exists + check that the file exists and is a regular file, but do not + create or modify it group Group to chgrp to. @@ -93,6 +100,8 @@ EXAMPLES __file /home/frodo/.bashrc --source "/etc/skel/.bashrc" \ --state exists \ --owner frodo --mode 0600 + # Check that the file is present, show an error when it is not + __file /etc/somefile --state pre-exists # Take file content from stdin __file /tmp/whatever --owner root --group root --mode 644 --source - << DONE Here goes the content for /tmp/whatever From aba8dc496564a235167bcb2c47aacf3316334fe8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 6 Mar 2018 07:33:19 +0100 Subject: [PATCH 0767/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e40d7f64..9536fd0a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -14,6 +14,7 @@ next: * Core: Fix determining save_output_streams value through configuration (Darko Poljak) * Core: Support in-distribution config file (Darko Poljak) * New type: __apt_default_release (Matthijs Kooijman) + * Type __file: Add pre-exists state (Matthijs Kooijman) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From 05084c6fc666e31462f400e9d16945a6830def77 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 6 Mar 2018 07:35:27 +0100 Subject: [PATCH 0768/1332] pep8 --- cdist/__init__.py | 3 ++- cdist/configuration.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index 370a1e04..e6fdfac6 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -97,7 +97,8 @@ class CdistEntityError(Error): def stderr(self): output = [] for stderr_name, stderr_path in self.stderr_paths: - if os.path.exists(stderr_path) and os.path.getsize(stderr_path) > 0: + if (os.path.exists(stderr_path) and + os.path.getsize(stderr_path) > 0): label_begin = '---- BEGIN ' + stderr_name + ':stderr ----' label_end = '---- END ' + stderr_name + ':stderr ----' output.append('\n' + label_begin) diff --git a/cdist/configuration.py b/cdist/configuration.py index 5737105a..848956aa 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -278,7 +278,8 @@ class Configuration(metaclass=Singleton): _dist_config_file = os.path.join( os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")), 'cdist.cfg') - default_config_files = (_global_config_file, _dist_config_file, _local_config_file, ) + default_config_files = (_global_config_file, _dist_config_file, + _local_config_file, ) ENV_VAR_CONFIG_FILE = 'CDIST_CONFIG_FILE' VERBOSITY_VALUES = _VERBOSITY_VALUES From bc94c01c49ffe5e9fda477a2695a5acfc874138a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 6 Mar 2018 07:39:50 +0100 Subject: [PATCH 0769/1332] Amend __file man. --- cdist/conf/type/__file/man.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__file/man.rst b/cdist/conf/type/__file/man.rst index d06fc275..a141d70b 100644 --- a/cdist/conf/type/__file/man.rst +++ b/cdist/conf/type/__file/man.rst @@ -37,7 +37,7 @@ None. OPTIONAL PARAMETERS ------------------- state - 'present', 'absent' or 'exists', defaults to 'present' where: + 'present', 'absent', 'exists' or 'pre-exists', defaults to 'present' where: present the file is exactly the one from source From bfe8b8fa57f4cad886417b3a253e47c24a3d1f83 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Mar 2018 20:52:55 +0100 Subject: [PATCH 0770/1332] Support stretch + ascii in __grafana_dashboard --- cdist/conf/type/__grafana_dashboard/manifest | 18 +++++++++++++++++- docs/changelog | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest index 898770dd..8f089367 100755 --- a/cdist/conf/type/__grafana_dashboard/manifest +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -20,7 +20,23 @@ case $os in require="__apt_source/grafana __package/apt-transport-https" __package grafana require="__package/grafana" __start_on_boot grafana-server - ;; + ;; + 9*|ascii/ceres) + __apt_key_uri grafana \ + --name 'Grafana Release Signing Key' \ + --uri https://packagecloud.io/gpg.key + + require="__apt_key_uri/grafana" __apt_source grafana \ + --uri https://packagecloud.io/grafana/stable/debian/ \ + --distribution stretch \ + --component main + + __package apt-transport-https + + require="__apt_source/grafana __package/apt-transport-https" __package grafana + require="__package/grafana" __start_on_boot grafana-server + ;; + *) echo "Don't know how to install Grafana on $os $os_version. Send us a pull request!" exit 1 diff --git a/docs/changelog b/docs/changelog index 9536fd0a..0b5c5f17 100644 --- a/docs/changelog +++ b/docs/changelog @@ -15,6 +15,7 @@ next: * Core: Support in-distribution config file (Darko Poljak) * New type: __apt_default_release (Matthijs Kooijman) * Type __file: Add pre-exists state (Matthijs Kooijman) + * Type __grafana_dashboard: Add support for stretch + ascii (Nico Schottelius) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From 54ca7b40c7b546e6460850ba1606d3858800e39c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 6 Mar 2018 22:33:10 +0100 Subject: [PATCH 0771/1332] Update consul agent init script so that it works again on Devuan Error before: ---- BEGIN code-remote:stderr ---- insserv: warning: script 'consul' missing LSB tags and overrides insserv: There is a loop between service monit and consul if stopped insserv: loop involving service consul at depth 2 insserv: loop involving service monit at depth 1 insserv: Stopping consul depends on monit and therefore on system facility `$all' which can not be true! insserv: exiting now without changing boot order! update-rc.d: error: insserv rejected the script header --- .../type/__consul_agent/files/consul.sysv-debian | 13 ++++++++++++- docs/changelog | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul_agent/files/consul.sysv-debian b/cdist/conf/type/__consul_agent/files/consul.sysv-debian index a75c555d..a699e64a 100644 --- a/cdist/conf/type/__consul_agent/files/consul.sysv-debian +++ b/cdist/conf/type/__consul_agent/files/consul.sysv-debian @@ -1,6 +1,6 @@ #!/bin/sh # -# 2015 Nico Schottelius (nico-cdist at schottelius.org) +# 2015-2018 Nico Schottelius (nico-cdist at schottelius.org) # 2015 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. @@ -18,6 +18,17 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # +### BEGIN INIT INFO +# Provides: consul +# Required-Start: $remote_fs +# Required-Stop: $remote_fs +# Should-Start: $all +# Should-Stop: $all +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: consul +# Description: consul agent +### END INIT INFO if [ -f "/etc/default/consul" ]; then . /etc/default/consul diff --git a/docs/changelog b/docs/changelog index 0b5c5f17..22249b92 100644 --- a/docs/changelog +++ b/docs/changelog @@ -16,6 +16,7 @@ next: * New type: __apt_default_release (Matthijs Kooijman) * Type __file: Add pre-exists state (Matthijs Kooijman) * Type __grafana_dashboard: Add support for stretch + ascii (Nico Schottelius) + * Type __consul_agent: Update Debian Sys-V-Init script (Nico Schottelius) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From b0c5bc793d768250af95c8f1e623787a4a74d0c7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 9 Mar 2018 09:58:49 +0100 Subject: [PATCH 0772/1332] Fix "label empty or too long" error #645 --- cdist/config.py | 11 ++++++++++- docs/changelog | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index 38e225a5..74f68a72 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -333,6 +333,15 @@ class Config(object): family = 0 return family + @staticmethod + def resolve_target_addresses(host, family): + try: + return ipaddr.resolve_target_addresses(host, family) + except: + e = sys.exc_info()[1] + raise cdist.Error(("Error resolving target addresses for host '{}'" + ": {}").format(host, e)) + @classmethod def onehost(cls, host, host_tags, host_base_path, host_dir_name, args, parallel, configuration, remove_remote_files_dirs=False): @@ -353,7 +362,7 @@ class Config(object): family = cls._address_family(args) log.debug("address family: {}".format(family)) - target_host = ipaddr.resolve_target_addresses(host, family) + target_host = cls.resolve_target_addresses(host, family) log.debug("target_host for host \"{}\": {}".format( host, target_host)) diff --git a/docs/changelog b/docs/changelog index 0b5c5f17..3ceae2ec 100644 --- a/docs/changelog +++ b/docs/changelog @@ -16,6 +16,7 @@ next: * New type: __apt_default_release (Matthijs Kooijman) * Type __file: Add pre-exists state (Matthijs Kooijman) * Type __grafana_dashboard: Add support for stretch + ascii (Nico Schottelius) + * Core: Fix idna (getaddrinfo) unicode tracebak for invalid host name (Darko Poljak) 4.8.0: 2018-02-14 * Core: Skip empty lines in parameter files (Darko Poljak) From 5090038e4ca8d3fbc21fd0cb3ba96c448407d858 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 9 Mar 2018 10:00:14 +0100 Subject: [PATCH 0773/1332] Add test-remote target - remote is not tested with test target --- Makefile | 3 +++ bin/build-helper | 5 +++++ bin/build-helper.freebsd | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/Makefile b/Makefile index e33be3f2..d727bccc 100644 --- a/Makefile +++ b/Makefile @@ -247,5 +247,8 @@ pub: test: $(helper) $@ +test-remote: + $(helper) $@ + pep8: $(helper) $@ diff --git a/bin/build-helper b/bin/build-helper index 46b139d1..ef15b6c2 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -359,6 +359,11 @@ eof fi ;; + test-remote) + export PYTHONPATH="$(pwd -P)" + python3 -m cdist.test.exec.remote + ;; + pep8) pep8 "${basedir}" "${basedir}/scripts/cdist" | less ;; diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 183129db..e49b2f7a 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -421,6 +421,11 @@ eof fi ;; + test-remote) + export PYTHONPATH="$(pwd -P)" + python3 -m cdist.test.exec.remote + ;; + pep8) pep8 "${basedir}" "${basedir}/scripts/cdist" | less ;; From fc79fe86a243eb6bc842e1582870a3031cdb94d3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 9 Mar 2018 17:25:01 +0100 Subject: [PATCH 0774/1332] Release 4.8.1 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 3ceae2ec..abe36509 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.8.1: 2018-03-09 * Type __consul: Add option for directly downloading on target host (Darko Poljak) * Core: Add -4 and -6 params to force IPv4, IPv6 addresses respectively (Darko Poljak) * Type __package_update_index: Fix messaging (Thomas Eckert) From fe870ba8ba9afa09bd7339b869dedf07ccf57e92 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 10 Mar 2018 11:12:31 +0100 Subject: [PATCH 0775/1332] Loglevel arguments not parsed but accessed #646 --- cdist/argparse.py | 2 +- docs/changelog | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index fbe2bba6..29620751 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -434,7 +434,7 @@ def get_parsers(): def handle_loglevel(args): - if args.quiet: + if hasattr(args, 'quiet') and args.quiet: args.verbose = _verbosity_level_off logging.root.setLevel(_verbosity_level[args.verbose]) diff --git a/docs/changelog b/docs/changelog index abe36509..a86cc6b0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Fix quiet argument access for bare cdist command (Darko Poljak) + 4.8.1: 2018-03-09 * Type __consul: Add option for directly downloading on target host (Darko Poljak) * Core: Add -4 and -6 params to force IPv4, IPv6 addresses respectively (Darko Poljak) From b58cb810acd3e36c1feb4b27c92415845e32f000 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 10 Mar 2018 23:49:50 +0100 Subject: [PATCH 0776/1332] Release 4.8.2 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index a86cc6b0..344d18a1 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.8.2: 2018-03-10 * Core: Fix quiet argument access for bare cdist command (Darko Poljak) 4.8.1: 2018-03-09 From 8a488591bb190d712fd44588ae727d1eb92fdac3 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Sun, 11 Mar 2018 00:47:33 +0100 Subject: [PATCH 0777/1332] __prometheus_server: switch to packages; assume prometheus 2.x --- cdist/conf/type/__prometheus_server/man.rst | 24 ++------ cdist/conf/type/__prometheus_server/manifest | 61 ++++++++++++------- .../__prometheus_server/parameter/boolean | 1 + .../__prometheus_server/parameter/required | 2 - 4 files changed, 45 insertions(+), 43 deletions(-) create mode 100644 cdist/conf/type/__prometheus_server/parameter/boolean diff --git a/cdist/conf/type/__prometheus_server/man.rst b/cdist/conf/type/__prometheus_server/man.rst index fadebd3f..33dd3e53 100644 --- a/cdist/conf/type/__prometheus_server/man.rst +++ b/cdist/conf/type/__prometheus_server/man.rst @@ -10,18 +10,12 @@ DESCRIPTION ----------- Install and configure Prometheus (https://prometheus.io/). -This type creates a daemontools-compatible service directory under /service/prometheus. -Daemontools (or something compatible) must be installed (in particular, the command `svc` must be executable). - +Note that due to significant differences between Prometheus 1.x and 2.x, only 2.x is supported. REQUIRED PARAMETERS ------------------- config Prometheus configuration file. It will be saved as /etc/prometheus/prometheus.yml on the target. -listen-address - Passed as web.listen-address. -alertmanager-url - Passed as alertmanager.url OPTIONAL PARAMETERS @@ -32,8 +26,6 @@ rule-files Path to rule files. They will be installed under /etc/prometheus/. You need to include `rule_files: [/etc/prometheus/]` in the config file if you use this. storage-path Where to put data. Default: /data/prometheus. (Directory will be created if needed.) -target-heap-size - Passed as storage.local.target-heap-size. Default: 1/2 of RAM. BOOLEAN PARAMETERS @@ -49,22 +41,16 @@ EXAMPLES PROMPORT=9090 ALERTPORT=9093 - __daemontools - __golang_from_vendor --version 1.8.1 # required for prometheus and many exporters - - require="__daemontools __golang_from_vendor" __prometheus_server \ - --with-daemontools \ + __prometheus_server \ --config "$__manifest/files/prometheus.yml" \ --retention-days 14 \ --storage-path /data/prometheus \ - --listen-address "[::]:$PROMPORT" \ - --rule-files "$__manifest/files/*.rules" \ - --alertmanager-url "http://monitoring1.node.consul:$ALERTPORT,http://monitoring2.node.consul:$ALERTPORT" + --rule-files "$__manifest/files/*.rules" SEE ALSO -------- -:strong:`cdist-type__prometheus_alertmanager`\ (7), :strong:`cdist-type__daemontools`\ (7), +:strong:`cdist-type__prometheus_alertmanager`\ (7), :strong:`cdist-type__grafana_dashboard`\ (7), Prometheus documentation: https://prometheus.io/docs/introduction/overview/ AUTHORS @@ -73,7 +59,7 @@ Kamila Součková COPYING ------- -Copyright \(C) 2017 Kamila Součková. You can redistribute it +Copyright \(C) 2018 Kamila Součková. 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/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index 96717ed6..d19d35b1 100755 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -1,52 +1,69 @@ #!/bin/sh -e -GOBIN=/opt/gocode/bin # where to find go binaries +##### HARD-CODED CONFIG ##################################################### + CONF_DIR=/etc/prometheus CONF=$CONF_DIR/prometheus.yml -LOGLEVEL=info + +##### GET SETTINGS ########################################################## config="$(cat "$__object/parameter/config")" retention_days="$(cat "$__object/parameter/retention-days")" storage_path="$(cat "$__object/parameter/storage-path")" -listen_address="$(cat "$__object/parameter/listen-address")" -alertmanager_url="$(cat "$__object/parameter/alertmanager-url")" -target_heap_size="$(cat "$__object/parameter/target-heap-size")" rule_files="$(cat "$__object/parameter/rule-files")" # explorer in kB => convert; by default we go with 1/2 RAM [ "$target_heap_size" = "auto" ] && target_heap_size=$(($(cat $__global/explorer/memory)*1024/2)) +##### INSTALL THE PACKAGE ################################################### -FLAGS="config.file '$CONF' -storage.local.path '$storage_path' -storage.local.target-heap-size $(($target_heap_size)) # in bytes; should be 2/3 of available memory because it may be hungry -storage.local.retention $(($retention_days*24))h # golang doesn't have days :D -web.listen-address '$listen_address' -alertmanager.url '$alertmanager_url' -log.level $LOGLEVEL" +if [ -f "$__object/parameter/install-from-backports" ]; then + os=$(cat "$__global/explorer/os") + lsb_codename=$(cat "$__global/explorer/lsb_codename") -REAL_FLAGS="$(echo "$FLAGS" | sed -nE 's/^([^#]+).*/ --\1 \\/p')" + case $os in + devuan) + if [ -z "$lsb_codename" ]; then + echo "Command `lsb_release` not functional -- is package `lsb-release` installed?" >&2 + exit 1 + fi + [ "$lsb_codename" = "n/a" ] && lsb_codename='ascii' # TODO this is a devuan bug that should be fixed soon => remove when no longer needed + __apt_source backports --uri http://auto.mirror.devuan.org/merged --distribution $lsb_codename-backports --component main + require="$require __apt_source/backports" __package_apt prometheus --target-release $lsb_codename-backports + ;; + *) + echo "--install-from-backports is only supported on Devuan -- ignoring" >&2 + echo "send a pull request if you require it" >&2 + ;; + esac +else + __package prometheus +fi -__go_get github.com/prometheus/prometheus/cmd/... +##### PREPARE PATHS AND SUCH ################################################ -__user prometheus --system -require="__user/prometheus" __directory "$storage_path" --owner prometheus --parents -require="__user/prometheus" __directory "$CONF_DIR" --owner prometheus --parents +require="__package_apt/prometheus" __directory "$storage_path" --owner prometheus --parents -__daemontools_service prometheus --run "setuidgid prometheus $GOBIN/prometheus $REAL_FLAGS" +##### CONFIGURE ############################################################# -require="$require __directory/$storage_path __user/prometheus" \ +FLAGS="--storage.tsdb.path $storage_path --storage.tsdb.retention $(($retention_days*24))h" + +# TODO it would be neat to restart prometheus on change -- __key_value really should have an --onchange parameter +require="$require __package_apt/prometheus" \ +__key_value prometheus_args --file /etc/default/prometheus --key "ARGS" --value "\"$FLAGS\"" --delimiter "=" + +require="$require __directory/$storage_path __package_apt/prometheus" \ __config_file $CONF \ --source $config \ --group prometheus --mode 640 \ - --onchange "$GOBIN/promtool check-config $CONF && svc -h /service/prometheus" + --onchange "promtool check config $CONF && service prometheus reload" for file in $rule_files; do dest=$CONF_DIR/$(basename $file) - require="$require __directory/$CONF_DIR __user/prometheus" \ + require="$require __package_apt/prometheus" \ __config_file "$dest" \ --source "$file" \ --owner prometheus \ - --onchange "$GOBIN/promtool check-rules '$dest' && svc -h /service/prometheus" + --onchange "promtool check rules '$dest' && service prometheus reload" done diff --git a/cdist/conf/type/__prometheus_server/parameter/boolean b/cdist/conf/type/__prometheus_server/parameter/boolean new file mode 100644 index 00000000..5d15e93d --- /dev/null +++ b/cdist/conf/type/__prometheus_server/parameter/boolean @@ -0,0 +1 @@ +install-from-backports diff --git a/cdist/conf/type/__prometheus_server/parameter/required b/cdist/conf/type/__prometheus_server/parameter/required index 49abf924..04204c7c 100644 --- a/cdist/conf/type/__prometheus_server/parameter/required +++ b/cdist/conf/type/__prometheus_server/parameter/required @@ -1,3 +1 @@ -alertmanager-url config -listen-address From ee6d63325d5e0267be90a70ae0c9db0e35764968 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Sun, 11 Mar 2018 01:28:26 +0100 Subject: [PATCH 0778/1332] new __prometheus_alertmanager; fixes to __prometheus_server --- .../type/__prometheus_alertmanager/manifest | 62 ++++++++++++++----- .../parameter/boolean | 1 + .../parameter/default/retention-days | 1 + .../parameter/optional | 1 + .../parameter/required | 1 - cdist/conf/type/__prometheus_server/manifest | 13 ++-- .../parameter/default/target-heap-size | 1 - .../__prometheus_server/parameter/optional | 1 - 8 files changed, 57 insertions(+), 24 deletions(-) create mode 100644 cdist/conf/type/__prometheus_alertmanager/parameter/boolean create mode 100644 cdist/conf/type/__prometheus_alertmanager/parameter/default/retention-days delete mode 100644 cdist/conf/type/__prometheus_server/parameter/default/target-heap-size diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index 0dbce3c2..926ad712 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -1,34 +1,64 @@ #!/bin/sh -e -GOBIN=/opt/gocode/bin # where to find go binaries +##### HARD-CODED CONFIG ##################################################### + CONF_DIR=/etc/prometheus -LOGLEVEL=info CONF=$CONF_DIR/alertmanager.yml -### Prometheus server ####################################################### +##### GET SETTINGS ########################################################## config="$(cat "$__object/parameter/config")" +retention_days="$(cat "$__object/parameter/retention-days")" storage_path="$(cat "$__object/parameter/storage-path")" -listen_address="$(cat "$__object/parameter/listen-address")" +# listen_address="$(cat "$__object/parameter/listen-address")" -FLAGS="config.file '$CONF' -storage.path '$storage_path' -web.listen-address '$listen_address' -log.level $LOGLEVEL" +##### INSTALL THE PACKAGE ################################################### -REAL_FLAGS="$(echo "$FLAGS" | sed -nE 's/^([^#]+).*/ --\1 \\/p')" +require_pkg="" # what to require if I want to require "the package" +if [ -f "$__object/parameter/install-from-backports" ]; then + os=$(cat "$__global/explorer/os") + lsb_codename=$(cat "$__global/explorer/lsb_codename") -__go_get github.com/prometheus/alertmanager/cmd/... + case $os in + devuan) + if [ -z "$lsb_codename" ]; then + echo "Command `lsb_release` not functional -- is package `lsb-release` installed?" >&2 + exit 1 + fi + [ "$lsb_codename" = "n/a" ] && lsb_codename='ascii' # TODO this is a devuan bug that should be fixed soon => remove when no longer needed + __apt_source backports --uri http://auto.mirror.devuan.org/merged --distribution $lsb_codename-backports --component main + require="$require __apt_source/backports" __package_apt prometheus-alertmanager --target-release $lsb_codename-backports + require_pkg="__package_apt/prometheus-alertmanager" + ;; + *) + echo "--install-from-backports is only supported on Devuan -- ignoring" >&2 + echo "send a pull request if you require it" >&2 + ;; + esac +else + __package prometheus-alertmanager + require_pkg="__package/prometheus-alertmanager" +fi -__user prometheus --system -require="__user/prometheus" __directory "$storage_path" --owner prometheus --parents -require="__user/prometheus" __directory "$CONF_DIR" --owner prometheus --parents +##### PREPARE PATHS AND SUCH ################################################ -__daemontools_service alertmanager --run "setuidgid prometheus $GOBIN/alertmanager $REAL_FLAGS" +require="$require $require_pkg" __directory "$storage_path" --owner prometheus --parents -require="$require __directory/$storage_path __user/prometheus" \ +# TODO this is a bug in the init script, patching it like this is awful and it should be reported +require="$require $require_pkg" \ +__key_value alertmanager_fix_init_script --file /etc/init.d/prometheus-alertmanager --key="NAME" --value="prometheus-alertmanager" --delimiter "=" + + +##### CONFIGURE ############################################################# + +FLAGS="--storage.path $storage_path --data.retention $(($retention_days*24))h --web.listen-address [::]:9093" + +require="$require $require_pkg" \ +__key_value alertmanager_args --file /etc/default/prometheus-alertmanager --key="ARGS" --value="\"$FLAGS\"" --delimiter "=" + +require="$require __directory/$storage_path $require_pkg" \ __config_file $CONF \ --source $config \ --group prometheus --mode 640 \ - --onchange "svc -h /service/alertmanager" # TODO when a config-check tool is available, check config here + --onchange "service prometheus-alertmanager reload" # TODO when a config-check tool is available, check config here diff --git a/cdist/conf/type/__prometheus_alertmanager/parameter/boolean b/cdist/conf/type/__prometheus_alertmanager/parameter/boolean new file mode 100644 index 00000000..5d15e93d --- /dev/null +++ b/cdist/conf/type/__prometheus_alertmanager/parameter/boolean @@ -0,0 +1 @@ +install-from-backports diff --git a/cdist/conf/type/__prometheus_alertmanager/parameter/default/retention-days b/cdist/conf/type/__prometheus_alertmanager/parameter/default/retention-days new file mode 100644 index 00000000..d61f00d8 --- /dev/null +++ b/cdist/conf/type/__prometheus_alertmanager/parameter/default/retention-days @@ -0,0 +1 @@ +90 diff --git a/cdist/conf/type/__prometheus_alertmanager/parameter/optional b/cdist/conf/type/__prometheus_alertmanager/parameter/optional index f99d0d37..7fe79009 100644 --- a/cdist/conf/type/__prometheus_alertmanager/parameter/optional +++ b/cdist/conf/type/__prometheus_alertmanager/parameter/optional @@ -1 +1,2 @@ storage-path +retention-days diff --git a/cdist/conf/type/__prometheus_alertmanager/parameter/required b/cdist/conf/type/__prometheus_alertmanager/parameter/required index 02cb49d0..04204c7c 100644 --- a/cdist/conf/type/__prometheus_alertmanager/parameter/required +++ b/cdist/conf/type/__prometheus_alertmanager/parameter/required @@ -1,2 +1 @@ config -listen-address diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index d19d35b1..a5c31b4e 100755 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -17,6 +17,7 @@ rule_files="$(cat "$__object/parameter/rule-files")" ##### INSTALL THE PACKAGE ################################################### +require_pkg="" # what to require if I want to require "the package" if [ -f "$__object/parameter/install-from-backports" ]; then os=$(cat "$__global/explorer/os") lsb_codename=$(cat "$__global/explorer/lsb_codename") @@ -30,6 +31,7 @@ if [ -f "$__object/parameter/install-from-backports" ]; then [ "$lsb_codename" = "n/a" ] && lsb_codename='ascii' # TODO this is a devuan bug that should be fixed soon => remove when no longer needed __apt_source backports --uri http://auto.mirror.devuan.org/merged --distribution $lsb_codename-backports --component main require="$require __apt_source/backports" __package_apt prometheus --target-release $lsb_codename-backports + require_pkg="__package_apt/prometheus" ;; *) echo "--install-from-backports is only supported on Devuan -- ignoring" >&2 @@ -38,21 +40,22 @@ if [ -f "$__object/parameter/install-from-backports" ]; then esac else __package prometheus + require_pkg="__package/prometheus" fi ##### PREPARE PATHS AND SUCH ################################################ -require="__package_apt/prometheus" __directory "$storage_path" --owner prometheus --parents +require="$require $require_pkg" __directory "$storage_path" --owner prometheus --parents ##### CONFIGURE ############################################################# -FLAGS="--storage.tsdb.path $storage_path --storage.tsdb.retention $(($retention_days*24))h" +FLAGS="--storage.tsdb.path $storage_path --storage.tsdb.retention $(($retention_days*24))h --web.listen-address [::]:9090" # TODO it would be neat to restart prometheus on change -- __key_value really should have an --onchange parameter -require="$require __package_apt/prometheus" \ +require="$require $require_pkg" \ __key_value prometheus_args --file /etc/default/prometheus --key "ARGS" --value "\"$FLAGS\"" --delimiter "=" -require="$require __directory/$storage_path __package_apt/prometheus" \ +require="$require __directory/$storage_path $require_pkg" \ __config_file $CONF \ --source $config \ --group prometheus --mode 640 \ @@ -60,7 +63,7 @@ __config_file $CONF \ for file in $rule_files; do dest=$CONF_DIR/$(basename $file) - require="$require __package_apt/prometheus" \ + require="$require $require_pkg" \ __config_file "$dest" \ --source "$file" \ --owner prometheus \ diff --git a/cdist/conf/type/__prometheus_server/parameter/default/target-heap-size b/cdist/conf/type/__prometheus_server/parameter/default/target-heap-size deleted file mode 100644 index 865faf10..00000000 --- a/cdist/conf/type/__prometheus_server/parameter/default/target-heap-size +++ /dev/null @@ -1 +0,0 @@ -auto diff --git a/cdist/conf/type/__prometheus_server/parameter/optional b/cdist/conf/type/__prometheus_server/parameter/optional index 4d8d8f3e..cb437211 100644 --- a/cdist/conf/type/__prometheus_server/parameter/optional +++ b/cdist/conf/type/__prometheus_server/parameter/optional @@ -1,4 +1,3 @@ -target-heap-size retention-days rule-files storage-path From 34aefbc0f6ea3340c6661f1c23be3ae1fe5f0a71 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Sun, 11 Mar 2018 01:35:16 +0100 Subject: [PATCH 0779/1332] __prometheus_{server,alertmanager}: new man pages --- .../type/__prometheus_alertmanager/man.rst | 25 ++++++++----------- .../type/__prometheus_alertmanager/manifest | 1 - cdist/conf/type/__prometheus_server/man.rst | 4 ++- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/cdist/conf/type/__prometheus_alertmanager/man.rst b/cdist/conf/type/__prometheus_alertmanager/man.rst index ba99e7c8..894100c8 100644 --- a/cdist/conf/type/__prometheus_alertmanager/man.rst +++ b/cdist/conf/type/__prometheus_alertmanager/man.rst @@ -18,19 +18,20 @@ REQUIRED PARAMETERS ------------------- config Alertmanager configuration file. It will be saved as /etc/alertmanager/alertmanager.yml on the target. -listen-address - Passed as web.listen-address. OPTIONAL PARAMETERS ------------------- storage-path Where to put data. Default: /data/alertmanager. (Directory will be created if needed.) +retention-days + How long to retain data. Default: 90 days. BOOLEAN PARAMETERS ------------------ -None +install-from-backports + Valid on Devuan only. Will enable the backports apt source and install the package from there. Useful for getting a newer version. EXAMPLES @@ -38,21 +39,15 @@ EXAMPLES .. code-block:: sh - ALERTPORT=9093 - - __daemontools - __golang_from_vendor --version 1.8.1 # required for prometheus and many exporters - - require="__daemontools __golang_from_vendor" __prometheus_alertmanager \ - --with-daemontools \ - --config "$__manifest/files/alertmanager.yml" \ - --storage-path /data/alertmanager \ - --listen-address "[::]:$ALERTPORT" + __prometheus_alertmanager \ + --install-from-backports \ + --config "$__manifest/files/alertmanager.yml" \ + --storage-path /data/alertmanager SEE ALSO -------- -:strong:`cdist-type__prometheus_server`\ (7), :strong:`cdist-type__daemontools`\ (7), +:strong:`cdist-type__prometheus_server`\ (7), :strong:`cdist-type__grafana_dashboard`\ (7), Prometheus alerting documentation: https://prometheus.io/docs/alerting/overview/ AUTHORS @@ -61,7 +56,7 @@ Kamila Součková COPYING ------- -Copyright \(C) 2017 Kamila Součková. You can redistribute it +Copyright \(C) 2018 Kamila Součková. 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/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index 926ad712..8278170a 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -48,7 +48,6 @@ require="$require $require_pkg" __directory "$storage_path" --owner prometheus - require="$require $require_pkg" \ __key_value alertmanager_fix_init_script --file /etc/init.d/prometheus-alertmanager --key="NAME" --value="prometheus-alertmanager" --delimiter "=" - ##### CONFIGURE ############################################################# FLAGS="--storage.path $storage_path --data.retention $(($retention_days*24))h --web.listen-address [::]:9093" diff --git a/cdist/conf/type/__prometheus_server/man.rst b/cdist/conf/type/__prometheus_server/man.rst index 33dd3e53..4308e6c4 100644 --- a/cdist/conf/type/__prometheus_server/man.rst +++ b/cdist/conf/type/__prometheus_server/man.rst @@ -30,7 +30,8 @@ storage-path BOOLEAN PARAMETERS ------------------ -None +install-from-backports + Valid on Devuan only. Will enable the backports apt source and install the package from there. Useful for getting a newer version. EXAMPLES @@ -42,6 +43,7 @@ EXAMPLES ALERTPORT=9093 __prometheus_server \ + --install-from-backports \ --config "$__manifest/files/prometheus.yml" \ --retention-days 14 \ --storage-path /data/prometheus \ From 7ae24cf67785d98c8877e363cf53ad411f2d601b Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Sun, 11 Mar 2018 10:52:25 +0100 Subject: [PATCH 0780/1332] __grafana_dashboard: cleanup --- cdist/conf/type/__grafana_dashboard/manifest | 54 ++++++++------------ 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest index 8f089367..e62bd15f 100755 --- a/cdist/conf/type/__grafana_dashboard/manifest +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -7,44 +7,34 @@ case $os in debian|devuan) case $os_version in 8*|jessie) - __apt_key_uri grafana \ - --name 'Grafana Release Signing Key' \ - --uri https://packagecloud.io/gpg.key - - require="__apt_key_uri/grafana" __apt_source grafana \ - --uri https://packagecloud.io/grafana/stable/debian/ \ - --distribution jessie \ - --component main - - __package apt-transport-https - - require="__apt_source/grafana __package/apt-transport-https" __package grafana - require="__package/grafana" __start_on_boot grafana-server + apt_source_distribution=jessie ;; 9*|ascii/ceres) - __apt_key_uri grafana \ - --name 'Grafana Release Signing Key' \ - --uri https://packagecloud.io/gpg.key - - require="__apt_key_uri/grafana" __apt_source grafana \ - --uri https://packagecloud.io/grafana/stable/debian/ \ - --distribution stretch \ - --component main - - __package apt-transport-https - - require="__apt_source/grafana __package/apt-transport-https" __package grafana - require="__package/grafana" __start_on_boot grafana-server + apt_source_distribution=stretch ;; - *) - echo "Don't know how to install Grafana on $os $os_version. Send us a pull request!" + echo "Don't know how to install Grafana on $os $os_version. Send us a pull request!" >&2 exit 1 - ;; + ;; esac - ;; + + __apt_key_uri grafana \ + --name 'Grafana Release Signing Key' \ + --uri https://packagecloud.io/gpg.key + + require="$require __apt_key_uri/grafana" __apt_source grafana \ + --uri https://packagecloud.io/grafana/stable/debian/ \ + --distribution $apt_source_distribution \ + --component main + + __package apt-transport-https + + require="$require __apt_source/grafana __package/apt-transport-https" __package grafana + require="$require __package/grafana" __start_on_boot grafana-server + require="$require __start_on_boot/grafana-server" __process grafana-server --start "service grafana-server start" + ;; *) - echo "Don't know how to install Grafana on $os. Send us a pull request!" + echo "Don't know how to install Grafana on $os. Send us a pull request!" >&2 exit 1 - ;; + ;; esac From 787f5237e5f3c274c94d7b647f874df14c9ccc71 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Sun, 11 Mar 2018 10:55:21 +0100 Subject: [PATCH 0781/1332] __prometheus_{server,alertmanager}: use os_version instead of lsb_release works without the `lsb-release` package and actually seems to be more reliable, even though it is inconsistent between debian and devuan --- .../conf/type/__prometheus_alertmanager/manifest | 16 ++++++---------- cdist/conf/type/__prometheus_server/manifest | 16 ++++++---------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index 8278170a..87546f47 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -17,22 +17,18 @@ storage_path="$(cat "$__object/parameter/storage-path")" require_pkg="" # what to require if I want to require "the package" if [ -f "$__object/parameter/install-from-backports" ]; then os=$(cat "$__global/explorer/os") - lsb_codename=$(cat "$__global/explorer/lsb_codename") + os_version=$(cat "$__global/explorer/os_version") case $os in devuan) - if [ -z "$lsb_codename" ]; then - echo "Command `lsb_release` not functional -- is package `lsb-release` installed?" >&2 - exit 1 - fi - [ "$lsb_codename" = "n/a" ] && lsb_codename='ascii' # TODO this is a devuan bug that should be fixed soon => remove when no longer needed - __apt_source backports --uri http://auto.mirror.devuan.org/merged --distribution $lsb_codename-backports --component main - require="$require __apt_source/backports" __package_apt prometheus-alertmanager --target-release $lsb_codename-backports + [ "$os_version" = "ascii/ceres" ] && os_version='ascii' # "ascii" used in the repo URLs + __apt_source backports --uri http://auto.mirror.devuan.org/merged --distribution $os_version-backports --component main + require="$require __apt_source/backports" __package_apt prometheus-alertmanager --target-release $os_version-backports require_pkg="__package_apt/prometheus-alertmanager" ;; *) - echo "--install-from-backports is only supported on Devuan -- ignoring" >&2 - echo "send a pull request if you require it" >&2 + echo "--install-from-backports is only supported on Devuan -- ignoring." >&2 + echo "Send a pull request if you require it." >&2 ;; esac else diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index a5c31b4e..a7ba7884 100755 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -20,22 +20,18 @@ rule_files="$(cat "$__object/parameter/rule-files")" require_pkg="" # what to require if I want to require "the package" if [ -f "$__object/parameter/install-from-backports" ]; then os=$(cat "$__global/explorer/os") - lsb_codename=$(cat "$__global/explorer/lsb_codename") + os_version=$(cat "$__global/explorer/os_version") case $os in devuan) - if [ -z "$lsb_codename" ]; then - echo "Command `lsb_release` not functional -- is package `lsb-release` installed?" >&2 - exit 1 - fi - [ "$lsb_codename" = "n/a" ] && lsb_codename='ascii' # TODO this is a devuan bug that should be fixed soon => remove when no longer needed - __apt_source backports --uri http://auto.mirror.devuan.org/merged --distribution $lsb_codename-backports --component main - require="$require __apt_source/backports" __package_apt prometheus --target-release $lsb_codename-backports + [ "$os_version" = "ascii/ceres" ] && os_version='ascii' # "ascii" used in the repo URLs + __apt_source backports --uri http://auto.mirror.devuan.org/merged --distribution $os_version-backports --component main + require="$require __apt_source/backports" __package_apt prometheus --target-release $os_version-backports require_pkg="__package_apt/prometheus" ;; *) - echo "--install-from-backports is only supported on Devuan -- ignoring" >&2 - echo "send a pull request if you require it" >&2 + echo "--install-from-backports is only supported on Devuan -- ignoring." >&2 + echo "Send a pull request if you require it." >&2 ;; esac else From e63c3429da906510b16587888f98490be87bc114 Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Sun, 11 Mar 2018 11:07:59 +0100 Subject: [PATCH 0782/1332] __prometheus_{server,alertmanager}: update man pages --- cdist/conf/type/__prometheus_alertmanager/man.rst | 3 +-- cdist/conf/type/__prometheus_server/man.rst | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__prometheus_alertmanager/man.rst b/cdist/conf/type/__prometheus_alertmanager/man.rst index 894100c8..67e97eaf 100644 --- a/cdist/conf/type/__prometheus_alertmanager/man.rst +++ b/cdist/conf/type/__prometheus_alertmanager/man.rst @@ -10,8 +10,7 @@ DESCRIPTION ----------- Install and configure Prometheus Alertmanager (https://prometheus.io/docs/alerting/alertmanager/). -This type create a daemontools-compatible service directory under /service/prometheus. -Daemontools (or something compatible) must be installed (in particular, the command `svc` must be executable). +Note that due to significant differences between Prometheus 1.x and 2.x, only 2.x is supported. It is your responsibility to make sure that your package manager installs 2.x. (On Devuan Ascii, the parameter `--install-from-backports` helps.) REQUIRED PARAMETERS diff --git a/cdist/conf/type/__prometheus_server/man.rst b/cdist/conf/type/__prometheus_server/man.rst index 4308e6c4..ab6a3c9b 100644 --- a/cdist/conf/type/__prometheus_server/man.rst +++ b/cdist/conf/type/__prometheus_server/man.rst @@ -10,7 +10,7 @@ DESCRIPTION ----------- Install and configure Prometheus (https://prometheus.io/). -Note that due to significant differences between Prometheus 1.x and 2.x, only 2.x is supported. +Note that due to significant differences between Prometheus 1.x and 2.x, only 2.x is supported. It is your responsibility to make sure that your package manager installs 2.x. (On Devuan Ascii, the parameter `--install-from-backports` helps.) REQUIRED PARAMETERS ------------------- From f9443532a19ce9fb179970498014d14e0fd92ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Sun, 11 Mar 2018 18:01:38 +0100 Subject: [PATCH 0783/1332] __key_value: --onchange parameter added (#648) --- cdist/conf/type/__key_value/gencode-remote | 15 ++++++++++++--- cdist/conf/type/__key_value/man.rst | 2 ++ .../type/__key_value/parameter/default/onchange | 0 cdist/conf/type/__key_value/parameter/optional | 1 + 4 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 cdist/conf/type/__key_value/parameter/default/onchange diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index 7a60f94b..13cc27c7 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -23,13 +23,14 @@ state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" +fire_onchange='' if [ "$state_is" = "$state_should" ]; then exit 0 fi # here we check only if the states are valid, -# emmit messages and +# emit messages and # let awk do the work ... case "$state_should" in absent) @@ -39,6 +40,7 @@ case "$state_should" in ;; wrongformat|wrongvalue|present) echo "remove" >> "$__messages_out" + fire_onchange=1 ;; *) echo "Unknown explorer state: $state_is" >&2 @@ -50,12 +52,15 @@ case "$state_should" in case "$state_is" in nosuchfile) echo "create" >> "$__messages_out" + fire_onchange=1 ;; absent) echo "insert" >> "$__messages_out" + fire_onchange=1 ;; wrongformated|wrongvalue) echo "change" >> "$__messages_out" + fire_onchange=1 ;; present) # nothing to do @@ -67,9 +72,13 @@ case "$state_should" in esac ;; *) - echo "Unknown state: $state_should" >&2 - exit 1 + echo "Unknown state: $state_should" >&2 + exit 1 ;; esac cat "$__type/files/remote_script.sh" + +if [ -n "$fire_onchange" ]; then + cat "$__object/parameter/onchange" +fi diff --git a/cdist/conf/type/__key_value/man.rst b/cdist/conf/type/__key_value/man.rst index f069d989..34e4aab2 100644 --- a/cdist/conf/type/__key_value/man.rst +++ b/cdist/conf/type/__key_value/man.rst @@ -34,6 +34,8 @@ comment but only if the key or value must be changed. You need to ensure yourself that the line is prefixed with the correct comment sign. (for example # or ; or wathever ..) +onchange + The code to run if the key or value changes (i.e. is inserted, removed or replaced). BOOLEAN PARAMETERS diff --git a/cdist/conf/type/__key_value/parameter/default/onchange b/cdist/conf/type/__key_value/parameter/default/onchange new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__key_value/parameter/optional b/cdist/conf/type/__key_value/parameter/optional index 666be2ae..d4b8cac0 100644 --- a/cdist/conf/type/__key_value/parameter/optional +++ b/cdist/conf/type/__key_value/parameter/optional @@ -2,3 +2,4 @@ key value state comment +onchange From ca42fe6ee3471907daf1eab08ec519d312481110 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 11 Mar 2018 18:01:03 +0100 Subject: [PATCH 0784/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 344d18a1..834488e8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * __key_value: Add onchange parameter (Kamila Součková) + 4.8.2: 2018-03-10 * Core: Fix quiet argument access for bare cdist command (Darko Poljak) From f03a0e586e3d867d65244b586fee6516c8854a6c Mon Sep 17 00:00:00 2001 From: Kamila Souckova Date: Sun, 11 Mar 2018 11:40:47 +0100 Subject: [PATCH 0785/1332] __prometheus_{server,alertmanager}: restart when cli parameters change --- cdist/conf/type/__prometheus_alertmanager/manifest | 8 ++++++-- cdist/conf/type/__prometheus_server/manifest | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index 87546f47..be50b71e 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -42,14 +42,18 @@ require="$require $require_pkg" __directory "$storage_path" --owner prometheus - # TODO this is a bug in the init script, patching it like this is awful and it should be reported require="$require $require_pkg" \ -__key_value alertmanager_fix_init_script --file /etc/init.d/prometheus-alertmanager --key="NAME" --value="prometheus-alertmanager" --delimiter "=" +__key_value alertmanager_fix_init_script --file /etc/init.d/prometheus-alertmanager \ + --key "NAME" --value "prometheus-alertmanager" --delimiter "=" \ + --onchange "service prometheus-alertmanager restart" ##### CONFIGURE ############################################################# FLAGS="--storage.path $storage_path --data.retention $(($retention_days*24))h --web.listen-address [::]:9093" require="$require $require_pkg" \ -__key_value alertmanager_args --file /etc/default/prometheus-alertmanager --key="ARGS" --value="\"$FLAGS\"" --delimiter "=" +__key_value alertmanager_args --file /etc/default/prometheus-alertmanager \ + --key "ARGS" --value "\"$FLAGS\"" --delimiter "=" \ + --onchange "service prometheus-alertmanager restart" require="$require __directory/$storage_path $require_pkg" \ __config_file $CONF \ diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index a7ba7884..84ba53cf 100755 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -49,7 +49,9 @@ FLAGS="--storage.tsdb.path $storage_path --storage.tsdb.retention $(($retention_ # TODO it would be neat to restart prometheus on change -- __key_value really should have an --onchange parameter require="$require $require_pkg" \ -__key_value prometheus_args --file /etc/default/prometheus --key "ARGS" --value "\"$FLAGS\"" --delimiter "=" +__key_value prometheus_args --file /etc/default/prometheus \ + --key "ARGS" --value "\"$FLAGS\"" --delimiter "=" \ + --onchange "service prometheus restart" require="$require __directory/$storage_path $require_pkg" \ __config_file $CONF \ From e4f263ecb72415a2f7759235eb87782359ac1c16 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 11 Mar 2018 21:11:26 +0100 Subject: [PATCH 0786/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 834488e8..88ff926e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,8 @@ Changelog next: * __key_value: Add onchange parameter (Kamila Součková) + * __prometheus_server, __prometheus_alertmanager, __grafana_dashboard: + Work with packages instead of go get, remove __daemontools dependency and clean up (Kamila Součková) 4.8.2: 2018-03-10 * Core: Fix quiet argument access for bare cdist command (Darko Poljak) From f8812288783a974e4f7ea61257e85eab2c4d0957 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 13 Mar 2018 15:09:13 +0100 Subject: [PATCH 0787/1332] Fix manpage generation. --- cdist/sphinxext/manpage.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cdist/sphinxext/manpage.py b/cdist/sphinxext/manpage.py index 97b41f03..a436421d 100644 --- a/cdist/sphinxext/manpage.py +++ b/cdist/sphinxext/manpage.py @@ -27,13 +27,12 @@ class ManualPageWriter(sphinx.writers.manpage.ManualPageWriter): def __init__(self, builder): super().__init__(builder) - self.translator_class = ( - self.builder.translator_class or ManualPageTranslator) class ManualPageBuilder(sphinx.builders.manpage.ManualPageBuilder): name = 'cman' + default_translator_class = ManualPageTranslator def write(self, *ignored): docwriter = ManualPageWriter(self) From f2fbb92fdd73c1b8cf78ba878850697065732e8b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 13 Mar 2018 15:17:14 +0100 Subject: [PATCH 0788/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 88ff926e..5c98ba88 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * __key_value: Add onchange parameter (Kamila Součková) * __prometheus_server, __prometheus_alertmanager, __grafana_dashboard: Work with packages instead of go get, remove __daemontools dependency and clean up (Kamila Součková) + * Documentation: Fix manpage generation (Darko Poljak) 4.8.2: 2018-03-10 * Core: Fix quiet argument access for bare cdist command (Darko Poljak) From 8b86c6fc95806562bde77af7212bb1d88e404a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Mon, 12 Mar 2018 12:30:22 +0100 Subject: [PATCH 0789/1332] Add new type __docker_swarm --- .../type/__docker_swarm/explorer/swarm-state | 21 ++++++++ cdist/conf/type/__docker_swarm/gencode-remote | 46 +++++++++++++++++ cdist/conf/type/__docker_swarm/man.rst | 49 +++++++++++++++++++ .../__docker_swarm/parameter/default/state | 1 + .../type/__docker_swarm/parameter/optional | 1 + cdist/conf/type/__docker_swarm/singleton | 0 6 files changed, 118 insertions(+) create mode 100755 cdist/conf/type/__docker_swarm/explorer/swarm-state create mode 100755 cdist/conf/type/__docker_swarm/gencode-remote create mode 100644 cdist/conf/type/__docker_swarm/man.rst create mode 100644 cdist/conf/type/__docker_swarm/parameter/default/state create mode 100644 cdist/conf/type/__docker_swarm/parameter/optional create mode 100644 cdist/conf/type/__docker_swarm/singleton diff --git a/cdist/conf/type/__docker_swarm/explorer/swarm-state b/cdist/conf/type/__docker_swarm/explorer/swarm-state new file mode 100755 index 00000000..9c1bc32d --- /dev/null +++ b/cdist/conf/type/__docker_swarm/explorer/swarm-state @@ -0,0 +1,21 @@ +#!/bin/sh -e +# +# 2018 Ľubomír Kučera +# +# 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 . +# + +docker info 2>/dev/null | grep "^Swarm: " | cut -d " " -f 2- diff --git a/cdist/conf/type/__docker_swarm/gencode-remote b/cdist/conf/type/__docker_swarm/gencode-remote new file mode 100755 index 00000000..4b199a02 --- /dev/null +++ b/cdist/conf/type/__docker_swarm/gencode-remote @@ -0,0 +1,46 @@ +#!/bin/sh -e +# +# 2018 Ľubomír Kučera +# +# 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 . +# + +state=$(cat "${__object:?}/parameter/state") +swarm_state="$(cat "${__object}/explorer/swarm-state")" + +if [ -z "${swarm_state}" ]; then + echo "Unable to determine Swarm state. Is compatible version of Docker installed?" >&2 + + exit 1 +fi + +case "${state}" in + absent) + if [ "${swarm_state}" = "active" ]; then + echo "docker swarm leave --force" + fi + ;; + present) + if [ "${swarm_state}" = "inactive" ]; then + echo "docker swarm init" + fi + ;; + *) + echo "Unsupported state: ${state}" >&2 + + exit 1 + ;; +esac diff --git a/cdist/conf/type/__docker_swarm/man.rst b/cdist/conf/type/__docker_swarm/man.rst new file mode 100644 index 00000000..7b0a57d3 --- /dev/null +++ b/cdist/conf/type/__docker_swarm/man.rst @@ -0,0 +1,49 @@ +cdist-type__docker_swarm(7) +=========================== + +NAME +---- + +cdist-type__docker_swarm - Manage Swarm + +DESCRIPTION +----------- + +This type can initialize Docker swarm mode. For more information about swarm +mode, see `Swarm mode overview `_. + +OPTIONAL PARAMETERS +------------------- + +state + 'present' or 'absent', defaults to 'present' where: + + present + Swarm is initialized + absent + Swarm is left + +EXAMPLES +-------- + +.. code-block:: sh + + # Initalizes a swarm + __docker_swarm + + # Leaves a swarm + __docker_swarm --state absent + + +AUTHORS +------- + +Ľubomír Kučera + +COPYING +------- + +Copyright \(C) 2018 Ľubomír Kučera. 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/__docker_swarm/parameter/default/state b/cdist/conf/type/__docker_swarm/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__docker_swarm/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__docker_swarm/parameter/optional b/cdist/conf/type/__docker_swarm/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__docker_swarm/parameter/optional @@ -0,0 +1 @@ +state diff --git a/cdist/conf/type/__docker_swarm/singleton b/cdist/conf/type/__docker_swarm/singleton new file mode 100644 index 00000000..e69de29b From 7184228536d7c879730ebea2c984ed50b173f835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Tue, 13 Mar 2018 11:26:25 +0100 Subject: [PATCH 0790/1332] Add new type __docker_stack --- .../type/__docker_stack/explorer/stack-exists | 25 ++++++++ cdist/conf/type/__docker_stack/gencode-remote | 63 +++++++++++++++++++ cdist/conf/type/__docker_stack/man.rst | 54 ++++++++++++++++ .../parameter/default/compose-file | 0 .../__docker_stack/parameter/default/state | 1 + .../type/__docker_stack/parameter/optional | 2 + 6 files changed, 145 insertions(+) create mode 100755 cdist/conf/type/__docker_stack/explorer/stack-exists create mode 100755 cdist/conf/type/__docker_stack/gencode-remote create mode 100644 cdist/conf/type/__docker_stack/man.rst create mode 100644 cdist/conf/type/__docker_stack/parameter/default/compose-file create mode 100644 cdist/conf/type/__docker_stack/parameter/default/state create mode 100644 cdist/conf/type/__docker_stack/parameter/optional diff --git a/cdist/conf/type/__docker_stack/explorer/stack-exists b/cdist/conf/type/__docker_stack/explorer/stack-exists new file mode 100755 index 00000000..4f511821 --- /dev/null +++ b/cdist/conf/type/__docker_stack/explorer/stack-exists @@ -0,0 +1,25 @@ +#!/bin/sh -e +# +# 2018 Ľubomír Kučera +# +# 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 docker stack ls | grep -q "^${__object_id:?} "; then + echo 1 +else + echo 0 +fi diff --git a/cdist/conf/type/__docker_stack/gencode-remote b/cdist/conf/type/__docker_stack/gencode-remote new file mode 100755 index 00000000..0d47dc52 --- /dev/null +++ b/cdist/conf/type/__docker_stack/gencode-remote @@ -0,0 +1,63 @@ +#!/bin/sh -e +# +# 2018 Ľubomír Kučera +# +# 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 . +# + +stack="${__object_id:?}" +state=$(cat "${__object:?}/parameter/state") + +case "${state}" in + absent) + stack_exists=$(cat "${__object:?}/explorer/stack-exists") + + if [ "${stack_exists}" -ne 1 ]; then + exit 0 + fi + + echo "docker stack rm ${stack}" + ;; + present) + compose_file=$(cat "${__object}/parameter/compose-file") + + if [ -z "${compose_file}" ]; then + exit 0 + fi + + if [ "${compose_file}" = "-" ]; then + compose_file="${__object}/stdin" + fi + + cat <<-EOF + compose_file="\$(mktemp cdist.XXXXXXXXXX)" + + base64 -d > "\${compose_file}" << eof + $(base64 "${compose_file}") + eof + + docker stack deploy --compose-file "\${compose_file}" \ + --prune ${stack} + + rm "\${compose_file}" + EOF + ;; + *) + echo "Unsupported state: ${state}" >&2 + + exit 1 + ;; +esac diff --git a/cdist/conf/type/__docker_stack/man.rst b/cdist/conf/type/__docker_stack/man.rst new file mode 100644 index 00000000..d0597c25 --- /dev/null +++ b/cdist/conf/type/__docker_stack/man.rst @@ -0,0 +1,54 @@ +cdist-type__docker_stack(7) +=========================== + +NAME +---- + +cdist-type__docker_stack - Manage Docker stacks + +DESCRIPTION +----------- + +This type manages service stacks. + +.. note:: + Since there is no easy way to tell whether a stack needs to be updated, + `docker stack deploy` is being run every time this type is invoked. + However, it does not mean this type is not idempotent. If Docker does not + detect changes, the existing stack will not be updated. + +OPTIONAL PARAMETERS +------------------- + +compose-file + Path to the compose file. If it is '-' (dash), read standard input. + +state + 'present' or 'absent', defaults to 'present' where: + + present + the stack is deployed + absent + the stack is removed + +EXAMPLES +-------- + +.. code-block:: sh + + # Deploys 'foo' stack defined in 'docker-compose.yml' compose file + __docker_stack foo --compose-file docker-compose.yml + + +AUTHORS +------- + +Ľubomír Kučera + +COPYING +------- + +Copyright \(C) 2018 Ľubomír Kučera. 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/__docker_stack/parameter/default/compose-file b/cdist/conf/type/__docker_stack/parameter/default/compose-file new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__docker_stack/parameter/default/state b/cdist/conf/type/__docker_stack/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__docker_stack/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__docker_stack/parameter/optional b/cdist/conf/type/__docker_stack/parameter/optional new file mode 100644 index 00000000..b3457bd3 --- /dev/null +++ b/cdist/conf/type/__docker_stack/parameter/optional @@ -0,0 +1,2 @@ +compose-file +state From 17fa27a56ae8cc72c0ccdbdd5cc30f222fa0612a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 13 Mar 2018 17:31:50 +0100 Subject: [PATCH 0791/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 5c98ba88..8fd5ae81 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * __prometheus_server, __prometheus_alertmanager, __grafana_dashboard: Work with packages instead of go get, remove __daemontools dependency and clean up (Kamila Součková) * Documentation: Fix manpage generation (Darko Poljak) + * New type: __docker_swarm (Ľubomír Kučera) 4.8.2: 2018-03-10 * Core: Fix quiet argument access for bare cdist command (Darko Poljak) From bba4c0ef67d2acd09f0a00e5b0ca23a27b897b5d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 13 Mar 2018 18:49:40 +0100 Subject: [PATCH 0792/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8fd5ae81..399287c6 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: Work with packages instead of go get, remove __daemontools dependency and clean up (Kamila Součková) * Documentation: Fix manpage generation (Darko Poljak) * New type: __docker_swarm (Ľubomír Kučera) + * New type: __docker_stack (Ľubomír Kučera) 4.8.2: 2018-03-10 * Core: Fix quiet argument access for bare cdist command (Darko Poljak) From 26a8827ec204c64864784a8d58d61cd6e6f63fb8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Mar 2018 06:33:05 +0100 Subject: [PATCH 0793/1332] Add gitattributes: export-ignore entries. --- .gitattributes | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..76eac516 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +.gitignore export-ignore +.gitattributes export-ignore +.gitkeep export-ignore +docs/speeches export-ignore +docs/video export-ignore From d4a7b298a6eb62abb33c001f124ca9477f0afd84 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Mar 2018 13:49:22 +0100 Subject: [PATCH 0794/1332] Return translator_class for older sphinx versions. --- cdist/sphinxext/manpage.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/sphinxext/manpage.py b/cdist/sphinxext/manpage.py index a436421d..135fe22e 100644 --- a/cdist/sphinxext/manpage.py +++ b/cdist/sphinxext/manpage.py @@ -27,6 +27,8 @@ class ManualPageWriter(sphinx.writers.manpage.ManualPageWriter): def __init__(self, builder): super().__init__(builder) + self.translator_class = ( + self.builder.translator_class or ManualPageTranslator) class ManualPageBuilder(sphinx.builders.manpage.ManualPageBuilder): From a06ee6f9f190e9ce3875da682e49275e3a9a2a04 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Mar 2018 14:00:25 +0100 Subject: [PATCH 0795/1332] Fix changelog. --- docs/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 399287c6..64ab1157 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,8 +2,8 @@ Changelog --------- next: - * __key_value: Add onchange parameter (Kamila Součková) - * __prometheus_server, __prometheus_alertmanager, __grafana_dashboard: + * Type __key_value: Add onchange parameter (Kamila Součková) + * Types __prometheus_server, __prometheus_alertmanager, __grafana_dashboard: Work with packages instead of go get, remove __daemontools dependency and clean up (Kamila Součková) * Documentation: Fix manpage generation (Darko Poljak) * New type: __docker_swarm (Ľubomír Kučera) From ef134496877bf6854b909a01bdcae652b702428f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 15 Mar 2018 18:01:23 +0100 Subject: [PATCH 0796/1332] Fix sphinx warnings. --- cdist/conf/type/__consul/man.rst | 2 + cdist/conf/type/__install_stage/man.rst | 6 +- docs/src/cdist-saving-output-streams.rst | 2 +- docs/src/conf.py | 5 - docs/src/docutils.conf | 2 + docs/src/man1/cdist.rst | 186 ++++++++--------------- 6 files changed, 70 insertions(+), 133 deletions(-) create mode 100644 docs/src/docutils.conf diff --git a/cdist/conf/type/__consul/man.rst b/cdist/conf/type/__consul/man.rst index 401f0c26..5b2db50a 100644 --- a/cdist/conf/type/__consul/man.rst +++ b/cdist/conf/type/__consul/man.rst @@ -40,9 +40,11 @@ MESSAGES If consul binary is created using __staged_file then underlaying __file type messages are emitted. If consul binary is created by direct method then the following messages are emitted: + /usr/local/bin/consul created consul binary was created + EXAMPLES -------- diff --git a/cdist/conf/type/__install_stage/man.rst b/cdist/conf/type/__install_stage/man.rst index e33e1e90..fd764693 100644 --- a/cdist/conf/type/__install_stage/man.rst +++ b/cdist/conf/type/__install_stage/man.rst @@ -17,9 +17,9 @@ REQUIRED PARAMETERS uri The uri from which to fetch the tarball. Can be anything understood by curl, e.g: - | http://path/to/stage.tgz - | tftp:///path/to/stage.tgz - | file:///local/path/stage.tgz + | http://path/to/stage.tgz + | tftp:///path/to/stage.tgz + | file:///local/path/stage.tgz OPTIONAL PARAMETERS diff --git a/docs/src/cdist-saving-output-streams.rst b/docs/src/cdist-saving-output-streams.rst index 28067cac..da66f754 100644 --- a/docs/src/cdist-saving-output-streams.rst +++ b/docs/src/cdist-saving-output-streams.rst @@ -9,7 +9,7 @@ during a config run, hidden in all other output. Now all created output is bound to the context where it was produced. Saving output streams include stdout and stderr of init manifest, remote -commands and for each object stdout and stderr of manifest, gencode-* and code-*. +commands and for each object stdout and stderr of manifest, gencode-\* and code-\*. Output stream files are created only if some output is produced. For more info on these cache files see `Local cache overview `_. diff --git a/docs/src/conf.py b/docs/src/conf.py index a63a14ff..8ed48324 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -161,11 +161,6 @@ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The empty string is equivalent to '%b %d, %Y'. # html_last_updated_fmt = None -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True -html_use_smartypants = False - # Custom sidebar templates, maps document names to template names. # html_sidebars = {} diff --git a/docs/src/docutils.conf b/docs/src/docutils.conf new file mode 100644 index 00000000..168f9e2b --- /dev/null +++ b/docs/src/docutils.conf @@ -0,0 +1,2 @@ +[parsers] +smart_quotes: false diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 90168f86..fb87ffe2 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -72,24 +72,20 @@ GENERAL ------- All commands accept the following options: -.. option:: -h, --help - +**-h, --help** Show the help screen. -.. option:: -l LOGLEVEL, --log-level LOGLEVEL - +**-l LOGLEVEL, --log-level LOGLEVEL** Set the specified verbosity level. The levels, in order from the lowest to the highest, are: ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) TRACE (4 or higher). If used along with -v then -v increases last set value and -l overwrites last set value. -.. option:: -q, --quiet - +**-q, --quiet** Quiet mode: disables logging, including WARNING and ERROR. -.. option:: -v, --verbose - +**-v, --verbose** Increase the verbosity level. Every instance of -v increments the verbosity level by one. Its default value is 0 which includes ERROR and WARNING levels. @@ -99,8 +95,7 @@ All commands accept the following options: then -l overwrites last set value and -v increases last set value. -.. option:: -V, --version - +**-V, --version** Show version and exit. @@ -115,55 +110,45 @@ CONFIG/INSTALL Configure/install one or more hosts. Install command is currently in beta. -.. option:: -4, --force-ipv4 - +**-4, --force-ipv4** Force to use IPv4 addresses only. No influence for custom remote commands. -.. option:: -6, --force-ipv6 - +**-6, --force-ipv6** Force to use IPv6 addresses only. No influence for custom remote commands. -.. option:: -A, --all-tagged - +**-A, --all-tagged** Use all hosts present in tags db. Currently in beta. -.. option:: -a, --all - +**-a, --all** List hosts that have all specified tags, if -t/--tag is specified. -.. option:: -b, --beta - +**-b, --beta** Enable beta functionality. -.. option:: -C CACHE_PATH_PATTERN, --cache-path-pattern CACHE_PATH_PATTERN - +**-C CACHE_PATH_PATTERN, --cache-path-pattern CACHE_PATH_PATTERN** Sepcify custom cache path pattern. If it is not set then default hostdir is used. For more info on format see :strong:`CACHE PATH PATTERN FORMAT` below. -.. option:: -c CONF_DIR, --conf-dir CONF_DIR - +**-c CONF_DIR, --conf-dir CONF_DIR** Add a configuration directory. Can be specified multiple times. If configuration directories contain conflicting types, explorers or manifests, then the last one found is used. -.. option:: -f HOSTFILE, --file HOSTFILE - +**-f HOSTFILE, --file HOSTFILE** Read specified file for a list of additional hosts to operate on or if '-' is given, read stdin (one host per line). If no host or host file is specified then, by default, read hosts from stdin. For the file format see :strong:`HOSTFILE FORMAT` below. -.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE - +**-g CONFIG_FILE, --config-file CONFIG_FILE** Use specified custom configuration file. -.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR - +**-I INVENTORY_DIR, --inventory INVENTORY_DIR** Use specified custom inventory directory. Inventory directory is set up by the following rules: if cdist configuration resolves this value then specified @@ -171,60 +156,48 @@ Install command is currently in beta. ~/.cdit/inventory is used, otherwise distribution inventory directory is used. -.. option:: -i MANIFEST, --initial-manifest MANIFEST - +**-i MANIFEST, --initial-manifest MANIFEST** Path to a cdist manifest or - to read from stdin. -.. option:: -j [JOBS], --jobs [JOBS] - +**-j [JOBS], --jobs [JOBS]** Operate in parallel in specified maximum number of jobs. Global explorers, object prepare and object run are supported. Without argument CPU count is used by default. Currently in beta. -.. option:: -n, --dry-run - +**-n, --dry-run** Do not execute code. -.. option:: -o OUT_PATH, --out-dir OUT_PATH - +**-o OUT_PATH, --out-dir OUT_PATH** Directory to save cdist output in. -.. option:: -p [HOST_MAX], --parallel [HOST_MAX] - +**-p [HOST_MAX], --parallel [HOST_MAX]** Operate on multiple hosts in parallel for specified maximum hosts at a time. Without argument CPU count is used by default. -.. option:: -R [{tar,tgz,tbz2,txz}], --use-archiving [{tar,tgz,tbz2,txz}] - +**-R [{tar,tgz,tbz2,txz}], --use-archiving [{tar,tgz,tbz2,txz}]** Operate by using archiving with compression where appropriate. Supported values are: tar - tar archive, tgz - gzip tar archive (the default), tbz2 - bzip2 tar archive and txz - lzma tar archive. Currently in beta. -.. option:: -r REMOTE_OUT_PATH, --remote-out-dir REMOTE_OUT_PATH - +**-r REMOTE_OUT_PATH, --remote-out-dir REMOTE_OUT_PATH** Directory to save cdist output in on the target host. -.. option:: -S, --disable-saving-output-streams - +**-S, --disable-saving-output-streams** Disable saving output streams. -.. option:: -s, --sequential - +**-s, --sequential** Operate on multiple hosts sequentially (default). -.. option:: --remote-copy REMOTE_COPY - +**--remote-copy REMOTE_COPY** Command to use for remote copy (should behave like scp). -.. option:: --remote-exec REMOTE_EXEC - +**--remote-exec REMOTE_EXEC** Command to use for remote execution (should behave like ssh). -.. option:: -t, --tag - +**-t, --tag** Host is specified by tag, not hostname/address; list all hosts that contain any of specified tags. Currently in beta. @@ -271,27 +244,22 @@ INVENTORY ADD-HOST ------------------ Add host(s) to inventory database. -.. option:: host - +**host** Host(s) to add. -.. option:: -b, --beta - +**-b, --beta** Enable beta functionality. -.. option:: -f HOSTFILE, --file HOSTFILE - +**-f HOSTFILE, --file HOSTFILE** Read additional hosts to add from specified file or from stdin if '-' (each host on separate line). If no host or host file is specified then, by default, read from stdin. Hostfile format is the same as config hostfile format. -.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE - +**-g CONFIG_FILE, --config-file CONFIG_FILE** Use specified custom configuration file. -.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR - +**-I INVENTORY_DIR, --inventory INVENTORY_DIR** Use specified custom inventory directory. Inventory directory is set up by the following rules: if cdist configuration resolves this value then specified @@ -304,16 +272,13 @@ INVENTORY ADD-TAG ----------------- Add tag(s) to inventory database. -.. option:: host - +**host** List of host(s) for which tags are added. -.. option:: -b, --beta - +**-b, --beta** Enable beta functionality. -.. option:: -f HOSTFILE, --file HOSTFILE - +**-f HOSTFILE, --file HOSTFILE** Read additional hosts to add tags from specified file or from stdin if '-' (each host on separate line). If no host or host file is specified then, by default, @@ -321,12 +286,10 @@ Add tag(s) to inventory database. are specified then tags are read from stdin and are added to all hosts. Hostfile format is the same as config hostfile format. -.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE - +**-g CONFIG_FILE, --config-file CONFIG_FILE** Use specified custom configuration file. -.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR - +**-I INVENTORY_DIR, --inventory INVENTORY_DIR** Use specified custom inventory directory. Inventory directory is set up by the following rules: if cdist configuration resolves this value then specified @@ -334,8 +297,7 @@ Add tag(s) to inventory database. ~/.cdit/inventory is used, otherwise distribution inventory directory is used. -.. option:: -T TAGFILE, --tag-file TAGFILE - +**-T TAGFILE, --tag-file TAGFILE** Read additional tags to add from specified file or from stdin if '-' (each tag on separate line). If no tag or tag file is specified then, by default, read @@ -343,8 +305,7 @@ Add tag(s) to inventory database. specified then tags are read from stdin and are added to all hosts. Tagfile format is the same as config hostfile format. -.. option:: -t TAGLIST, --taglist TAGLIST - +**-t TAGLIST, --taglist TAGLIST** Tag list to be added for specified host(s), comma separated values. @@ -353,31 +314,25 @@ INVENTORY DEL-HOST ------------------ Delete host(s) from inventory database. -.. option:: host - +**host** Host(s) to delete. -.. option:: -a, --all - +**-a, --all** Delete all hosts. -.. option:: -b, --beta - +**-b, --beta** Enable beta functionality. -.. option:: -f HOSTFILE, --file HOSTFILE - +**-f HOSTFILE, --file HOSTFILE** Read additional hosts to delete from specified file or from stdin if '-' (each host on separate line). If no host or host file is specified then, by default, read from stdin. Hostfile format is the same as config hostfile format. -.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE - +**-g CONFIG_FILE, --config-file CONFIG_FILE** Use specified custom configuration file. -.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR - +**-I INVENTORY_DIR, --inventory INVENTORY_DIR** Use specified custom inventory directory. Inventory directory is set up by the following rules: if cdist configuration resolves this value then specified @@ -390,20 +345,16 @@ INVENTORY DEL-TAG ----------------- Delete tag(s) from inventory database. -.. option:: host - +**host** List of host(s) for which tags are deleted. -.. option:: -a, --all - +**-a, --all** Delete all tags for specified host(s). -.. option:: -b, --beta - +**-b, --beta** Enable beta functionality. -.. option:: -f HOSTFILE, --file HOSTFILE - +**-f HOSTFILE, --file HOSTFILE** Read additional hosts to delete tags for from specified file or from stdin if '-' (each host on separate line). If no host or host file is specified @@ -412,12 +363,10 @@ Delete tag(s) from inventory database. from stdin and are deleted from all hosts. Hostfile format is the same as config hostfile format. -.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE - +**-g CONFIG_FILE, --config-file CONFIG_FILE** Use specified custom configuration file. -.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR - +**-I INVENTORY_DIR, --inventory INVENTORY_DIR** Use specified custom inventory directory. Inventory directory is set up by the following rules: if cdist configuration resolves this value then specified @@ -425,8 +374,7 @@ Delete tag(s) from inventory database. ~/.cdit/inventory is used, otherwise distribution inventory directory is used. -.. option:: -T TAGFILE, --tag-file TAGFILE - +**-T TAGFILE, --tag-file TAGFILE** Read additional tags from specified file or from stdin if '-' (each tag on separate line). If no tag or tag file is specified then, by default, read from stdin. @@ -434,8 +382,7 @@ Delete tag(s) from inventory database. then tags are read from stdin and are added to all hosts. Tagfile format is the same as config hostfile format. -.. option:: -t TAGLIST, --taglist TAGLIST - +**-t TAGLIST, --taglist TAGLIST** Tag list to be deleted for specified host(s), comma separated values. @@ -444,36 +391,29 @@ INVENTORY LIST -------------- List inventory database. -.. option:: host - +**host** Host(s) to list. -.. option:: -a, --all - +**-a, --all** List hosts that have all specified tags, if -t/--tag is specified. -.. option:: -b, --beta - +**-b, --beta** Enable beta functionality. -.. option:: -f HOSTFILE, --file HOSTFILE - +**-f HOSTFILE, --file HOSTFILE** Read additional hosts to list from specified file or from stdin if '-' (each host on separate line). If no host or host file is specified then, by default, list all. Hostfile format is the same as config hostfile format. -.. option:: -g CONFIG_FILE, --config-file CONFIG_FILE - +**-g CONFIG_FILE, --config-file CONFIG_FILE** Use specified custom configuration file. -.. option:: -H, --host-only - +**-H, --host-only** Suppress tags listing. -.. option:: -I INVENTORY_DIR, --inventory INVENTORY_DIR - +**-I INVENTORY_DIR, --inventory INVENTORY_DIR** Use specified custom inventory directory. Inventory directory is set up by the following rules: if cdist configuration resolves this value then specified @@ -481,8 +421,7 @@ List inventory database. ~/.cdit/inventory is used, otherwise distribution inventory directory is used. -.. option:: -t, --tag - +**-t, --tag** Host is specified by tag, not hostname/address; list all hosts that contain any of specified tags. @@ -494,8 +433,7 @@ to the types as commands. It can be thought as an "interactive manifest" environment. See below for example usage. Its primary use is for debugging type parameters. -.. option:: -s SHELL, --shell SHELL - +**-s SHELL, --shell SHELL** Select shell to use, defaults to current shell. Used shell should be POSIX compatible shell. From 7de80678f02bdc2badf94923c5a68ea28cd33a13 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 16 Mar 2018 19:17:53 +0100 Subject: [PATCH 0797/1332] Release 4.8.3 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 64ab1157..7348974e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.8.3: 2018-03-16 * Type __key_value: Add onchange parameter (Kamila Součková) * Types __prometheus_server, __prometheus_alertmanager, __grafana_dashboard: Work with packages instead of go get, remove __daemontools dependency and clean up (Kamila Součková) From 958222133bf4d369c28b09636520d5af83b8080d Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Sun, 18 Mar 2018 20:38:44 +0300 Subject: [PATCH 0798/1332] Fix spelling errors in manpages --- cdist/conf/type/__docker_swarm/man.rst | 2 +- docs/src/cdist-inventory.rst | 2 +- docs/src/man1/cdist.rst | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__docker_swarm/man.rst b/cdist/conf/type/__docker_swarm/man.rst index 7b0a57d3..4dc408f0 100644 --- a/cdist/conf/type/__docker_swarm/man.rst +++ b/cdist/conf/type/__docker_swarm/man.rst @@ -28,7 +28,7 @@ EXAMPLES .. code-block:: sh - # Initalizes a swarm + # Initializes a swarm __docker_swarm # Leaves a swarm diff --git a/docs/src/cdist-inventory.rst b/docs/src/cdist-inventory.rst index 584fe310..106fcdb6 100644 --- a/docs/src/cdist-inventory.rst +++ b/docs/src/cdist-inventory.rst @@ -64,7 +64,7 @@ Examples # Delete hosts from file old-hosts from inventory $ cdist inventory del-host -b -f old-hosts - # Add tags to specifed hosts + # Add tags to specified hosts $ cdist inventory add-tag -b -t europe,croatia,web,static web1 web2 # Add tag to all hosts in inventory diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index fb87ffe2..79683883 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -129,7 +129,7 @@ Install command is currently in beta. Enable beta functionality. **-C CACHE_PATH_PATTERN, --cache-path-pattern CACHE_PATH_PATTERN** - Sepcify custom cache path pattern. If it is not set then + Specify custom cache path pattern. If it is not set then default hostdir is used. For more info on format see :strong:`CACHE PATH PATTERN FORMAT` below. @@ -604,7 +604,7 @@ EXAMPLES # Delete hosts from file old-hosts from inventory % cdist inventory del-host -b -f old-hosts - # Add tags to specifed hosts + # Add tags to specified hosts % cdist inventory add-tag -b -t europe,croatia,web,static web1 web2 # Add tag to all hosts in inventory From b740d415cad11a5e3a1d3f1be26983e3f3bd5bb7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 19 Mar 2018 15:18:08 +0100 Subject: [PATCH 0799/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 7348974e..272d1751 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Documentation, type manpages: Fix spelling (Dmitry Bogatov) + 4.8.3: 2018-03-16 * Type __key_value: Add onchange parameter (Kamila Součková) * Types __prometheus_server, __prometheus_alertmanager, __grafana_dashboard: From b695e82becffc0c13243b517df05ab9a7d1d3d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamila=20Sou=C4=8Dkov=C3=A1?= Date: Mon, 26 Mar 2018 08:53:31 +0200 Subject: [PATCH 0800/1332] FreeBSD improvements (#651) --- cdist/conf/explorer/is-freebsd-jail | 1 + cdist/conf/type/__hostname/gencode-remote | 4 +-- cdist/conf/type/__hostname/manifest | 7 +++++ .../conf/type/__start_on_boot/explorer/state | 4 +++ .../conf/type/__start_on_boot/gencode-remote | 4 +++ cdist/conf/type/__start_on_boot/manifest | 28 +++++++++++++++++++ cdist/conf/type/__sysctl/gencode-remote | 12 +++++++- cdist/conf/type/__sysctl/manifest | 2 +- 8 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 cdist/conf/explorer/is-freebsd-jail create mode 100644 cdist/conf/type/__start_on_boot/manifest diff --git a/cdist/conf/explorer/is-freebsd-jail b/cdist/conf/explorer/is-freebsd-jail new file mode 100644 index 00000000..a6d11d1a --- /dev/null +++ b/cdist/conf/explorer/is-freebsd-jail @@ -0,0 +1 @@ +sysctl -n security.jail.jailed 2>/dev/null | grep "1" || true diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index dbffad61..89bf7b3f 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -40,7 +40,7 @@ case "$os" in exit 0 fi ;; - scientific|centos|openbsd) + scientific|centos|freebsd|openbsd) if [ "$name_sysconfig" = "$name_should" -a "$name_running" = "$name_should" ]; then exit 0 fi @@ -62,7 +62,7 @@ case "$os" in echo "printf '%s\n' '$name_should' > /etc/hostname" echo "hostname -F /etc/hostname" ;; - openbsd) + freebsd|openbsd) echo "hostname '$name_should'" ;; suse) diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 4836c501..74664aa7 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -52,6 +52,13 @@ case "$os" in --key HOSTNAME \ --value "$name_should" --exact_delimiter ;; + freebsd) + __key_value rcconf-hostname \ + --file /etc/rc.conf \ + --delimiter '=' \ + --key 'hostname' \ + --value "$name_should" + ;; openbsd) echo "$name_should" | __file /etc/myname --source - ;; diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index d49f01c7..d8f9b7ba 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -64,6 +64,10 @@ else state="present" [ -f "/etc/runlevels/${target_runlevel}/${name}" ] || state="absent" ;; + freebsd) + state="absent" + service -e | grep "/$name$" && state="present" + ;; *) echo "Unsupported os: $os" >&2 exit 1 diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 63f0ba3c..14ee7dab 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -77,6 +77,10 @@ case "$state_should" in echo "update-rc.d \"$name\" defaults >/dev/null" ;; + freebsd) + : # handled in manifest + ;; + *) echo "Unsupported os: $os" >&2 exit 1 diff --git a/cdist/conf/type/__start_on_boot/manifest b/cdist/conf/type/__start_on_boot/manifest new file mode 100644 index 00000000..b9ee20e2 --- /dev/null +++ b/cdist/conf/type/__start_on_boot/manifest @@ -0,0 +1,28 @@ +#!/bin/sh -e + +state_should="$(cat "$__object/parameter/state")" +state_is=$(cat "$__object/explorer/state") +name="$__object_id" + +# Short circuit if nothing is to be done +[ "$state_should" = "$state_is" ] && exit 0 + +os=$(cat "$__global/explorer/os") + +case "$os" in + freebsd) + if [ "$state_should" = 'present' ]; then + value='YES' + else + value='NO' + fi + __key_value rcconf-$name-enable \ + --file /etc/rc.conf \ + --key "${name}_enable" \ + --value "\"$value\"" \ + --delimiter '=' + ;; + *) + : # handled in gencode-remote + ;; +esac diff --git a/cdist/conf/type/__sysctl/gencode-remote b/cdist/conf/type/__sysctl/gencode-remote index b7fb02c8..a7aedb84 100755 --- a/cdist/conf/type/__sysctl/gencode-remote +++ b/cdist/conf/type/__sysctl/gencode-remote @@ -26,5 +26,15 @@ if [ "$value_should" = "$value_is" ]; then exit 0 fi +os=$(cat "$__global/explorer/os") +case "$os" in + redhat|centos|ubuntu|debian|devuan|archlinux|coreos) + flag='-w' + ;; + frebsd) + flag='' + ;; +esac + # set the current runtime value -printf 'sysctl -w %s="%s"\n' "$__object_id" "$value_should" +printf 'sysctl %s %s="%s"\n' "$flag" "$__object_id" "$value_should" diff --git a/cdist/conf/type/__sysctl/manifest b/cdist/conf/type/__sysctl/manifest index 39a2e53c..c903dbae 100755 --- a/cdist/conf/type/__sysctl/manifest +++ b/cdist/conf/type/__sysctl/manifest @@ -22,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - redhat|centos|ubuntu|debian|devuan|archlinux|coreos) + redhat|centos|ubuntu|debian|devuan|archlinux|coreos|freebsd) : ;; *) From 60eba4214137f2eb43052066cae8e585629603d4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 26 Mar 2018 08:52:41 +0200 Subject: [PATCH 0801/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 272d1751..ce5a169d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,8 @@ Changelog next: * Documentation, type manpages: Fix spelling (Dmitry Bogatov) + * New explorer: is-freebsd-jail (Kamila Součková) + * Types __hostname, __start_on_boot, __sysctl: Support FreeBSD (Kamila Součková) 4.8.3: 2018-03-16 * Type __key_value: Add onchange parameter (Kamila Součková) From 999f221c880f2209c178627c892c5ec3fefebfb6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 5 Apr 2018 10:32:33 +0200 Subject: [PATCH 0802/1332] need a way to distinguish between install-config and normal config Signed-off-by: Steven Armstrong --- cdist/conf/type/__install_config/gencode-local | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__install_config/gencode-local b/cdist/conf/type/__install_config/gencode-local index 8f24cf2e..dd4f2a78 100755 --- a/cdist/conf/type/__install_config/gencode-local +++ b/cdist/conf/type/__install_config/gencode-local @@ -1,6 +1,6 @@ #!/bin/sh -e # -# 2011-2017 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2018 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -23,6 +23,7 @@ remote_exec="$__type/files/remote/exec" remote_copy="$__type/files/remote/copy" cat << DONE +export __cdist_install_config=yes export __cdist_log_level=$__cdist_log_level export __default_remote_exec="$__remote_exec" export __default_remote_copy="$__remote_copy" From 43a65d91b10cb2e393bf74e74a09f0e597992f32 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 5 Apr 2018 10:36:38 +0200 Subject: [PATCH 0803/1332] changelog++ Signed-off-by: Steven Armstrong --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index ce5a169d..bd8996cb 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,8 @@ next: * Documentation, type manpages: Fix spelling (Dmitry Bogatov) * New explorer: is-freebsd-jail (Kamila Součková) * Types __hostname, __start_on_boot, __sysctl: Support FreeBSD (Kamila Součková) + * Type __install_config: set environment variable to distinguish between + install-config and regular config (Steven Armstrong) 4.8.3: 2018-03-16 * Type __key_value: Add onchange parameter (Kamila Součková) From f09765a03af9fe9576acff4041b342d2ffb6324d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 17 Apr 2018 11:15:28 +0200 Subject: [PATCH 0804/1332] Improve error reporting. --- cdist/__init__.py | 81 +++++++++++++++++++++++++++++++++----------- cdist/config.py | 3 +- cdist/exec/local.py | 6 ++-- cdist/exec/remote.py | 6 ++-- cdist/exec/util.py | 1 + 5 files changed, 68 insertions(+), 29 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index e6fdfac6..b1b9df9f 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -83,41 +83,72 @@ class CdistBetaRequired(cdist.Error): class CdistEntityError(Error): """Something went wrong while executing cdist entity""" - def __init__(self, entity_name, entity_params, stderr_paths, subject=''): + def __init__(self, entity_name, entity_params, stdout_paths, + stderr_paths, subject=''): self.entity_name = entity_name self.entity_params = entity_params self.stderr_paths = stderr_paths + self.stdout_paths = stdout_paths if isinstance(subject, Error): self.original_error = subject else: self.original_error = None self.message = str(subject) - @property - def stderr(self): - output = [] - for stderr_name, stderr_path in self.stderr_paths: - if (os.path.exists(stderr_path) and - os.path.getsize(stderr_path) > 0): - label_begin = '---- BEGIN ' + stderr_name + ':stderr ----' - label_end = '---- END ' + stderr_name + ':stderr ----' - output.append('\n' + label_begin) - with open(stderr_path, 'r') as fd: + def _stdpath(self, stdpaths, header_name): + result = {} + for name, path in stdpaths: + if name not in result: + result[name] = [] + if os.path.exists(path) and os.path.getsize(path) > 0: + output = [] + label_begin = name + ":" + header_name + output.append(label_begin) + output.append('\n') + output.append('-' * len(label_begin)) + output.append('\n') + with open(path, 'r') as fd: output.append(fd.read()) - output.append(label_end) - return '\n'.join(output) + output.append('\n') + result[name].append(''.join(output)) + return result + + def _stderr(self): + return self._stdpath(self.stderr_paths, 'stderr') + + def _stdout(self): + return self._stdpath(self.stdout_paths, 'stdout') + + def _update_dict_list(self, target, source): + for x in source: + if x not in target: + target[x] = [] + target[x].extend(source[x]) + + @property + def std_streams(self): + std_dict = {} + self._update_dict_list(std_dict, self._stdout()) + self._update_dict_list(std_dict, self._stderr()) + return std_dict def __str__(self): output = [] output.append(self.message) - header = "\nError processing " + self.entity_name + output.append('\n\n') + header = "Error processing " + self.entity_name under_header = '=' * len(header) output.append(header) + output.append('\n') output.append(under_header) + output.append('\n') for param_name, param_value in self.entity_params: output.append(param_name + ': ' + str(param_value)) - output.append(self.stderr + '\n') - return '\n'.join(output) + output.append('\n') + output.append('\n') + for x in self.std_streams: + output.append(''.join(self.std_streams[x])) + return ''.join(output) class CdistObjectError(CdistEntityError): @@ -127,28 +158,38 @@ class CdistObjectError(CdistEntityError): ('name', cdist_object.name, ), ('path', cdist_object.absolute_path, ), ('source', " ".join(cdist_object.source), ), - ('type', cdist_object.cdist_type.absolute_path, ), + ('type', os.path.realpath(cdist_object.cdist_type.absolute_path), ), ] stderr_paths = [] for stderr_name in os.listdir(cdist_object.stderr_path): stderr_path = os.path.join(cdist_object.stderr_path, stderr_name) stderr_paths.append((stderr_name, stderr_path, )) + stdout_paths = [] + for stdout_name in os.listdir(cdist_object.stdout_path): + stdout_path = os.path.join(cdist_object.stdout_path, + stdout_name) + stdout_paths.append((stdout_name, stdout_path, )) super().__init__("object '{}'".format(cdist_object.name), - params, stderr_paths, subject) + params, stdout_paths, stderr_paths, subject) class InitialManifestError(CdistEntityError): """Something went wrong while executing initial manifest""" - def __init__(self, initial_manifest, stderr_path, subject=''): + def __init__(self, initial_manifest, stdout_path, stderr_path, subject=''): params = [ ('path', initial_manifest, ), ] + stdout_paths = [] + stdout_paths = [ + ('init', stdout_path, ), + ] stderr_paths = [] stderr_paths = [ ('init', stderr_path, ), ] - super().__init__('initial manifest', params, stderr_paths, subject) + super().__init__('initial manifest', params, stdout_paths, + stderr_paths, subject) def file_to_list(filename): diff --git a/cdist/config.py b/cdist/config.py index 74f68a72..2dcb1005 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -440,9 +440,10 @@ class Config(object): self.manifest.run_initial_manifest(self.local.initial_manifest) except cdist.Error as e: which = "init" + stdout_path = os.path.join(self.local.stdout_base_path, which) stderr_path = os.path.join(self.local.stderr_base_path, which) raise cdist.InitialManifestError(self.local.initial_manifest, - stderr_path, e) + stdout_path, stderr_path, e) self.iterate_until_finished() self.cleanup() self._remove_files_dirs() diff --git a/cdist/exec/local.py b/cdist/exec/local.py index a50fe072..f83c85df 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -259,10 +259,8 @@ class Local(object): util.log_std_fd(self.log, command, stderr, 'Local stderr') util.log_std_fd(self.log, command, stdout, 'Local stdout') return output - except subprocess.CalledProcessError as e: - util.handle_called_process_error(e, command) - except OSError as error: - raise cdist.Error(" ".join(command) + ": " + error.args[1]) + except (OSError, subprocess.CalledProcessError) as error: + raise cdist.Error(" ".join(command) + ": " + str(error.args[1])) finally: if message_prefix: message.merge_messages() diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index b75905ba..4466545e 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -343,10 +343,8 @@ class Remote(object): util.log_std_fd(self.log, command, stdout, 'Remote stdout') return output - except subprocess.CalledProcessError as e: - util.handle_called_process_error(e, command) - except OSError as error: - raise cdist.Error(" ".join(command) + ": " + error.args[1]) + except (OSError, subprocess.CalledProcessError) as error: + raise cdist.Error(" ".join(command) + ": " + str(error.args[1])) except UnicodeDecodeError: raise DecodeError(command) finally: diff --git a/cdist/exec/util.py b/cdist/exec/util.py index 2f2aa38c..c96f757b 100644 --- a/cdist/exec/util.py +++ b/cdist/exec/util.py @@ -127,6 +127,7 @@ def call_get_output(command, env=None, stderr=None): return (_call_get_stdout(command, env, stderr), None) +# Currently not used. def handle_called_process_error(err, command): # Currently, stderr is not captured. # errout = None From 2a9057f892f67014a67a34ffb260318ea8465349 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 19 Apr 2018 17:53:47 +0200 Subject: [PATCH 0805/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index bd8996cb..e958ddff 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: * Types __hostname, __start_on_boot, __sysctl: Support FreeBSD (Kamila Součková) * Type __install_config: set environment variable to distinguish between install-config and regular config (Steven Armstrong) + * Core: Improve error reporting (Darko Poljak) 4.8.3: 2018-03-16 * Type __key_value: Add onchange parameter (Kamila Součková) From 7349da777be5316a9130033af7f9ebf852ddb02d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 20 Apr 2018 14:24:51 +0200 Subject: [PATCH 0806/1332] ++changelog --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index e958ddff..681256fc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,7 +6,7 @@ next: * New explorer: is-freebsd-jail (Kamila Součková) * Types __hostname, __start_on_boot, __sysctl: Support FreeBSD (Kamila Součková) * Type __install_config: set environment variable to distinguish between - install-config and regular config (Steven Armstrong) + install-config and regular config (Steven Armstrong) * Core: Improve error reporting (Darko Poljak) 4.8.3: 2018-03-16 From 09642142f478ee61b804f7ad1f6f5ecd6fd70d66 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 20 Apr 2018 14:31:10 +0200 Subject: [PATCH 0807/1332] Release 4.8.4 --- cdist/__init__.py | 3 ++- docs/changelog | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index b1b9df9f..b7602ff8 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -158,7 +158,8 @@ class CdistObjectError(CdistEntityError): ('name', cdist_object.name, ), ('path', cdist_object.absolute_path, ), ('source', " ".join(cdist_object.source), ), - ('type', os.path.realpath(cdist_object.cdist_type.absolute_path), ), + ('type', os.path.realpath( + cdist_object.cdist_type.absolute_path), ), ] stderr_paths = [] for stderr_name in os.listdir(cdist_object.stderr_path): diff --git a/docs/changelog b/docs/changelog index 681256fc..6330a149 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.8.4: 2018-04-20 * Documentation, type manpages: Fix spelling (Dmitry Bogatov) * New explorer: is-freebsd-jail (Kamila Součková) * Types __hostname, __start_on_boot, __sysctl: Support FreeBSD (Kamila Součková) From aa20ed5ea1b3c833acc78c54166f655c2b9cd355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Sun, 29 Apr 2018 13:02:18 +0200 Subject: [PATCH 0808/1332] __docker_stack: Use --with-registry-auth deploy option Without this option, Swarm agents are unable to download images from private registries. --- cdist/conf/type/__docker_stack/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker_stack/gencode-remote b/cdist/conf/type/__docker_stack/gencode-remote index 0d47dc52..586271d0 100755 --- a/cdist/conf/type/__docker_stack/gencode-remote +++ b/cdist/conf/type/__docker_stack/gencode-remote @@ -50,7 +50,7 @@ case "${state}" in eof docker stack deploy --compose-file "\${compose_file}" \ - --prune ${stack} + --prune --with-registry-auth ${stack} rm "\${compose_file}" EOF From 3869940fc8ae4a8c35656298ce40146a111b7064 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 29 Apr 2018 20:39:39 +0200 Subject: [PATCH 0809/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 6330a149..74d6d7c6 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __docker_stack: Use --with-registry-auth option (Ľubomír Kučera) + 4.8.4: 2018-04-20 * Documentation, type manpages: Fix spelling (Dmitry Bogatov) * New explorer: is-freebsd-jail (Kamila Součková) From 4f61f6be9cd2052ede37dfb184211e23e9ec6328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Mon, 30 Apr 2018 12:50:09 +0200 Subject: [PATCH 0810/1332] Add new type __docker_config --- .../type/__docker_config/explorer/config-data | 21 ++++++ .../__docker_config/explorer/config-exists | 25 +++++++ .../conf/type/__docker_config/gencode-remote | 69 +++++++++++++++++++ cdist/conf/type/__docker_config/man.rst | 55 +++++++++++++++ .../__docker_config/parameter/default/source | 0 .../__docker_config/parameter/default/state | 1 + .../type/__docker_config/parameter/optional | 2 + 7 files changed, 173 insertions(+) create mode 100644 cdist/conf/type/__docker_config/explorer/config-data create mode 100755 cdist/conf/type/__docker_config/explorer/config-exists create mode 100755 cdist/conf/type/__docker_config/gencode-remote create mode 100644 cdist/conf/type/__docker_config/man.rst create mode 100644 cdist/conf/type/__docker_config/parameter/default/source create mode 100644 cdist/conf/type/__docker_config/parameter/default/state create mode 100644 cdist/conf/type/__docker_config/parameter/optional diff --git a/cdist/conf/type/__docker_config/explorer/config-data b/cdist/conf/type/__docker_config/explorer/config-data new file mode 100644 index 00000000..926a795d --- /dev/null +++ b/cdist/conf/type/__docker_config/explorer/config-data @@ -0,0 +1,21 @@ +#!/bin/sh -e +# +# 2018 Ľubomír Kučera +# +# 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 . +# + +docker config inspect "${__object_id:?}" | jq -r '.[0].Spec.Data' | base64 -d diff --git a/cdist/conf/type/__docker_config/explorer/config-exists b/cdist/conf/type/__docker_config/explorer/config-exists new file mode 100755 index 00000000..58c207d4 --- /dev/null +++ b/cdist/conf/type/__docker_config/explorer/config-exists @@ -0,0 +1,25 @@ +#!/bin/sh -e +# +# 2018 Ľubomír Kučera +# +# 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 docker config ls | grep -q " ${__object_id:?} "; then + echo yes +else + echo no +fi diff --git a/cdist/conf/type/__docker_config/gencode-remote b/cdist/conf/type/__docker_config/gencode-remote new file mode 100755 index 00000000..65497b7e --- /dev/null +++ b/cdist/conf/type/__docker_config/gencode-remote @@ -0,0 +1,69 @@ +#!/bin/sh -e +# +# 2018 Ľubomír Kučera +# +# 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 . +# + +config="${__object_id:?}" +config_exists=$(cat "${__object:?}/explorer/config-exists") +state=$(cat "${__object:?}/parameter/state") + +case "${state}" in + absent) + if [ "${config_exists}" != "yes" ]; then + exit 0 + fi + + echo "docker config rm \"${config}\"" + ;; + present) + source=$(cat "${__object}/parameter/source") + + if [ -z "${source}" ]; then + exit 0 + fi + + if [ "${source}" = "-" ]; then + source="${__object}/stdin" + fi + + if [ "${config_exists}" = "yes" ]; then + if cmp -s "${source}" "${__object}/explorer/config-data"; then + exit 0 + else + echo "docker config rm \"${config}\"" + fi + fi + + cat <<-EOF + source_file="\$(mktemp cdist.XXXXXXXXXX)" + + base64 -d > "\${source_file}" << eof + $(base64 "${source}") + eof + + docker config create "${config}" "\${source_file}" + + rm "\${source_file}" + EOF + ;; + *) + echo "Unsupported state: ${state}" >&2 + + exit 1 + ;; +esac diff --git a/cdist/conf/type/__docker_config/man.rst b/cdist/conf/type/__docker_config/man.rst new file mode 100644 index 00000000..7c74c8af --- /dev/null +++ b/cdist/conf/type/__docker_config/man.rst @@ -0,0 +1,55 @@ +cdist-type__docker_config(7) +============================ + +NAME +---- + +cdist-type__docker_config - Manage Docker configs + +DESCRIPTION +----------- + +This type manages Docker configs. + +OPTIONAL PARAMETERS +------------------- + +source + Path to the source file. If it is '-' (dash), read standard input. + +state + 'present' or 'absent', defaults to 'present' where: + + present + if the config does not exist, it is created + absent + the config is removed + +CAVEATS +------- + +Since Docker configs cannot be updated once created, this type tries removing +and recreating the config if it changes. If the config is used by a service at +the time of removing, then this type will fail. + +EXAMPLES +-------- + +.. code-block:: sh + + # Creates "foo" config from "bar" source file + __docker_config foo --source bar + + +AUTHORS +------- + +Ľubomír Kučera + +COPYING +------- + +Copyright \(C) 2018 Ľubomír Kučera. 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/__docker_config/parameter/default/source b/cdist/conf/type/__docker_config/parameter/default/source new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__docker_config/parameter/default/state b/cdist/conf/type/__docker_config/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__docker_config/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__docker_config/parameter/optional b/cdist/conf/type/__docker_config/parameter/optional new file mode 100644 index 00000000..d77f3048 --- /dev/null +++ b/cdist/conf/type/__docker_config/parameter/optional @@ -0,0 +1,2 @@ +source +state From 5a7d74b90542de9ad179268c0561fbffbf0c8f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Mon, 30 Apr 2018 12:52:54 +0200 Subject: [PATCH 0811/1332] Add new type __docker_secret --- .../__docker_secret/explorer/secret-exists | 25 +++++++ .../conf/type/__docker_secret/gencode-remote | 65 +++++++++++++++++++ cdist/conf/type/__docker_secret/man.rst | 54 +++++++++++++++ .../__docker_secret/parameter/default/source | 0 .../__docker_secret/parameter/default/state | 1 + .../type/__docker_secret/parameter/optional | 2 + 6 files changed, 147 insertions(+) create mode 100644 cdist/conf/type/__docker_secret/explorer/secret-exists create mode 100644 cdist/conf/type/__docker_secret/gencode-remote create mode 100644 cdist/conf/type/__docker_secret/man.rst create mode 100644 cdist/conf/type/__docker_secret/parameter/default/source create mode 100644 cdist/conf/type/__docker_secret/parameter/default/state create mode 100644 cdist/conf/type/__docker_secret/parameter/optional diff --git a/cdist/conf/type/__docker_secret/explorer/secret-exists b/cdist/conf/type/__docker_secret/explorer/secret-exists new file mode 100644 index 00000000..1405f8bc --- /dev/null +++ b/cdist/conf/type/__docker_secret/explorer/secret-exists @@ -0,0 +1,25 @@ +#!/bin/sh -e +# +# 2018 Ľubomír Kučera +# +# 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 docker secret ls | grep -q " ${__object_id:?} "; then + echo yes +else + echo no +fi diff --git a/cdist/conf/type/__docker_secret/gencode-remote b/cdist/conf/type/__docker_secret/gencode-remote new file mode 100644 index 00000000..c75e91d9 --- /dev/null +++ b/cdist/conf/type/__docker_secret/gencode-remote @@ -0,0 +1,65 @@ +#!/bin/sh -e +# +# 2018 Ľubomír Kučera +# +# 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 . +# + +secret="${__object_id:?}" +secret_exists=$(cat "${__object:?}/explorer/secret-exists") +state=$(cat "${__object:?}/parameter/state") + +case "${state}" in + absent) + if [ "${secret_exists}" != "yes" ]; then + exit 0 + fi + + echo "docker secret rm ${secret}" + ;; + present) + if [ "${secret_exists}" = "yes" ]; then + exit 0 + fi + + source=$(cat "${__object}/parameter/source") + + if [ -z "${source}" ]; then + exit 0 + fi + + if [ "${source}" = "-" ]; then + source="${__object}/stdin" + fi + + cat <<-EOF + source_file="\$(mktemp cdist.XXXXXXXXXX)" + + base64 -d > "\${source_file}" << eof + $(base64 "${source}") + eof + + docker secret create "${secret}" "\${source_file}" + + rm "\${source_file}" + EOF + ;; + *) + echo "Unsupported state: ${state}" >&2 + + exit 1 + ;; +esac diff --git a/cdist/conf/type/__docker_secret/man.rst b/cdist/conf/type/__docker_secret/man.rst new file mode 100644 index 00000000..7fe69623 --- /dev/null +++ b/cdist/conf/type/__docker_secret/man.rst @@ -0,0 +1,54 @@ +cdist-type__docker_secret(7) +============================ + +NAME +---- + +cdist-type__docker_secret - Manage Docker secrets + +DESCRIPTION +----------- + +This type manages Docker secrets. + +OPTIONAL PARAMETERS +------------------- + +source + Path to the source file. If it is '-' (dash), read standard input. + +state + 'present' or 'absent', defaults to 'present' where: + + present + if the secret does not exist, it is created + absent + the secret is removed + +CAVEATS +------- + +Since Docker secrets cannot be updated once created, this type takes no action +if the specified secret already exists. + +EXAMPLES +-------- + +.. code-block:: sh + + # Creates "foo" secret from "bar" source file + __docker_secret foo --source bar + + +AUTHORS +------- + +Ľubomír Kučera + +COPYING +------- + +Copyright \(C) 2018 Ľubomír Kučera. 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/__docker_secret/parameter/default/source b/cdist/conf/type/__docker_secret/parameter/default/source new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__docker_secret/parameter/default/state b/cdist/conf/type/__docker_secret/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__docker_secret/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__docker_secret/parameter/optional b/cdist/conf/type/__docker_secret/parameter/optional new file mode 100644 index 00000000..d77f3048 --- /dev/null +++ b/cdist/conf/type/__docker_secret/parameter/optional @@ -0,0 +1,2 @@ +source +state From b5e96efcbff20f403e5a3f4c5f3ab31c76dfde9e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 2 May 2018 08:35:12 +0200 Subject: [PATCH 0812/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 74d6d7c6..3bdf446b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,8 @@ Changelog next: * Type __docker_stack: Use --with-registry-auth option (Ľubomír Kučera) + * New type: __docker_config (Ľubomír Kučera) + * New type: __docker_secret (Ľubomír Kučera) 4.8.4: 2018-04-20 * Documentation, type manpages: Fix spelling (Dmitry Bogatov) From 1efbd6a3a054d44dd4c399274fc6cd3e417e887f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Fri, 4 May 2018 16:37:45 +0200 Subject: [PATCH 0813/1332] __docker_config: Fix config-data explorer Before this fix, the explorer returned binary data when config did not exist. This commit also removes dependency on jq and sets executable flag on the explorer file. --- cdist/conf/type/__docker_config/explorer/config-data | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 cdist/conf/type/__docker_config/explorer/config-data diff --git a/cdist/conf/type/__docker_config/explorer/config-data b/cdist/conf/type/__docker_config/explorer/config-data old mode 100644 new mode 100755 index 926a795d..b4bb0e11 --- a/cdist/conf/type/__docker_config/explorer/config-data +++ b/cdist/conf/type/__docker_config/explorer/config-data @@ -18,4 +18,5 @@ # along with cdist. If not, see . # -docker config inspect "${__object_id:?}" | jq -r '.[0].Spec.Data' | base64 -d +docker config inspect "${__object_id:?}" --format '{{json .Spec.Data}}' \ + 2>/dev/null | tr -d '"' | base64 -d From fdb5bbcf91389626f9e32f6909db1c3bd8c89abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Fri, 4 May 2018 16:47:09 +0200 Subject: [PATCH 0814/1332] __docker_secret: Set executable flag on scripts --- cdist/conf/type/__docker_secret/explorer/secret-exists | 0 cdist/conf/type/__docker_secret/gencode-remote | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 cdist/conf/type/__docker_secret/explorer/secret-exists mode change 100644 => 100755 cdist/conf/type/__docker_secret/gencode-remote diff --git a/cdist/conf/type/__docker_secret/explorer/secret-exists b/cdist/conf/type/__docker_secret/explorer/secret-exists old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__docker_secret/gencode-remote b/cdist/conf/type/__docker_secret/gencode-remote old mode 100644 new mode 100755 From 22d570ae6084710d7af60dcd36ad9f0ec8ea882c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Mon, 7 May 2018 12:57:48 +0200 Subject: [PATCH 0815/1332] Rewrite __letsencrypt_cert type This commit adds the following features: * Ability to expand existing certificate * Ability to manage object state * Ability to obtain test certificate * Ability to promote test certificate to production * Ability to specify custom certificate name * Ability to specify multiple domains per certificate * Ability to use Certbot in standalone mode * Messaging This commit also introduces the following behavioral changes: * Attempt to install Certbot only when it is not installed already * Installation of the cron job has to be enabled using `--automatic-renewal` parameter **Note:** Object ID is now treated as certificate name and new required parameter `--domain` was added. --- .../__letsencrypt_cert/explorer/certbot-path | 3 + .../explorer/certificate-domains | 4 + .../explorer/certificate-exists | 7 + .../explorer/certificate-is-test | 8 + .../type/__letsencrypt_cert/explorer/exists | 5 - .../type/__letsencrypt_cert/gencode-remote | 85 ++++++++-- cdist/conf/type/__letsencrypt_cert/man.rst | 73 +++++++-- cdist/conf/type/__letsencrypt_cert/manifest | 152 ++++++++++-------- .../type/__letsencrypt_cert/parameter/boolean | 2 + .../parameter/default/state | 1 + .../parameter/default/webroot | 0 .../__letsencrypt_cert/parameter/optional | 2 + .../__letsencrypt_cert/parameter/required | 1 - .../parameter/required_multiple | 1 + 14 files changed, 239 insertions(+), 105 deletions(-) create mode 100755 cdist/conf/type/__letsencrypt_cert/explorer/certbot-path create mode 100755 cdist/conf/type/__letsencrypt_cert/explorer/certificate-domains create mode 100755 cdist/conf/type/__letsencrypt_cert/explorer/certificate-exists create mode 100755 cdist/conf/type/__letsencrypt_cert/explorer/certificate-is-test delete mode 100644 cdist/conf/type/__letsencrypt_cert/explorer/exists mode change 100644 => 100755 cdist/conf/type/__letsencrypt_cert/gencode-remote mode change 100644 => 100755 cdist/conf/type/__letsencrypt_cert/manifest create mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/boolean create mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/default/state create mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/default/webroot create mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/optional create mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/required_multiple diff --git a/cdist/conf/type/__letsencrypt_cert/explorer/certbot-path b/cdist/conf/type/__letsencrypt_cert/explorer/certbot-path new file mode 100755 index 00000000..3c6076df --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/explorer/certbot-path @@ -0,0 +1,3 @@ +#!/bin/sh -e + +command -v certbot 2>/dev/null || true diff --git a/cdist/conf/type/__letsencrypt_cert/explorer/certificate-domains b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-domains new file mode 100755 index 00000000..367fda93 --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-domains @@ -0,0 +1,4 @@ +#!/bin/sh -e + +certbot certificates --cert-name "${__object_id:?}" | grep ' Domains: ' | \ + cut -d ' ' -f 6- | tr ' ' '\n' diff --git a/cdist/conf/type/__letsencrypt_cert/explorer/certificate-exists b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-exists new file mode 100755 index 00000000..d2ea35cc --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-exists @@ -0,0 +1,7 @@ +#!/bin/sh -e + +if certbot certificates | grep -q " Certificate Name: ${__object_id:?}$"; then + echo yes +else + echo no +fi diff --git a/cdist/conf/type/__letsencrypt_cert/explorer/certificate-is-test b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-is-test new file mode 100755 index 00000000..6d7b0ae9 --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-is-test @@ -0,0 +1,8 @@ +#!/bin/sh -e + +if certbot certificates --cert-name "${__object_id:?}" | \ + grep -q 'INVALID: TEST_CERT'; then + echo yes +else + echo no +fi diff --git a/cdist/conf/type/__letsencrypt_cert/explorer/exists b/cdist/conf/type/__letsencrypt_cert/explorer/exists deleted file mode 100644 index cb967663..00000000 --- a/cdist/conf/type/__letsencrypt_cert/explorer/exists +++ /dev/null @@ -1,5 +0,0 @@ -domain=$__object_id - -if [ -f "/etc/letsencrypt/live/$domain/fullchain.pem" ]; then - echo yes -fi diff --git a/cdist/conf/type/__letsencrypt_cert/gencode-remote b/cdist/conf/type/__letsencrypt_cert/gencode-remote old mode 100644 new mode 100755 index 62ada241..4bd05eff --- a/cdist/conf/type/__letsencrypt_cert/gencode-remote +++ b/cdist/conf/type/__letsencrypt_cert/gencode-remote @@ -1,18 +1,75 @@ -domain="$__object_id" +#!/bin/sh -e -exists=$(cat "$__object/explorer/exists") -webroot="$(cat "$__object/parameter/webroot")" -admin_email="$(cat "$__object/parameter/admin-email")" +certificate_exists=$(cat "${__object:?}/explorer/certificate-exists") +name="${__object_id:?}" +state=$(cat "${__object}/parameter/state") -if [ -n "$exists" ]; then - exit 0 -fi +case "${state}" in + absent) + if [ "${certificate_exists}" = "no" ]; then + exit 0 + fi -cat <> "${__messages_out:?}" + ;; + present) + requested_domains="${__object}/parameter/domain" + + staging=no + if [ -f "${__object}/parameter/staging" ]; then + staging=yes + fi + + if [ "${certificate_exists}" = "yes" ]; then + existing_domains="${__object}/explorer/certificate-domains" + certificate_is_test=$(cat "${__object}/explorer/certificate-is-test") + + sort -uo "${requested_domains}" "${requested_domains}" + sort -uo "${existing_domains}" "${existing_domains}" + + if [ -z "$(comm -23 "${requested_domains}" "${existing_domains}")" ] && \ + [ "${certificate_is_test}" = "${staging}" ]; then + exit 0 + fi + fi + + admin_email="$(cat "$__object/parameter/admin-email")" + webroot="$(cat "$__object/parameter/webroot")" + + cat <<-EOF + certbot certonly \ + --agree-tos \ + --cert-name '${name}' \ + --email '${admin_email}' \ + --expand \ + --non-interactive \ + --quiet \ + $(if [ "${staging}" = "yes" ]; then + echo "--staging" + elif [ "${certificate_is_test}" != "${staging}" ]; then + echo "--force-renewal" + fi) \ + $(if [ -z "${webroot}" ]; then + echo "--standalone" + else + echo "--webroot --webroot-path '${webroot}'" + fi) \ + $(while read -r domain; do + echo "--domain '${domain}' \\" + done < "${requested_domains}") + EOF + + if [ "${certificate_exists}" = "no" ]; then + echo create >> "${__messages_out}" + else + echo change >> "${__messages_out}" + fi + ;; + *) + echo "Unsupported state: ${state}" >&2 + + exit 1 + ;; +esac diff --git a/cdist/conf/type/__letsencrypt_cert/man.rst b/cdist/conf/type/__letsencrypt_cert/man.rst index bb1e5d05..16b23fea 100644 --- a/cdist/conf/type/__letsencrypt_cert/man.rst +++ b/cdist/conf/type/__letsencrypt_cert/man.rst @@ -3,54 +3,95 @@ cdist-type__letsencrypt_cert(7) NAME ---- -cdist-type__letsencrypt_cert - Get an SSL certificate from Let's Encrypt +cdist-type__letsencrypt_cert - Get an SSL certificate from Let's Encrypt DESCRIPTION ----------- -Automatically obtain a Let's Encrypt SSL certificate. Uses certbot's webroot -method. You must set up your web server to work with webroot. +Automatically obtain a Let's Encrypt SSL certificate using Certbot. REQUIRED PARAMETERS ------------------- -webroot - The path to your webroot, as set up in your webserver config. admin-email - Where to send Let's Encrypt emails like "certificate needs renewal". + Where to send Let's Encrypt emails like "certificate needs renewal". +REQUIRED MULTIPLE PARAMETERS +---------------------------- + +domain + A domain to be included in the certificate. OPTIONAL PARAMETERS ------------------- -None. +state + 'present' or 'absent', defaults to 'present' where: + + present + if the certificate does not exist, it will be obtained + absent + the certificate will be removed + +webroot + The path to your webroot, as set up in your webserver config. If this + parameter is not present, Certbot will be run in standalone mode. OPTIONAL MULTIPLE PARAMETERS ---------------------------- + renew-hook - Renew hook command directly passed to certbot in cron job. + Renew hook command directly passed to Certbot in cron job. + +BOOLEAN PARAMETERS +------------------ + +automatic-renewal + Install a cron job, which attempts to renew certificates daily. + +staging + Obtain a test certificate from a staging server. + +MESSAGES +-------- + +change + Certificte was changed. + +create + Certificte was created. + +remove + Certificte was removed. EXAMPLES -------- .. code-block:: sh - __letsencrypt_cert example.com --admin-email root@example.com --webroot /data/letsencrypt/root - - __letsencrypt_cert example.com --admin-email root@example.com --webroot /data/letsencrypt/root --renew-hook "service nginx reload" + __letsencrypt_cert example.com \ + --admin-email root@example.com \ + --automatic-renewal \ + --domain example.com \ + --domain foo.example.com \ + --domain bar.example.com \ + --renew-hook "service nginx reload" \ + --webroot /data/letsencrypt/root AUTHORS ------- + | Nico Schottelius | Kamila Součková | Darko Poljak - +| Ľubomír Kučera COPYING ------- -Copyright \(C) 2017 Nico Schottelius, Kamila Součková, Darko Poljak. 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) 2017-2018 Nico Schottelius, Kamila Součková, Darko Poljak and +Ľubomír Kučera. 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/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest old mode 100644 new mode 100755 index 800e5e18..94e9d225 --- a/cdist/conf/type/__letsencrypt_cert/manifest +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -1,79 +1,93 @@ -os=$(cat "$__global/explorer/os") -os_version=$(cat "$__global/explorer/os_version") +#!/bin/sh -case "$os" in - debian) - case "$os_version" in - 8*) - __apt_source jessie-backports \ - --uri http://http.debian.net/debian \ - --distribution jessie-backports \ - --component main +certbot_fullpath="$(cat "${__object:?}/explorer/certbot-path")" - require="__apt_source/jessie-backports" __package_apt python-certbot --target-release jessie-backports - require="__apt_source/jessie-backports" __package_apt certbot --target-release jessie-backports - # Seems to be a missing dependency on debian 8 - __package python-ndg-httpsclient - ;; - 9*) - __apt_source stretch-backports \ - --uri http://http.debian.net/debian \ - --distribution stretch-backports \ - --component main +if [ -z "${certbot_fullpath}" ]; then + os="$(cat "${__global:?}/explorer/os")" + os_version="$(cat "${__global}/explorer/os_version")" - require="__apt_source/stretch-backports" __package_apt python-certbot --target-release stretch-backports - require="__apt_source/stretch-backports" __package_apt certbot --target-release stretch-backports - ;; - *) - echo "Unsupported OS version: $os_version" >&2 - exit 1 - ;; - esac + case "$os" in + debian) + case "$os_version" in + 8*) + __apt_source jessie-backports \ + --uri http://http.debian.net/debian \ + --distribution jessie-backports \ + --component main - certbot_fullpath=/usr/bin/certbot - ;; - devuan) - case "$os_version" in - jessie) - __apt_source jessie-backports \ - --uri http://auto.mirror.devuan.org/merged \ - --distribution jessie-backports \ - --component main + require="__apt_source/jessie-backports" __package_apt python-certbot \ + --target-release jessie-backports + require="__apt_source/jessie-backports" __package_apt certbot \ + --target-release jessie-backports + # Seems to be a missing dependency on debian 8 + __package python-ndg-httpsclient + ;; + 9*) + __apt_source stretch-backports \ + --uri http://http.debian.net/debian \ + --distribution stretch-backports \ + --component main - require="__apt_source/jessie-backports" __package_apt python-certbot --target-release jessie-backports - require="__apt_source/jessie-backports" __package_apt certbot --target-release jessie-backports - # Seems to be a missing dependency on debian 8 - __package python-ndg-httpsclient - ;; - *) - echo "Unsupported OS version: $os_version" >&2 - exit 1 - ;; - esac + require="__apt_source/stretch-backports" __package_apt python-certbot \ + --target-release stretch-backports + require="__apt_source/stretch-backports" __package_apt certbot \ + --target-release stretch-backports + ;; + *) + echo "Unsupported OS version: $os_version" >&2 + exit 1 + ;; + esac - certbot_fullpath=/usr/bin/certbot - ;; - freebsd) - __package py27-certbot + certbot_fullpath=/usr/bin/certbot + ;; + devuan) + case "$os_version" in + jessie) + __apt_source jessie-backports \ + --uri http://auto.mirror.devuan.org/merged \ + --distribution jessie-backports \ + --component main - certbot_fullpath=/usr/local/bin/certbot - ;; - *) - echo "Unsupported os: $os" >&2 - exit 1 - ;; -esac + require="__apt_source/jessie-backports" __package_apt python-certbot \ + --target-release jessie-backports + require="__apt_source/jessie-backports" __package_apt certbot \ + --target-release jessie-backports + # Seems to be a missing dependency on debian 8 + __package python-ndg-httpsclient + ;; + *) + echo "Unsupported OS version: $os_version" >&2 + exit 1 + ;; + esac -renew_hook_param="$__object/parameter/renew-hook" -renew_hook="" -if [ -f "$renew_hook_param" ]; then - while read hook; do - renew_hook="$renew_hook --renew-hook \"$hook\"" - done < "$renew_hook_param" + certbot_fullpath=/usr/bin/certbot + ;; + freebsd) + __package py27-certbot + + certbot_fullpath=/usr/local/bin/certbot + ;; + *) + echo "Unsupported os: $os" >&2 + exit 1 + ;; + esac fi -__cron letsencrypt-certbot \ - --user root \ - --command "$certbot_fullpath renew -q $renew_hook" \ - --hour 0 \ - --minute 47 +if [ -f "${__object}/parameter/automatic-renewal" ]; then + renew_hook_param="${__object}/parameter/renew-hook" + renew_hook="" + if [ -f "${renew_hook_param}" ]; then + while read hook; do + renew_hook="${renew_hook} --renew-hook \"${hook}\"" + done < "${renew_hook_param}" + fi + + __cron letsencrypt-certbot \ + --user root \ + --command "${certbot_fullpath} renew -q ${renew_hook}" \ + --hour 0 \ + --minute 47 +fi diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/boolean b/cdist/conf/type/__letsencrypt_cert/parameter/boolean new file mode 100644 index 00000000..d5b8be99 --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/parameter/boolean @@ -0,0 +1,2 @@ +automatic-renewal +staging diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/default/state b/cdist/conf/type/__letsencrypt_cert/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/default/webroot b/cdist/conf/type/__letsencrypt_cert/parameter/default/webroot new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/optional b/cdist/conf/type/__letsencrypt_cert/parameter/optional new file mode 100644 index 00000000..0a63b11e --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/parameter/optional @@ -0,0 +1,2 @@ +state +webroot diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/required b/cdist/conf/type/__letsencrypt_cert/parameter/required index 45fe4ea6..bfe77226 100644 --- a/cdist/conf/type/__letsencrypt_cert/parameter/required +++ b/cdist/conf/type/__letsencrypt_cert/parameter/required @@ -1,2 +1 @@ admin-email -webroot diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/required_multiple b/cdist/conf/type/__letsencrypt_cert/parameter/required_multiple new file mode 100644 index 00000000..d23ab7ab --- /dev/null +++ b/cdist/conf/type/__letsencrypt_cert/parameter/required_multiple @@ -0,0 +1 @@ +domain From 72bb485db7964a37e2f3c93dc396f10b813ca1db Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 11 May 2018 18:29:43 +0200 Subject: [PATCH 0816/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 3bdf446b..64d2489e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __docker_stack: Use --with-registry-auth option (Ľubomír Kučera) * New type: __docker_config (Ľubomír Kučera) * New type: __docker_secret (Ľubomír Kučera) + * Type __letsencrypt_cert: Rewritten; WARN: breaks backward compatibility (Ľubomír Kučera) 4.8.4: 2018-04-20 * Documentation, type manpages: Fix spelling (Dmitry Bogatov) From 3cf417fa2bb8152fd0bcef757ce29d3f24649d9c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 15 May 2018 12:12:01 +0200 Subject: [PATCH 0817/1332] Fix NameError: name 'cdist_object' is not defined, #662 --- cdist/core/explorer.py | 29 +++++++++++++---------------- docs/changelog | 1 + 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 072ca692..874d36f2 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -214,22 +214,19 @@ class Explorer(object): def transfer_type_explorers(self, cdist_type): """Transfer the type explorers for the given type to the remote side.""" - try: - if cdist_type.explorers: - if cdist_type.name in self._type_explorers_transferred: - self.log.trace(("Skipping retransfer of type explorers " - "for: %s"), cdist_type) - else: - source = os.path.join(self.local.type_path, - cdist_type.explorer_path) - destination = os.path.join(self.remote.type_path, - cdist_type.explorer_path) - self.remote.mkdir(destination) - self.remote.transfer(source, destination) - self.remote.run(["chmod", "0700", "%s/*" % (destination)]) - self._type_explorers_transferred.append(cdist_type.name) - except cdist.Error as e: - raise cdist.CdistObjectError(cdist_object, e) + if cdist_type.explorers: + if cdist_type.name in self._type_explorers_transferred: + self.log.trace(("Skipping retransfer of type explorers " + "for: %s"), cdist_type) + else: + source = os.path.join(self.local.type_path, + cdist_type.explorer_path) + destination = os.path.join(self.remote.type_path, + cdist_type.explorer_path) + self.remote.mkdir(destination) + self.remote.transfer(source, destination) + self.remote.run(["chmod", "0700", "%s/*" % (destination)]) + self._type_explorers_transferred.append(cdist_type.name) def transfer_object_parameters(self, cdist_object): """Transfer the parameters for the given object to the remote side.""" diff --git a/docs/changelog b/docs/changelog index 64d2489e..1e3787fd 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * New type: __docker_config (Ľubomír Kučera) * New type: __docker_secret (Ľubomír Kučera) * Type __letsencrypt_cert: Rewritten; WARN: breaks backward compatibility (Ľubomír Kučera) + * Core: Fix NameError: name 'cdist_object' is not defined (Darko Poljak) 4.8.4: 2018-04-20 * Documentation, type manpages: Fix spelling (Dmitry Bogatov) From 6946dc877a6e25980f6d9368cee77bcccfbc68ef Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 17 May 2018 13:33:58 +0200 Subject: [PATCH 0818/1332] pep8 --- cdist/core/explorer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 874d36f2..8c18a19f 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -220,9 +220,9 @@ class Explorer(object): "for: %s"), cdist_type) else: source = os.path.join(self.local.type_path, - cdist_type.explorer_path) + cdist_type.explorer_path) destination = os.path.join(self.remote.type_path, - cdist_type.explorer_path) + cdist_type.explorer_path) self.remote.mkdir(destination) self.remote.transfer(source, destination) self.remote.run(["chmod", "0700", "%s/*" % (destination)]) From e6b6925908c3daf01c3b16c1714a5b9e9184c926 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 17 May 2018 16:11:05 +0200 Subject: [PATCH 0819/1332] Release 4.9.0 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 1e3787fd..da23589c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.9.0: 2018-05-17 * Type __docker_stack: Use --with-registry-auth option (Ľubomír Kučera) * New type: __docker_config (Ľubomír Kučera) * New type: __docker_secret (Ľubomír Kučera) From a3968f831306534c32aa3873e64c2e5a7fdfc811 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 18 May 2018 01:25:35 +0200 Subject: [PATCH 0820/1332] rewrite __line type for --before and --after support Signed-off-by: Steven Armstrong --- cdist/conf/type/__line/explorer/state | 72 +++++++-- cdist/conf/type/__line/gencode-remote | 148 ++++++++++-------- cdist/conf/type/__line/man.rst | 100 +++++++----- .../conf/type/__line/parameter/default/state | 1 + cdist/conf/type/__line/parameter/optional | 6 +- 5 files changed, 211 insertions(+), 116 deletions(-) create mode 100644 cdist/conf/type/__line/parameter/default/state diff --git a/cdist/conf/type/__line/explorer/state b/cdist/conf/type/__line/explorer/state index 08056c86..1f81b540 100755 --- a/cdist/conf/type/__line/explorer/state +++ b/cdist/conf/type/__line/explorer/state @@ -1,6 +1,6 @@ -#!/bin/sh +#!/bin/sh -e # -# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2018 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -17,26 +17,64 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -file="/$__object_id" -[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file") +if [ -f "$__object/parameter/before" ]; then + position="before" +elif [ -f "$__object/parameter/after" ]; then + position="after" +fi if [ -f "$__object/parameter/regex" ]; then - regex=$(cat "$__object/parameter/regex") - greparg="" + needle="regex" else - if [ ! -f "$__object/parameter/line" ]; then - echo "Parameter line and regex missing - cannot explore" >&2 - exit 1 - fi - regex="$(cat "$__object/parameter/line")" - greparg="-F -x" + needle="line" fi -# Allow missing file - thus 2>/dev/null -if grep -q $greparg -- "$regex" "$file" 2>/dev/null; then - echo present +if [ -f "$__object/parameter/file" ]; then + file="$(cat "$__object/parameter/file")" else - echo absent + file="/$__object_id" fi + +awk -v position="$position" -v needle="$needle" ' +BEGIN { + getline anchor < (ENVIRON["__object"] "/parameter/" position) + getline pattern < (ENVIRON["__object"] "/parameter/" needle) + state = "absent" +} +{ + if (position == "after") { + if (match($0, anchor)) { + getline + if (match($0, pattern)) { + state = "present" + } + else { + state = "wrongposition" + } + exit 0 + } + } + else if (position == "before") { + if (match($0, pattern)) { + getline + if (match($0, anchor)) { + state = "present" + } + else { + state = "wrongposition" + } + exit 0 + } + } + else { + if (match($0, pattern)) { + state = "present" + exit 0 + } + } +} +END { + print state +} +' "$file" diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index 4a75b4c5..7951ea49 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -1,7 +1,6 @@ #!/bin/sh -e # -# 2012 Nico Schottelius (nico-cdist at schottelius.org) -# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2018 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -18,76 +17,101 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -file="/$__object_id" -regex="" -state_should="present" -[ -f "$__object/parameter/file" ] && file=$(cat "$__object/parameter/file") -[ -f "$__object/parameter/regex" ] && regex=$(cat "$__object/parameter/regex") -[ -f "$__object/parameter/state" ] && state_should=$(cat "$__object/parameter/state") -[ -f "$__object/parameter/line" ] && line=$(cat "$__object/parameter/line") +if [ -f "$__object/parameter/before" -a -f "$__object/parameter/after" ]; then + echo "Use either --before OR --after but not both." >&2 + exit 1 +fi +state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" -[ "$state_should" = "$state_is" ] && exit 0 +if [ "$state_should" = "$state_is" ]; then + # nothing to do + exit 0 +fi +if [ -f "$__object/parameter/before" ]; then + position="before" +elif [ -f "$__object/parameter/after" ]; then + position="after" +else + # By default we append to the end of the file. + position="end" +fi + +if [ -f "$__object/parameter/regex" ]; then + needle="regex" +else + needle="line" +fi + +if [ -f "$__object/parameter/file" ]; then + file="$(cat "$__object/parameter/file")" +else + file="/$__object_id" +fi + +add=0 +remove=0 case "$state_should" in - present) - if [ ! "$line" ]; then - echo "Required parameter \"line\" is missing" >&2 - exit 1 - fi + present) + if [ "$state_is" = "wrongposition" ]; then + echo updated >> "$__messages_out" + remove=1 + else + echo added >> "$__messages_out" + fi + add=1 + ;; + absent) + echo removed >> "$__messages_out" + remove=1 + ;; +esac - #echo "echo \"$line\" >> $file" - #line_sanitised=$(cat "$__object/parameter/line" | sed 's/"/\"/g') - # Idea: replace ' in the string: - # '"'"' - # |------> ': end the string - # |-|---> "'": create ' in the output string - # |--> ': continue the string - # - # Replace all \ so \t and other combinations are not interpreted - # - - - # line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g" -e 's/\\/\\\\/g') - # The one above does not work: - # --line "PS1='[\t] \[\033[1m\]\h\[\033[0m\]:\w\\$ '" - # becomes - # PS1='[\\t] \\[\\033[1m\\]\\h\\[\\033[0m\\]:\\w\\$ ' - - # Only replace ' with '"'"' and keep \ as they are - line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g") - printf '%s' "printf '%s\n' '$line_sanitised' >> $file" - echo "added" >> "$__messages_out" - - ;; - absent) - if [ "$regex" -a "$line" ]; then - echo "Mutally exclusive parameters regex and line given for state absent" >&2 - exit 1 - fi - - greparg="" - if [ "$line" ]; then - regex="$line" - greparg="-F -x" - fi - - cat << eof +cat << DONE tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) # preserve ownership and permissions of existing file if [ -f "$file" ]; then cp -p "$file" "\$tmpfile" fi -grep -v $greparg "$regex" '$file' > \$tmpfile || true + +awk -v position="$position" -v needle="$needle" -v remove=$remove -v add=$add ' +BEGIN { + line_file = ENVIRON["__object"] "/parameter/line" + getline line < line_file + # Need to close line file as it may be re-read as pattern below. + close(line_file) + getline pattern < (ENVIRON["__object"] "/parameter/" needle) + getline anchor < (ENVIRON["__object"] "/parameter/" position) +} +{ + if (remove) { + if (match(\$0, pattern)) { + # skip over this line -> remove it + next + } + } + if (add) { + if (anchor && match(\$0, anchor)) { + if (position == "before") { + print line + print + } else if (position == "after") { + print + print line + } + next + } + } + print +} +END { + if (add && position == "end") { + print line + } +} +' "$file" > "\$tmpfile" mv -f "\$tmpfile" "$file" -eof - echo "removed" >> "$__messages_out" - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; -esac +DONE diff --git a/cdist/conf/type/__line/man.rst b/cdist/conf/type/__line/man.rst index b63ea2b3..d651985e 100644 --- a/cdist/conf/type/__line/man.rst +++ b/cdist/conf/type/__line/man.rst @@ -13,72 +13,102 @@ This cdist type allows you to add lines and remove lines from files. REQUIRED PARAMETERS ------------------- +None. + OPTIONAL PARAMETERS ------------------- -state - 'present' or 'absent', defaults to 'present' +after + Insert the given line after this pattern. -line - Specifies the line which should be absent or present - - Must be present, if state is present. - Must not be combined with regex, if state is absent. - -regex - If state is present, search for this pattern and add - given line, if the given regular expression does not match. - - In case of absent, ensure all lines matching the - regular expression are absent. - - The regular expression is interpreted by grep. - - Must not be combined with line, if state is absent. +before + Insert the given line before this pattern. file If supplied, use this as the destination file. Otherwise the object_id is used. +line + Specifies the line which should be absent or present. + + Must be present, if state is 'present'. + Ignored if regex is given and state is 'absent'. + +regex + If state is 'present', search for this pattern and if it matches add + the given line. + + If state is 'absent', ensure all lines matching the regular expression + are absent. + + The regular expression is interpreted by awk's match function. + +state + 'present' or 'absent', defaults to 'present' + + + +BOOLEAN PARAMETERS +------------------ +None. + + MESSAGES -------- added - The line was added. + The line was added. + +updated + The line or its position was changed. removed - The line was removed. + The line was removed. + EXAMPLES -------- .. code-block:: sh - # Manage the DAEMONS line in rc.conf - __line daemons --file /etc/rc.conf --line 'DAEMONS=(hwclock !network sshd crond postfix)' + # Manage a hosts entry for www.example.com. + __line /etc/hosts \ + --line '127.0.0.2 www.example.com' - # Ensure the home mount is present in /etc/fstab - explicitly make it present - __line home-fstab \ - --file /etc/fstab \ - --line 'filer.fs:/vol/home /home nfs defaults 0 0' \ - --state present + # Manage another hosts entry for test.example.com. + __line hosts:test.example.com \ + --file /etc/hosts \ + --line '127.0.0.3 test.example.com' - # Removes the line specifiend in "include_www" from the file "lighttpd.conf" - __line legacy_timezone --file /etc/rc.conf --regex 'TIMEZONE=.*' --state absent + # Remove the line starting with TIMEZONE from the /etc/rc.conf file. + __line legacy_timezone \ + --file /etc/rc.conf \ + --regex 'TIMEZONE=.*' \ + --state absent + + # Insert a line before another one. + __line password-auth-local:classify \ + --file /etc/pam.d/password-auth-local \ + --line '-session required pam_exec.so debug log=/tmp/classify.log /usr/local/libexec/classify' \ + --before '^session[[:space:]]+include[[:space:]]+password-auth-ac$' + + # Insert a line after another one. + __line password-auth-local:classify \ + --file /etc/pam.d/password-auth-local \ + --line '-session required pam_exec.so debug log=/tmp/classify.log /usr/local/libexec/classify' \ + --after '^session[[:space:]]+include[[:space:]]+password-auth-ac$' SEE ALSO -------- -:strong:`grep`\ (1) +:strong:`cdist-type`\ (7) AUTHORS ------- -Nico Schottelius +Steven Armstrong COPYING ------- -Copyright \(C) 2012-2013 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) 2018 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__line/parameter/default/state b/cdist/conf/type/__line/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__line/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__line/parameter/optional b/cdist/conf/type/__line/parameter/optional index 604a203e..f89a2115 100644 --- a/cdist/conf/type/__line/parameter/optional +++ b/cdist/conf/type/__line/parameter/optional @@ -1,4 +1,6 @@ -state -regex +after +before file line +regex +state From fb26894cbd45268b62eb40d4ed285dd557ea4f6c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 18 May 2018 16:57:34 +0200 Subject: [PATCH 0821/1332] when searching treat line as string, and regex as regexp Signed-off-by: Steven Armstrong --- cdist/conf/type/__line/explorer/state | 13 ++++++++++--- cdist/conf/type/__line/gencode-remote | 9 ++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__line/explorer/state b/cdist/conf/type/__line/explorer/state index 1f81b540..d27bca18 100755 --- a/cdist/conf/type/__line/explorer/state +++ b/cdist/conf/type/__line/explorer/state @@ -37,6 +37,13 @@ else fi awk -v position="$position" -v needle="$needle" ' +function _find(_text, _pattern) { + if (needle == "regex") { + return match(_text, _pattern) + } else { + return index(_text, _pattern) + } +} BEGIN { getline anchor < (ENVIRON["__object"] "/parameter/" position) getline pattern < (ENVIRON["__object"] "/parameter/" needle) @@ -46,7 +53,7 @@ BEGIN { if (position == "after") { if (match($0, anchor)) { getline - if (match($0, pattern)) { + if (_find($0, pattern)) { state = "present" } else { @@ -56,7 +63,7 @@ BEGIN { } } else if (position == "before") { - if (match($0, pattern)) { + if (_find($0, pattern)) { getline if (match($0, anchor)) { state = "present" @@ -68,7 +75,7 @@ BEGIN { } } else { - if (match($0, pattern)) { + if (_find($0, pattern)) { state = "present" exit 0 } diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index 7951ea49..996029f5 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -78,6 +78,13 @@ if [ -f "$file" ]; then fi awk -v position="$position" -v needle="$needle" -v remove=$remove -v add=$add ' +function _find(_text, _pattern) { + if (needle == "regex") { + return match(_text, _pattern) + } else { + return index(_text, _pattern) + } +} BEGIN { line_file = ENVIRON["__object"] "/parameter/line" getline line < line_file @@ -88,7 +95,7 @@ BEGIN { } { if (remove) { - if (match(\$0, pattern)) { + if (_find(\$0, pattern)) { # skip over this line -> remove it next } From e7e8f1428aafbffc8c391527ec5c84c8710f4082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Sat, 19 May 2018 17:42:25 +0200 Subject: [PATCH 0822/1332] Add new type __install_coreos --- .../conf/type/__install_coreos/gencode-remote | 19 +++++++ cdist/conf/type/__install_coreos/install | 0 cdist/conf/type/__install_coreos/man.rst | 50 +++++++++++++++++++ .../parameter/default/ignition | 0 .../type/__install_coreos/parameter/optional | 1 + .../type/__install_coreos/parameter/required | 1 + cdist/conf/type/__install_coreos/singleton | 0 7 files changed, 71 insertions(+) create mode 100755 cdist/conf/type/__install_coreos/gencode-remote create mode 100644 cdist/conf/type/__install_coreos/install create mode 100644 cdist/conf/type/__install_coreos/man.rst create mode 100644 cdist/conf/type/__install_coreos/parameter/default/ignition create mode 100644 cdist/conf/type/__install_coreos/parameter/optional create mode 100644 cdist/conf/type/__install_coreos/parameter/required create mode 100644 cdist/conf/type/__install_coreos/singleton diff --git a/cdist/conf/type/__install_coreos/gencode-remote b/cdist/conf/type/__install_coreos/gencode-remote new file mode 100755 index 00000000..fbe86479 --- /dev/null +++ b/cdist/conf/type/__install_coreos/gencode-remote @@ -0,0 +1,19 @@ +#!/bin/sh -e + +device=$(cat "${__object:?}/parameter/device") +ignition=$(cat "${__object}/parameter/ignition") + +cat < "\${ignition_file}" << eof +$(base64 "${ignition}") +eof + +coreos-install -d "${device}" \ + \$(if [ -s "\${ignition_file}" ]; then + printf -- "-i \${ignition_file}\n" + fi) + +rm "\${ignition_file}" +EOF diff --git a/cdist/conf/type/__install_coreos/install b/cdist/conf/type/__install_coreos/install new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_coreos/man.rst b/cdist/conf/type/__install_coreos/man.rst new file mode 100644 index 00000000..314f9f2a --- /dev/null +++ b/cdist/conf/type/__install_coreos/man.rst @@ -0,0 +1,50 @@ +cdist-type__install_coreos(7) +============================= + +NAME +---- + +cdist-type__install_coreos - Install CoreOS + +DESCRIPTION +----------- + +This type installs CoreOS to a given device using coreos-install_, which is +present in CoreOS ISO by default. + +.. _coreos-install: https://raw.githubusercontent.com/coreos/init/master/bin/coreos-install + +REQUIRED PARAMETERS +------------------- + +device + A device CoreOS will be installed to. + +OPTIONAL PARAMETERS +------------------- + +ignition + Path to ignition config. + +EXAMPLES +-------- + +.. code-block:: sh + + __install_coreos \ + --device /dev/sda \ + --ignition ignition.json + + +AUTHORS +------- + +Ľubomír Kučera + +COPYING +------- + +Copyright \(C) 2018 Ľubomír Kučera. 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/__install_coreos/parameter/default/ignition b/cdist/conf/type/__install_coreos/parameter/default/ignition new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__install_coreos/parameter/optional b/cdist/conf/type/__install_coreos/parameter/optional new file mode 100644 index 00000000..df284caa --- /dev/null +++ b/cdist/conf/type/__install_coreos/parameter/optional @@ -0,0 +1 @@ +ignition diff --git a/cdist/conf/type/__install_coreos/parameter/required b/cdist/conf/type/__install_coreos/parameter/required new file mode 100644 index 00000000..f89ee6a8 --- /dev/null +++ b/cdist/conf/type/__install_coreos/parameter/required @@ -0,0 +1 @@ +device diff --git a/cdist/conf/type/__install_coreos/singleton b/cdist/conf/type/__install_coreos/singleton new file mode 100644 index 00000000..e69de29b From ab696a8cb86800576db4c0d24c33338778041059 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 25 May 2018 18:01:26 +0200 Subject: [PATCH 0823/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index da23589c..7a811271 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * New type: __install_coreos (Ľubomír Kučera) + 4.9.0: 2018-05-17 * Type __docker_stack: Use --with-registry-auth option (Ľubomír Kučera) * New type: __docker_config (Ľubomír Kučera) From b3a4152e00f3a86fbc741dd02ba839e956216490 Mon Sep 17 00:00:00 2001 From: Alexander Dinu Date: Sun, 27 May 2018 17:20:55 +0200 Subject: [PATCH 0824/1332] Fix __package_yum explorer Why: In case when name contains package name with exact version specified (e.g. rpm-build-4.11.3) ``` rpm -q --whatprovides "$pkg_name" ``` will tell you that no package could provide you with 'rpm-build-4.11.3', because it's not virtual or file-provide, but exact package name. This will lead to the installation of the package which was already installed. It slows down manifest execution a lot. My change will keep previous behaviour which relies on --whatprovides and will fix wrong behaviour when argument is full package name with version. --- cdist/conf/type/__package_yum/explorer/pkg_version | 2 +- cdist/conf/type/__package_yum/gencode-remote | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__package_yum/explorer/pkg_version b/cdist/conf/type/__package_yum/explorer/pkg_version index fb3b7753..b81b0fe9 100755 --- a/cdist/conf/type/__package_yum/explorer/pkg_version +++ b/cdist/conf/type/__package_yum/explorer/pkg_version @@ -27,4 +27,4 @@ else name="$__object_id" fi -rpm -q --whatprovides "$name" 2>/dev/null || true +rpm -q "$name" 2>/dev/null || rpm -q --whatprovides "$name" 2>/dev/null || true diff --git a/cdist/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote index e9b48ee8..e1323dea 100755 --- a/cdist/conf/type/__package_yum/gencode-remote +++ b/cdist/conf/type/__package_yum/gencode-remote @@ -43,10 +43,15 @@ else opts="--assumeyes --quiet" fi -not_installed="^no package provides" +not_provided="^no package provides" +not_installed='is not installed$' -if grep -q "$not_installed" "$__object/explorer/pkg_version"; then - state_is="absent" +if grep -q "$not_provided" "$__object/explorer/pkg_version"; then + if grep -q "$not_installed" "$__object/explorer/pkg_version"; then + state_is="absent" + else + state_is="present" + fi else state_is="present" fi From 709c216096fd6a9249d1a817e6e33864dd64a2b7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 27 May 2018 19:07:57 +0200 Subject: [PATCH 0825/1332] [__consul_agent] Add LSB header so that innserv doe not fail --- .../conf/type/__consul_agent/files/consul.sysv-debian | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cdist/conf/type/__consul_agent/files/consul.sysv-debian b/cdist/conf/type/__consul_agent/files/consul.sysv-debian index a75c555d..098328b3 100644 --- a/cdist/conf/type/__consul_agent/files/consul.sysv-debian +++ b/cdist/conf/type/__consul_agent/files/consul.sysv-debian @@ -18,6 +18,16 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # +### BEGIN INIT INFO +# Provides: consul +# Required-Start: $network $local_fs $remote_fs +# Required-Stop: $local_fs +# Should-Start: +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: libvirt management daemon +### END INIT INFO if [ -f "/etc/default/consul" ]; then . /etc/default/consul From ab62d5871545cb6df3103d7d8f7e4432ebd319f6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 27 May 2018 19:09:24 +0200 Subject: [PATCH 0826/1332] ++ changes --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 7a811271..bf88e047 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * New type: __install_coreos (Ľubomír Kučera) + * Type __consul_agent: Add LSB init header (Nico Schottelius) 4.9.0: 2018-05-17 * Type __docker_stack: Use --with-registry-auth option (Ľubomír Kučera) From 81adabd1ab286d22e15fa2ac8c89bc3f8e72222a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 28 May 2018 08:04:41 +0200 Subject: [PATCH 0827/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index bf88e047..99d9bb81 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * New type: __install_coreos (Ľubomír Kučera) * Type __consul_agent: Add LSB init header (Nico Schottelius) + * Type __package_yum: Fix explorer when name contains package name with exact version specified (Aleksandr Dinu) 4.9.0: 2018-05-17 * Type __docker_stack: Use --with-registry-auth option (Ľubomír Kučera) From efebe153868e0fd6a51a89387097dc847a7ae14e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 27 May 2018 15:32:44 +0200 Subject: [PATCH 0828/1332] Fix __letsencrypt_cert type: use object id as domain if domain param is not specified --- .../type/__letsencrypt_cert/gencode-remote | 8 +++++- cdist/conf/type/__letsencrypt_cert/man.rst | 26 ++++++++++++++----- .../parameter/optional_multiple | 1 + .../parameter/required_multiple | 1 - docs/changelog | 1 + 5 files changed, 28 insertions(+), 9 deletions(-) delete mode 100644 cdist/conf/type/__letsencrypt_cert/parameter/required_multiple diff --git a/cdist/conf/type/__letsencrypt_cert/gencode-remote b/cdist/conf/type/__letsencrypt_cert/gencode-remote index 4bd05eff..788da74c 100755 --- a/cdist/conf/type/__letsencrypt_cert/gencode-remote +++ b/cdist/conf/type/__letsencrypt_cert/gencode-remote @@ -15,7 +15,13 @@ case "${state}" in echo remove >> "${__messages_out:?}" ;; present) - requested_domains="${__object}/parameter/domain" + domain_param_file="${__object}/parameter/domain" + requested_domains=$(mktemp domain.cdist.XXXXXXXXXX) + if [ -f "${domain_param_file}" ]; then + cp "${domain_param_file}" "${requested_domains}" + else + echo "$__object_id" >> "${requested_domains}" + fi staging=no if [ -f "${__object}/parameter/staging" ]; then diff --git a/cdist/conf/type/__letsencrypt_cert/man.rst b/cdist/conf/type/__letsencrypt_cert/man.rst index 16b23fea..c4ffc6bc 100644 --- a/cdist/conf/type/__letsencrypt_cert/man.rst +++ b/cdist/conf/type/__letsencrypt_cert/man.rst @@ -14,15 +14,13 @@ Automatically obtain a Let's Encrypt SSL certificate using Certbot. REQUIRED PARAMETERS ------------------- +object id + A cert name. If domain parameter is not specified then it is used + as a domain to be included in the certificate. + admin-email Where to send Let's Encrypt emails like "certificate needs renewal". -REQUIRED MULTIPLE PARAMETERS ----------------------------- - -domain - A domain to be included in the certificate. - OPTIONAL PARAMETERS ------------------- @@ -44,6 +42,10 @@ OPTIONAL MULTIPLE PARAMETERS renew-hook Renew hook command directly passed to Certbot in cron job. +domain + Domains to be included in the certificate. When specified then object id + is not used as a domain. + BOOLEAN PARAMETERS ------------------ @@ -70,6 +72,17 @@ EXAMPLES .. code-block:: sh + # use object id as domain + __letsencrypt_cert example.com \ + --admin-email root@example.com \ + --automatic-renewal \ + --renew-hook "service nginx reload" \ + --webroot /data/letsencrypt/root + +.. code-block:: sh + + # domain parameter is specified so object id is not used as domain + # and example.com needs to be included again with domain parameter __letsencrypt_cert example.com \ --admin-email root@example.com \ --automatic-renewal \ @@ -79,7 +92,6 @@ EXAMPLES --renew-hook "service nginx reload" \ --webroot /data/letsencrypt/root - AUTHORS ------- diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/optional_multiple b/cdist/conf/type/__letsencrypt_cert/parameter/optional_multiple index 3384c74f..0e866d45 100644 --- a/cdist/conf/type/__letsencrypt_cert/parameter/optional_multiple +++ b/cdist/conf/type/__letsencrypt_cert/parameter/optional_multiple @@ -1 +1,2 @@ +domain renew-hook diff --git a/cdist/conf/type/__letsencrypt_cert/parameter/required_multiple b/cdist/conf/type/__letsencrypt_cert/parameter/required_multiple deleted file mode 100644 index d23ab7ab..00000000 --- a/cdist/conf/type/__letsencrypt_cert/parameter/required_multiple +++ /dev/null @@ -1 +0,0 @@ -domain diff --git a/docs/changelog b/docs/changelog index 99d9bb81..250baae5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * New type: __install_coreos (Ľubomír Kučera) * Type __consul_agent: Add LSB init header (Nico Schottelius) * Type __package_yum: Fix explorer when name contains package name with exact version specified (Aleksandr Dinu) + * Type __letsencrypt_cert: Use object id as domain if domain param is not specified (Darko Poljak) 4.9.0: 2018-05-17 * Type __docker_stack: Use --with-registry-auth option (Ľubomír Kučera) From 5ec99ceda2a3d6a3c7478d46f9f941e89be3ca0d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 30 May 2018 19:44:54 +0200 Subject: [PATCH 0829/1332] Release 4.9.1 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 250baae5..38411e14 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.9.1: 2018-05-30 * New type: __install_coreos (Ľubomír Kučera) * Type __consul_agent: Add LSB init header (Nico Schottelius) * Type __package_yum: Fix explorer when name contains package name with exact version specified (Aleksandr Dinu) From 4516ee0baabef2c3a612d624a60fce27fd43ced0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 1 Jun 2018 15:27:40 +0200 Subject: [PATCH 0830/1332] position can not be empty Signed-off-by: Steven Armstrong --- cdist/conf/type/__line/explorer/state | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdist/conf/type/__line/explorer/state b/cdist/conf/type/__line/explorer/state index d27bca18..afdf3502 100755 --- a/cdist/conf/type/__line/explorer/state +++ b/cdist/conf/type/__line/explorer/state @@ -22,6 +22,9 @@ if [ -f "$__object/parameter/before" ]; then position="before" elif [ -f "$__object/parameter/after" ]; then position="after" +else + # By default we append to the end of the file. + position="end" fi if [ -f "$__object/parameter/regex" ]; then From 90adefe2e455e7ab8cef2629145ec0ad7136fbc4 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Thu, 7 Jun 2018 15:07:00 +0300 Subject: [PATCH 0831/1332] add __acl: Basic wrapper around setfacl --- cdist/conf/type/__acl/explorer/acl_is | 23 ++++++ cdist/conf/type/__acl/gencode-remote | 81 +++++++++++++++++++ cdist/conf/type/__acl/man.rst | 62 ++++++++++++++ cdist/conf/type/__acl/parameter/boolean | 3 + .../type/__acl/parameter/optional_multiple | 2 + 5 files changed, 171 insertions(+) create mode 100755 cdist/conf/type/__acl/explorer/acl_is create mode 100755 cdist/conf/type/__acl/gencode-remote create mode 100644 cdist/conf/type/__acl/man.rst create mode 100644 cdist/conf/type/__acl/parameter/boolean create mode 100644 cdist/conf/type/__acl/parameter/optional_multiple diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is new file mode 100755 index 00000000..4dc98c51 --- /dev/null +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -0,0 +1,23 @@ +#!/bin/sh -e +# +# 2018 Ander Punnar (ander-at-kvlt-dot-ee) +# +# 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 [ -e "/$__object_id" ] +then getfacl "/$__object_id" | grep -E '^((default:|)(user|group)):[a-z]' || true +fi diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote new file mode 100755 index 00000000..a9d14102 --- /dev/null +++ b/cdist/conf/type/__acl/gencode-remote @@ -0,0 +1,81 @@ +#!/bin/sh -e +# +# 2018 Ander Punnar (ander-at-kvlt-dot-ee) +# +# 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 . +# + +os="$( "$__explorer/os" )" + +acl_path="/$__object_id" + +acl_is="$( cat "$__object/explorer/acl_is" )" + +acl_should="$( for parameter in user group +do + if [ ! -f "$__object/parameter/$parameter" ] + then continue + fi + while read -r l + do + echo "$parameter:$l" + + if [ -f "$__object/parameter/default" ] + then echo "default:$parameter:$l" + fi + done < "$__object/parameter/$parameter" +done )" + +setfacl_exec='setfacl' + +if [ -f "$__object/parameter/recursive" ] +then + if echo "$os" | grep -E 'macosx|netbsd|freebsd|openbsd' + then + echo "$os setfacl do not support recursive operations" >&2 + else + setfacl_exec="$setfacl_exec -R" + fi +fi + +if [ -f "$__object/parameter/remove" ] +then + if echo "$os" | grep 'solaris' + then + # Solaris setfacl behaves differently. + # We will not support Solaris for now, because no way to test it. + # But adding support should be easy (use -s instead of -m on modify). + echo "$os setfacl do not support -x flag for ACL remove" >&2 + else + echo "$acl_is" | while read -r acl + do + if echo "$acl_should" | grep -Fq "$acl" + then continue + fi + + no_bits="$( echo "$acl" | sed -r 's/:[rwx-]+$//' )" + + echo "$setfacl_exec -x \"$no_bits\" \"$acl_path\"" + done + fi +fi + +for acl in $acl_should +do + if ! echo "$acl_is" | grep -Eq "^$acl" + then echo "$setfacl_exec -m \"$acl\" \"$acl_path\"" + fi +done diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst new file mode 100644 index 00000000..39db4d75 --- /dev/null +++ b/cdist/conf/type/__acl/man.rst @@ -0,0 +1,62 @@ +cdist-type__acl(7) +================== + +NAME +---- +cdist-type__acl - Basic wrapper around `setfacl` + + +DESCRIPTION +----------- +ACL must be defined as 3-symbol combination, using `r`, `w`, `x` and `-`. + +See setfacl(1) and acl(5) for more details. + + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- +user + Add user ACL entry. + +group + Add group ACL entry. + + +BOOLEAN PARAMETERS +------------------ +recursive + Operate recursively (Linux only). + +default + Add default ACL entries. + +remove + Remove undefined ACL entries (Solaris not supported). + + +EXAMPLES +-------- + +.. code-block:: sh + + __acl /srv/project \ + --recursive \ + --default \ + --remove \ + --user alice:rwx \ + --user bob:r-x \ + --group project-group:rwx \ + --group some-other-group:r-x + + +AUTHORS +------- +Ander Punnar + + +COPYING +------- +Copyright \(C) 2018 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/__acl/parameter/boolean b/cdist/conf/type/__acl/parameter/boolean new file mode 100644 index 00000000..8b96693f --- /dev/null +++ b/cdist/conf/type/__acl/parameter/boolean @@ -0,0 +1,3 @@ +recursive +default +remove diff --git a/cdist/conf/type/__acl/parameter/optional_multiple b/cdist/conf/type/__acl/parameter/optional_multiple new file mode 100644 index 00000000..22f5a52c --- /dev/null +++ b/cdist/conf/type/__acl/parameter/optional_multiple @@ -0,0 +1,2 @@ +user +group From d7a1645e4ed3f9bca0d687c51feb209b9dbabb49 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Mon, 11 Jun 2018 11:21:07 +0300 Subject: [PATCH 0832/1332] __acl: fix os explorer --- cdist/conf/type/__acl/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index a9d14102..a59d49e0 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -18,7 +18,7 @@ # along with cdist. If not, see . # -os="$( "$__explorer/os" )" +os="$( cat "$__global/explorer/os" )" acl_path="/$__object_id" From b9a48c931689afe009075fc3ddc0b9ab7fb34d10 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Jun 2018 06:20:02 +0200 Subject: [PATCH 0833/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 38411e14..241f4933 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * New type: __acl (Ander Punnar) + 4.9.1: 2018-05-30 * New type: __install_coreos (Ľubomír Kučera) * Type __consul_agent: Add LSB init header (Nico Schottelius) From 5aa8dac80a93b4158a713a7837f460042ecd11fe Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Jun 2018 07:53:52 +0200 Subject: [PATCH 0834/1332] Disable config parser interpolation --- cdist/configuration.py | 2 +- cdist/test/configuration/__init__.py | 66 ++++++++++++------- .../fixtures/interpolation-test.cfg | 2 + docs/changelog | 1 + 4 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 cdist/test/configuration/fixtures/interpolation-test.cfg diff --git a/cdist/configuration.py b/cdist/configuration.py index 848956aa..8df43f9f 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -382,7 +382,7 @@ class Configuration(metaclass=Singleton): return args def _read_config_file(self, files): - config_parser = configparser.ConfigParser() + config_parser = configparser.ConfigParser(interpolation=None) config_parser.read(files) d = dict() for section in config_parser.sections(): diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index e34c30b9..3319d320 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -31,6 +31,11 @@ import logging my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') +interpolation_config_file = op.join(fixtures, "interpolation-test.cfg") + + +def newConfigParser(): + return configparser.ConfigParser(interpolation=None) class ConfigurationOptionsTestCase(test.CdistTestCase): @@ -141,7 +146,7 @@ class ConfigurationTestCase(test.CdistTestCase): def setUp(self): # Create test config file. - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'off', 'local_shell': '/bin/sh', @@ -159,13 +164,13 @@ class ConfigurationTestCase(test.CdistTestCase): 'verbosity': 'INFO', 'archiving': 'none', } - config_custom = configparser.ConfigParser() + config_custom = newConfigParser() config_custom['GLOBAL'] = { 'parallel': '4', 'archiving': 'txz', } - config_custom2 = configparser.ConfigParser() + config_custom2 = newConfigParser() config_custom2['GLOBAL'] = { 'parallel': '16', 'archiving': 'tbz2', @@ -405,7 +410,7 @@ class ConfigurationTestCase(test.CdistTestCase): } args = argparse.Namespace() - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'off', 'local_shell': '/bin/sh', @@ -463,7 +468,7 @@ class ConfigurationTestCase(test.CdistTestCase): } args = argparse.Namespace() - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'off', 'local_shell': '/bin/sh', @@ -486,7 +491,7 @@ class ConfigurationTestCase(test.CdistTestCase): with open(global_config_file, 'w') as f: config.write(f) - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'on', 'local_shell': '/usr/bin/sh', @@ -544,7 +549,7 @@ class ConfigurationTestCase(test.CdistTestCase): } args = argparse.Namespace() - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'off', 'local_shell': '/bin/sh', @@ -611,7 +616,7 @@ class ConfigurationTestCase(test.CdistTestCase): } args = argparse.Namespace() - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'off', 'local_shell': '/bin/sh', @@ -634,7 +639,7 @@ class ConfigurationTestCase(test.CdistTestCase): with open(global_config_file, 'w') as f: config.write(f) - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'on', 'local_shell': '/usr/bin/sh', @@ -709,7 +714,7 @@ class ConfigurationTestCase(test.CdistTestCase): } args = argparse.Namespace() - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'off', 'local_shell': '/bin/sh', @@ -732,7 +737,7 @@ class ConfigurationTestCase(test.CdistTestCase): with open(global_config_file, 'w') as f: config.write(f) - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'on', 'local_shell': '/usr/bin/sh', @@ -800,7 +805,7 @@ class ConfigurationTestCase(test.CdistTestCase): } args = argparse.Namespace() - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'off', 'local_shell': '/bin/sh', @@ -823,7 +828,7 @@ class ConfigurationTestCase(test.CdistTestCase): with open(global_config_file, 'w') as f: config.write(f) - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'on', 'local_shell': '/usr/bin/sh', @@ -840,7 +845,7 @@ class ConfigurationTestCase(test.CdistTestCase): with open(local_config_file, 'w') as f: config.write(f) - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'conf_dir': '/opt/conf/cdist', 'remote_copy': 'scpcustom', @@ -899,7 +904,7 @@ class ConfigurationTestCase(test.CdistTestCase): } args = argparse.Namespace() - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'off', 'local_shell': '/bin/sh', @@ -922,7 +927,7 @@ class ConfigurationTestCase(test.CdistTestCase): with open(global_config_file, 'w') as f: config.write(f) - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'on', 'local_shell': '/usr/bin/sh', @@ -939,7 +944,7 @@ class ConfigurationTestCase(test.CdistTestCase): with open(local_config_file, 'w') as f: config.write(f) - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'conf_dir': '/opt/conf/cdist', 'remote_copy': 'scpcustom', @@ -998,7 +1003,7 @@ class ConfigurationTestCase(test.CdistTestCase): } args = argparse.Namespace() - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'off', 'local_shell': '/bin/sh', @@ -1021,7 +1026,7 @@ class ConfigurationTestCase(test.CdistTestCase): with open(global_config_file, 'w') as f: config.write(f) - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'beta': 'on', 'local_shell': '/usr/bin/sh', @@ -1038,7 +1043,7 @@ class ConfigurationTestCase(test.CdistTestCase): with open(local_config_file, 'w') as f: config.write(f) - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'conf_dir': '/opt/conf/cdist', 'remote_copy': 'scpcustom', @@ -1107,7 +1112,7 @@ class ConfigurationTestCase(test.CdistTestCase): self.assertEqual(dargs, expected_args) def test_configuration_empty_value_in_file(self): - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'inventory_dir': '', 'conf_dir': '', @@ -1169,7 +1174,7 @@ class ConfigurationTestCase(test.CdistTestCase): config_files=()) def test_configuration_disable_saving_output_streams1(self): - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'save_output_streams': 'True', } @@ -1197,7 +1202,7 @@ class ConfigurationTestCase(test.CdistTestCase): self.assertEqual(configuration.config, expected_config_dict) def test_configuration_disable_saving_output_streams2(self): - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'save_output_streams': 'False', } @@ -1225,7 +1230,7 @@ class ConfigurationTestCase(test.CdistTestCase): self.assertEqual(configuration.config, expected_config_dict) def test_configuration_disable_saving_output_streams3(self): - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'save_output_streams': 'False', } @@ -1253,7 +1258,7 @@ class ConfigurationTestCase(test.CdistTestCase): self.assertEqual(configuration.config, expected_config_dict) def test_configuration_disable_saving_output_streams4(self): - config = configparser.ConfigParser() + config = newConfigParser() config['GLOBAL'] = { 'save_output_streams': 'True', } @@ -1280,6 +1285,17 @@ class ConfigurationTestCase(test.CdistTestCase): config_files=config_files) self.assertEqual(configuration.config, expected_config_dict) + def test_read_config_file_with_interpolation(self): + try: + config = cc.Configuration(None, env={}, config_files=()) + d = config._read_config_file(interpolation_config_file) + val = d['GLOBAL']['cache_path_pattern'] + self.assertIsNotNone(val) + self.assertEqual(val, '%N') + except configparser.InterpolationSyntaxError as e: + self.fail("Exception should not have been raised: {}".format( + e)) + if __name__ == "__main__": import unittest diff --git a/cdist/test/configuration/fixtures/interpolation-test.cfg b/cdist/test/configuration/fixtures/interpolation-test.cfg new file mode 100644 index 00000000..df723121 --- /dev/null +++ b/cdist/test/configuration/fixtures/interpolation-test.cfg @@ -0,0 +1,2 @@ +[GLOBAL] +cache_path_pattern = %N diff --git a/docs/changelog b/docs/changelog index 241f4933..6a1e1318 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * New type: __acl (Ander Punnar) + * Core: Disable config parser interpolation (Darko Poljak) 4.9.1: 2018-05-30 * New type: __install_coreos (Ľubomír Kučera) From 9d4c0331a9fd4772162c8ff98cdcae91040c94ac Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Jun 2018 12:54:58 +0200 Subject: [PATCH 0835/1332] __sysctl: support sysctl.d --- cdist/conf/type/__sysctl/explorer/conf-path | 25 +++++++++++++++++++++ cdist/conf/type/__sysctl/manifest | 4 +++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100755 cdist/conf/type/__sysctl/explorer/conf-path diff --git a/cdist/conf/type/__sysctl/explorer/conf-path b/cdist/conf/type/__sysctl/explorer/conf-path new file mode 100755 index 00000000..ba35c4c6 --- /dev/null +++ b/cdist/conf/type/__sysctl/explorer/conf-path @@ -0,0 +1,25 @@ +#!/bin/sh +# +# 2018 Darko Poljak (darko.poljak 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 [ -d "/etc/sysctl.d" ]; then + echo "/etc/sysctl.d/99-Z-sysctl-cdist.conf"; +else + echo "/etc/sysctl.conf"; +fi diff --git a/cdist/conf/type/__sysctl/manifest b/cdist/conf/type/__sysctl/manifest index c903dbae..6e337ccb 100755 --- a/cdist/conf/type/__sysctl/manifest +++ b/cdist/conf/type/__sysctl/manifest @@ -32,8 +32,10 @@ case "$os" in ;; esac +conf_path=$(cat "$__object/explorer/conf-path") + __key_value "$__object_name" \ --key "$__object_id" \ - --file /etc/sysctl.conf \ + --file "${conf_path}" \ --value "$(cat "$__object/parameter/value")" \ --delimiter '=' From d49daca3dc9e3af09e42ea37dc38d561cf3d5743 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 16 Jun 2018 10:51:46 +0200 Subject: [PATCH 0836/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 6a1e1318..509d0c44 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,8 @@ Changelog next: * New type: __acl (Ander Punnar) * Core: Disable config parser interpolation (Darko Poljak) + * Type __sysctl: Use sysctl.d location if exists (Darko Poljak) + * Type __line: Rewrite and support --before and --after (Steven Armstrong) 4.9.1: 2018-05-30 * New type: __install_coreos (Ľubomír Kučera) From ee64936ff9f07a2129a6c809db0512aafd2d70bc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 17 Jun 2018 10:57:06 +0200 Subject: [PATCH 0837/1332] Release 4.10.0 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 509d0c44..0001b346 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.0: 2018-06-17 * New type: __acl (Ander Punnar) * Core: Disable config parser interpolation (Darko Poljak) * Type __sysctl: Use sysctl.d location if exists (Darko Poljak) From ec8f2f9488ef6dc7f6bc3ae282979555f544e82c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Jun 2018 08:29:41 +0200 Subject: [PATCH 0838/1332] Fix temp file location and removal --- cdist/conf/type/__letsencrypt_cert/gencode-remote | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__letsencrypt_cert/gencode-remote b/cdist/conf/type/__letsencrypt_cert/gencode-remote index 788da74c..375570a4 100755 --- a/cdist/conf/type/__letsencrypt_cert/gencode-remote +++ b/cdist/conf/type/__letsencrypt_cert/gencode-remote @@ -16,7 +16,7 @@ case "${state}" in ;; present) domain_param_file="${__object}/parameter/domain" - requested_domains=$(mktemp domain.cdist.XXXXXXXXXX) + requested_domains=$(mktemp "${TMPDIR:-/tmp}/domain.cdist.XXXXXXXXXX") if [ -f "${domain_param_file}" ]; then cp "${domain_param_file}" "${requested_domains}" else @@ -66,6 +66,7 @@ case "${state}" in echo "--domain '${domain}' \\" done < "${requested_domains}") EOF + rm -f "${requested_domains}" if [ "${certificate_exists}" = "no" ]; then echo create >> "${__messages_out}" From 41186d66d406a3eb411e6fc1e8aa4b68ffbd49a7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Jun 2018 09:23:12 +0200 Subject: [PATCH 0839/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 0001b346..b81c4939 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) + 4.10.0: 2018-06-17 * New type: __acl (Ander Punnar) * Core: Disable config parser interpolation (Darko Poljak) From 4eaace7dd5c427150cf99b07893bff7c1d072f8c Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Wed, 20 Jun 2018 11:14:25 +0200 Subject: [PATCH 0840/1332] Handle missing file in __line explorer gracefully closes #675 --- cdist/conf/type/__line/explorer/state | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cdist/conf/type/__line/explorer/state b/cdist/conf/type/__line/explorer/state index afdf3502..2ef252c8 100755 --- a/cdist/conf/type/__line/explorer/state +++ b/cdist/conf/type/__line/explorer/state @@ -39,6 +39,11 @@ else file="/$__object_id" fi +if [ ! -f "$file" ]; then + echo "file_missing" + exit 0 +fi + awk -v position="$position" -v needle="$needle" ' function _find(_text, _pattern) { if (needle == "regex") { From 58b0e83655895f5d92c7c4c63ba4b79651703ee6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Jun 2018 17:28:30 +0200 Subject: [PATCH 0841/1332] Add env vars usage idiom for writing types --- docs/src/cdist-type.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index a6587328..7c0dab8d 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -331,6 +331,19 @@ So when you generate a script with the following content, it will work: fi +Environment variable usage idiom +-------------------------------- +In type scripts you can support environment variables with default values if +environment variable is unset or null by using **${parameter:-[word]}** +parameter expansion. + +Example using mktemp in a portable way that supports TMPDIR environment variable. + +.. code-block:: sh + + tempfile=$(mktemp "${TMPDIR:-/tmp}/cdist.XXXXXXXXXX") + + Log level in types ------------------ cdist log level can be accessed from __cdist_log_level variable.One of: From 8350b6297ea2b03005d5b7beaaec64e02c8d4ff3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 20 Jun 2018 17:28:38 +0200 Subject: [PATCH 0842/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index b81c4939..3794221f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,8 @@ Changelog next: * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) + * Type __line: Handle missing file in __line explorer gracefully (Jonas Weber) + * Documentation: Add env vars usage idiom for writing types (Darko Poljak) 4.10.0: 2018-06-17 * New type: __acl (Ander Punnar) From 7eae68c11da10d294e181f099dd2c58fffc81be6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 21 Jun 2018 08:33:48 +0200 Subject: [PATCH 0843/1332] Release 4.10.1 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 3794221f..4453b6cb 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.1: 2018-06-21 * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) * Type __line: Handle missing file in __line explorer gracefully (Jonas Weber) * Documentation: Add env vars usage idiom for writing types (Darko Poljak) From 6c8014b407cf28ee54764ffc6182cb28a580dc66 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 22 Jun 2018 14:09:31 +0200 Subject: [PATCH 0844/1332] __letsencrypt_cert: add support for devuan ascii --- cdist/conf/type/__letsencrypt_cert/manifest | 11 +++++++++++ docs/changelog | 3 +++ 2 files changed, 14 insertions(+) diff --git a/cdist/conf/type/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest index 94e9d225..56e3532c 100755 --- a/cdist/conf/type/__letsencrypt_cert/manifest +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -56,6 +56,17 @@ if [ -z "${certbot_fullpath}" ]; then # Seems to be a missing dependency on debian 8 __package python-ndg-httpsclient ;; + ascii*) + __apt_source ascii-backports \ + --uri http://auto.mirror.devuan.org/merged \ + --distribution ascii-backports \ + --component main + + require="__apt_source/ascii-backports" __package_apt python-certbot \ + --target-release ascii-backports + require="__apt_source/ascii-backports" __package_apt certbot \ + --target-release ascii-backports + ;; *) echo "Unsupported OS version: $os_version" >&2 exit 1 diff --git a/docs/changelog b/docs/changelog index 4453b6cb..921e0c26 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) + 4.10.1: 2018-06-21 * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) * Type __line: Handle missing file in __line explorer gracefully (Jonas Weber) From 8d84834db6f2bf16474161cff358496d76923801 Mon Sep 17 00:00:00 2001 From: Adam Dej Date: Wed, 11 Jul 2018 15:53:23 +0200 Subject: [PATCH 0845/1332] __systemd_unit: manpage clarifications Clarify that this type only operates on units in /etc/systemd/system. Also, when state=present, it is not always true that the type is "installed, enabled and started" --- cdist/conf/type/__systemd_unit/man.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__systemd_unit/man.rst b/cdist/conf/type/__systemd_unit/man.rst index 88da6b30..5d68b253 100644 --- a/cdist/conf/type/__systemd_unit/man.rst +++ b/cdist/conf/type/__systemd_unit/man.rst @@ -9,9 +9,10 @@ cdist-type__systemd_unit - Install a systemd unit DESCRIPTION ----------- -This type can install, enable and start a systemd unit. This is particularly -useful on systems which take advantage of systemd heavily (e.g., CoreOS). For -more information about systemd units, see SYSTEMD.UNIT(5). +This type manages systemd units in ``/etc/systemd/system/``. It can install, +enable and start a systemd unit. This is particularly useful on systems which +take advantage of systemd heavily (e.g., CoreOS). For more information about +systemd units, see SYSTEMD.UNIT(5). REQUIRED PARAMETERS ------------------- @@ -37,7 +38,7 @@ state 'present' or 'absent', defaults to 'present' where: present - the unit is installed, enabled and started + the unit is installed absent the unit is stopped, disabled and uninstalled From 37b37f6e66d1d2d85b3eb2178787aec03221d2a6 Mon Sep 17 00:00:00 2001 From: Adam Dej Date: Wed, 11 Jul 2018 15:58:41 +0200 Subject: [PATCH 0846/1332] __systemd_unit: fix crash when transitioning to state=absent This type tried to disable an unit after it has removed it, which failed. Now the removal happens in gencode-remote, after the unit has been stopped and disabled. --- cdist/conf/type/__systemd_unit/gencode-remote | 2 ++ cdist/conf/type/__systemd_unit/manifest | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__systemd_unit/gencode-remote b/cdist/conf/type/__systemd_unit/gencode-remote index c608d9b3..9c64b6c4 100644 --- a/cdist/conf/type/__systemd_unit/gencode-remote +++ b/cdist/conf/type/__systemd_unit/gencode-remote @@ -25,6 +25,8 @@ current_enablement_state=$(cat "${__object}/explorer/enablement-state") if [ "${state}" = "absent" ]; then if [ ! -z "${current_enablement_state}" ]; then echo "systemctl --now disable ${name}" + echo "rm -f /etc/systemd/system/${name}" + echo "systemctl daemon-reload" fi exit 0 diff --git a/cdist/conf/type/__systemd_unit/manifest b/cdist/conf/type/__systemd_unit/manifest index 8b136605..7739c3d8 100644 --- a/cdist/conf/type/__systemd_unit/manifest +++ b/cdist/conf/type/__systemd_unit/manifest @@ -30,7 +30,9 @@ name="${__object_id}" source=$(cat "${__object}/parameter/source") state=$(cat "${__object}/parameter/state") -if [ -z "${source}" ] && [ "${state}" != "absent" ]; then +# The unit must be disabled before removing its unit file. The unit file is +# therefore removed by gencode-remote of this type, not here. +if [ -z "${source}" ] || [ "${state}" = "absent" ]; then exit 0 fi From 43982f821f6cae64a99673cf9541b5b0b0a940c1 Mon Sep 17 00:00:00 2001 From: Adam Dej Date: Wed, 11 Jul 2018 13:00:41 +0200 Subject: [PATCH 0847/1332] __systemd_unit: add support for masking units --- cdist/conf/type/__systemd_unit/gencode-remote | 17 ++++++++++++++--- cdist/conf/type/__systemd_unit/man.rst | 12 ++++++++---- cdist/conf/type/__systemd_unit/manifest | 12 +++++++++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/cdist/conf/type/__systemd_unit/gencode-remote b/cdist/conf/type/__systemd_unit/gencode-remote index 9c64b6c4..60486c52 100644 --- a/cdist/conf/type/__systemd_unit/gencode-remote +++ b/cdist/conf/type/__systemd_unit/gencode-remote @@ -33,16 +33,24 @@ if [ "${state}" = "absent" ]; then fi unit_status=$(cat "${__object}/explorer/unit-status") +desired_enablement_state=$(cat "${__object}/parameter/enablement-state") + +if [ "${current_enablement_state}" = "masked" ] && \ + [ "${desired_enablement_state}" != "masked" ]; then + echo "systemctl unmask ${name}" +fi if [ -f "${__object}/parameter/restart" ]; then - if grep -q "^__file/etc/systemd/system/${name}" "${__messages_in}" || \ + if [ "${desired_enablement_state}" = "masked" ]; then + if [ "${unit_status}" = "active" ]; then + echo "systemctl stop ${name}" + fi + elif grep -q "^__file/etc/systemd/system/${name}" "${__messages_in}" || \ [ "${unit_status}" != "active" ]; then echo "systemctl restart ${name} || true" fi fi -desired_enablement_state=$(cat "${__object}/parameter/enablement-state") - if [ "${current_enablement_state}" = "${desired_enablement_state}" ]; then exit 0 fi @@ -58,6 +66,9 @@ case "${desired_enablement_state}" in disabled) echo "systemctl disable ${name}" ;; + masked) + echo "systemctl mask ${name}" + ;; *) echo "Unsupported unit status: ${desired_enablement_state}" >&2 exit 1 diff --git a/cdist/conf/type/__systemd_unit/man.rst b/cdist/conf/type/__systemd_unit/man.rst index 5d68b253..25a4e501 100644 --- a/cdist/conf/type/__systemd_unit/man.rst +++ b/cdist/conf/type/__systemd_unit/man.rst @@ -23,12 +23,14 @@ OPTIONAL PARAMETERS ------------------- enablement-state - 'enabled' or 'disabled', where: + 'enabled', 'disabled' or 'masked', where: enabled enables the unit disabled disables the unit + masked + masks the unit source Path to the config file. If source is '-' (dash), take what was written to @@ -38,15 +40,17 @@ state 'present' or 'absent', defaults to 'present' where: present - the unit is installed + the unit (or its mask) is installed absent - the unit is stopped, disabled and uninstalled + The unit is stopped, disabled and uninstalled. If the unit was masked, + the mask is removed. BOOLEAN PARAMETERS ------------------ restart - Restart the unit on unit file change or when the unit is inactive. + Start the unit if it was inactive. Restart the unit if the unit file + changed. Stop the unit if new ``enablement-state`` is ``masked``. MESSAGES -------- diff --git a/cdist/conf/type/__systemd_unit/manifest b/cdist/conf/type/__systemd_unit/manifest index 7739c3d8..688a00b1 100644 --- a/cdist/conf/type/__systemd_unit/manifest +++ b/cdist/conf/type/__systemd_unit/manifest @@ -29,6 +29,7 @@ fi name="${__object_id}" source=$(cat "${__object}/parameter/source") state=$(cat "${__object}/parameter/state") +enablement_state=$(cat "${__object}/parameter/enablement-state") # The unit must be disabled before removing its unit file. The unit file is # therefore removed by gencode-remote of this type, not here. @@ -41,8 +42,17 @@ if [ "${source}" = "-" ]; then source="${__object}/stdin" fi +unitfile_state="${state}" +if [ "${enablement_state}" = "masked" ]; then + # Masking creates a symlink from /etc/systemd/system/ to /dev/null. + # This process fails with "Failed to execute operation: Invalid argument" + # if file /etc/systemd/system/ already exists. We must therefore + # remove it. + unitfile_state="absent" +fi + __config_file "/etc/systemd/system/${name}" \ --mode 644 \ --onchange "systemctl daemon-reload" \ --source "${source}" \ - --state "${state}" + --state "${unitfile_state}" From 1f2b7c84c2c56b69267321174971794da2d1b986 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 18 Jul 2018 07:40:34 +0200 Subject: [PATCH 0848/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 921e0c26..370c034b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) + * Type __systemd_unit: Fix minor issues and add masking unit files support (Adam Dej) 4.10.1: 2018-06-21 * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) From f04f76524c60b8de865079e24a6143a83b8e5d7b Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Sun, 22 Jul 2018 18:35:30 +0200 Subject: [PATCH 0849/1332] Bugfix: - __grafana_dashboard had the wrong release name for devuan ascii --- cdist/conf/type/__grafana_dashboard/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest index e62bd15f..308af59a 100755 --- a/cdist/conf/type/__grafana_dashboard/manifest +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -9,7 +9,7 @@ case $os in 8*|jessie) apt_source_distribution=jessie ;; - 9*|ascii/ceres) + 9*|ascii/ceres|ascii) apt_source_distribution=stretch ;; *) From eeb059015029208ec55131caf2e5f17c3bd0b738 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 23 Jul 2018 08:09:55 +0200 Subject: [PATCH 0850/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 370c034b..311d7a57 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) * Type __systemd_unit: Fix minor issues and add masking unit files support (Adam Dej) + * Type __grafana_dashboard: Fix devuan ascii support (Dominique Roux) 4.10.1: 2018-06-21 * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) From 2f89d8a514a5996a76ca5a34397b3d087e2fe5c2 Mon Sep 17 00:00:00 2001 From: Stu Zhao Date: Tue, 28 Aug 2018 23:27:13 -0700 Subject: [PATCH 0851/1332] Fix __package_update_index processing error exit 1 in explorer will abort cdist. --- cdist/conf/type/__package_update_index/explorer/currage | 1 - docs/changelog | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage index cd042bd5..e86e3f13 100644 --- a/cdist/conf/type/__package_update_index/explorer/currage +++ b/cdist/conf/type/__package_update_index/explorer/currage @@ -29,6 +29,5 @@ case "$os" in ;; *) echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 echo "Please contribute an implementation for it if you can." >&2 - exit 1 ;; esac diff --git a/docs/changelog b/docs/changelog index 311d7a57..12bdb1e0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) * Type __systemd_unit: Fix minor issues and add masking unit files support (Adam Dej) * Type __grafana_dashboard: Fix devuan ascii support (Dominique Roux) + * Type __package_update_index: Fix error when using OS not using apt (Stu Zhao) 4.10.1: 2018-06-21 * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) From b12c02138df4086e2e8e5e366e2156fa2ff95b3a Mon Sep 17 00:00:00 2001 From: Stu Zhao Date: Wed, 29 Aug 2018 00:07:19 -0700 Subject: [PATCH 0852/1332] Refactor __package_update_index explorers * add an type explorer to unify detecting of package type. * update currage use the type explorer, so if os and passed in type does not match, it behaves correctly. --- .../__package_update_index/explorer/currage | 8 ++--- .../type/__package_update_index/explorer/type | 34 +++++++++++++++++++ .../__package_update_index/gencode-remote | 18 +--------- 3 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 cdist/conf/type/__package_update_index/explorer/type diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage index e86e3f13..45653f91 100644 --- a/cdist/conf/type/__package_update_index/explorer/currage +++ b/cdist/conf/type/__package_update_index/explorer/currage @@ -17,17 +17,17 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . -os="$("$__explorer/os")" +type="$($__type_explorer/type)" -case "$os" in - debian|ubuntu|devuan) +case "$type" in + apt) if [ -f "/var/cache/apt/pkgcache.bin" ]; then echo $(($(date +"%s")-$(stat --format '%Y' /var/cache/apt/pkgcache.bin))) else echo 0 fi ;; - *) echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 + *) echo "Your specified type ($type) is currently not supported." >&2 echo "Please contribute an implementation for it if you can." >&2 ;; esac diff --git a/cdist/conf/type/__package_update_index/explorer/type b/cdist/conf/type/__package_update_index/explorer/type new file mode 100644 index 00000000..805b9f04 --- /dev/null +++ b/cdist/conf/type/__package_update_index/explorer/type @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 2018 Stu Zhao (z12y12l12 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/type" ]; then + cat "$__object/parameter/type" +else + # By default determine package manager based on operating system + os="$($__explorer/os)" + case "$os" in + amazon|scientific|centos|fedora|redhat) echo "yum" ;; + debian|ubuntu|devuan) echo "apt" ;; + archlinux) echo "pacman" ;; + *) + echo "Don't know how to manage packages on: $os" >&2 + exit 1 + ;; + esac +fi diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index 37bfe7ab..132a3daa 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -21,28 +21,12 @@ # Update the package index with the appropriate package manager # -type="$__object/parameter/type" +type=$(cat "$__object/explorer/type") if [ -f "$__object/parameter/maxage" ]; then maxage="$(cat "$__object/parameter/maxage")" currage="$(cat "$__object/explorer/currage")" fi -if [ -f "$type" ]; then - type="$(cat "$type")" -else - # By default determine package manager based on operating system - os="$(cat "$__global/explorer/os")" - case "$os" in - amazon|scientific|centos|fedora|redhat) type="yum" ;; - debian|ubuntu|devuan) type="apt" ;; - archlinux) type="pacman" ;; - *) - echo "Don't know how to manage packages on: $os" >&2 - exit 1 - ;; - esac -fi - if [ -n "$maxage" ] && [ "$type" != "apt" ]; then echo "ERROR: \"--maxage\" only supported for \"apt\" pkg-manager." >&2 exit 1 From f143a70463e0740937370faa9492daf5cba9a2fd Mon Sep 17 00:00:00 2001 From: Stu Zhao Date: Wed, 29 Aug 2018 00:30:27 -0700 Subject: [PATCH 0853/1332] Support pacman with --maxage parameter --- .../__package_update_index/explorer/currage | 7 ++++ .../__package_update_index/gencode-remote | 35 ++++++++++--------- .../conf/type/__package_update_index/man.rst | 6 ++-- docs/changelog | 1 + 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage index 45653f91..50474fb3 100644 --- a/cdist/conf/type/__package_update_index/explorer/currage +++ b/cdist/conf/type/__package_update_index/explorer/currage @@ -27,6 +27,13 @@ case "$type" in echo 0 fi ;; + pacman) + if [ -d "/var/lib/pacman/sync" ]; then + echo $(($(date +"%s")-$(stat --format '%Y' /var/lib/pacman/sync))) + else + echo 0 + fi + ;; *) echo "Your specified type ($type) is currently not supported." >&2 echo "Please contribute an implementation for it if you can." >&2 ;; diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index 132a3daa..2cc76b81 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -22,32 +22,33 @@ # type=$(cat "$__object/explorer/type") +currage="$(cat "$__object/explorer/currage")" if [ -f "$__object/parameter/maxage" ]; then maxage="$(cat "$__object/parameter/maxage")" - currage="$(cat "$__object/explorer/currage")" fi -if [ -n "$maxage" ] && [ "$type" != "apt" ]; then - echo "ERROR: \"--maxage\" only supported for \"apt\" pkg-manager." >&2 - exit 1 +if [ -n "$maxage" ]; then + if [ "$type" != "apt" -a "$type" != "pacman" ]; then + echo "ERROR: \"--maxage\" only supported for \"apt\" or \"pacman\" pkg-manager." >&2 + exit 1 + elif [ $currage -lt $maxage ]; then + exit 0 # no need to update + fi fi + case "$type" in yum) ;; - apt) if [ -n "$maxage" ]; then - ## check if we need to update: - if [ $currage -ge $maxage ]; then - echo "apt-get --quiet update" - echo "apt-cache updated (age was: $currage)" >> "$__messages_out" - fi - else - echo "apt-get --quiet update" - echo "apt-cache updated (age was: $currage)" >> "$__messages_out" - fi - ;; - pacman) echo "pacman --noprogressbar --sync --refresh" ;; + apt) + echo "apt-get --quiet update" + echo "apt-cache updated (age was: $currage)" >> "$__messages_out" + ;; + pacman) + echo "pacman --noprogressbar --sync --refresh" + echo "pacman package database synced (age was: $currage)" >> "$__messages_out" + ;; *) - echo "Don't know how to manage packages on: $os" >&2 + echo "Don't know how to manage packages for type: $type" >&2 exit 1 ;; esac diff --git a/cdist/conf/type/__package_update_index/man.rst b/cdist/conf/type/__package_update_index/man.rst index b63af654..3cd787b9 100644 --- a/cdist/conf/type/__package_update_index/man.rst +++ b/cdist/conf/type/__package_update_index/man.rst @@ -28,8 +28,8 @@ type * pacman for Arch Linux maxage - Available for package manager apt, max time in seconds since last update. - Repo update is skipped if maxage is not reached yet. + Available for package manager apt and pacman, max time in seconds since + last update. Repo update is skipped if maxage is not reached yet. MESSAGES -------- @@ -51,6 +51,7 @@ EXAMPLES # Only update every hour: __package_update_index --maxage 3600 --type apt + # same as above (on apt-type systems): __package_update_index --maxage 3600 @@ -58,6 +59,7 @@ AUTHORS ------- | Ricardo Catalinas Jiménez | Thomas Eckert +| Stu Zhao COPYING diff --git a/docs/changelog b/docs/changelog index 12bdb1e0..e989fb61 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Type __systemd_unit: Fix minor issues and add masking unit files support (Adam Dej) * Type __grafana_dashboard: Fix devuan ascii support (Dominique Roux) * Type __package_update_index: Fix error when using OS not using apt (Stu Zhao) + * Type __package_update_index: Support --maxage for type pacman (Stu Zhao) 4.10.1: 2018-06-21 * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) From 93d877f5bff4d12510146051af032bc92e062fd3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 30 Aug 2018 20:22:51 +0200 Subject: [PATCH 0854/1332] Add nonparallel marker for __apt_source type. --- cdist/conf/type/__apt_source/nonparallel | 0 docs/changelog | 1 + 2 files changed, 1 insertion(+) create mode 100644 cdist/conf/type/__apt_source/nonparallel diff --git a/cdist/conf/type/__apt_source/nonparallel b/cdist/conf/type/__apt_source/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/docs/changelog b/docs/changelog index 311d7a57..e7c59952 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) * Type __systemd_unit: Fix minor issues and add masking unit files support (Adam Dej) * Type __grafana_dashboard: Fix devuan ascii support (Dominique Roux) + * Type __apt_source: Add nonparallel marker (Darko Poljak) 4.10.1: 2018-06-21 * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) From 282647a88c3bbaf66db53f643796dd76976320a6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 31 Aug 2018 10:48:21 +0200 Subject: [PATCH 0855/1332] Fix changelog formatting. --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 23b0e352..7df1a38e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,7 +6,7 @@ next: * Type __systemd_unit: Fix minor issues and add masking unit files support (Adam Dej) * Type __grafana_dashboard: Fix devuan ascii support (Dominique Roux) * Type __apt_source: Add nonparallel marker (Darko Poljak) - * Type __package_update_index: Fix error when using OS not using apt (Stu Zhao) + * Type __package_update_index: Fix error when using OS not using apt (Stu Zhao) * Type __package_update_index: Support --maxage for type pacman (Stu Zhao) 4.10.1: 2018-06-21 From a627247908bdce5b393a6296b71b5300f5fa6b30 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 1 Sep 2018 10:38:16 +0200 Subject: [PATCH 0856/1332] Check if certbot exists before using it. Fixes #685. --- .../__letsencrypt_cert/explorer/certificate-domains | 8 ++++++-- .../__letsencrypt_cert/explorer/certificate-exists | 10 ++++++++-- .../__letsencrypt_cert/explorer/certificate-is-test | 12 +++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__letsencrypt_cert/explorer/certificate-domains b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-domains index 367fda93..db605b63 100755 --- a/cdist/conf/type/__letsencrypt_cert/explorer/certificate-domains +++ b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-domains @@ -1,4 +1,8 @@ #!/bin/sh -e -certbot certificates --cert-name "${__object_id:?}" | grep ' Domains: ' | \ - cut -d ' ' -f 6- | tr ' ' '\n' +certbot_path=$("${__type_explorer}/certbot-path") +if [ -n "${certbot_path}" ] +then + certbot certificates --cert-name "${__object_id:?}" | grep ' Domains: ' | \ + cut -d ' ' -f 6- | tr ' ' '\n' +fi diff --git a/cdist/conf/type/__letsencrypt_cert/explorer/certificate-exists b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-exists index d2ea35cc..4e6f44db 100755 --- a/cdist/conf/type/__letsencrypt_cert/explorer/certificate-exists +++ b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-exists @@ -1,7 +1,13 @@ #!/bin/sh -e -if certbot certificates | grep -q " Certificate Name: ${__object_id:?}$"; then - echo yes +certbot_path=$("${__type_explorer}/certbot-path") +if [ -n "${certbot_path}" ] +then + if certbot certificates | grep -q " Certificate Name: ${__object_id:?}$"; then + echo yes + else + echo no + fi else echo no fi diff --git a/cdist/conf/type/__letsencrypt_cert/explorer/certificate-is-test b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-is-test index 6d7b0ae9..9b445059 100755 --- a/cdist/conf/type/__letsencrypt_cert/explorer/certificate-is-test +++ b/cdist/conf/type/__letsencrypt_cert/explorer/certificate-is-test @@ -1,8 +1,14 @@ #!/bin/sh -e -if certbot certificates --cert-name "${__object_id:?}" | \ - grep -q 'INVALID: TEST_CERT'; then - echo yes +certbot_path=$("${__type_explorer}/certbot-path") +if [ -n "${certbot_path}" ] +then + if certbot certificates --cert-name "${__object_id:?}" | \ + grep -q 'INVALID: TEST_CERT'; then + echo yes + else + echo no + fi else echo no fi From b9ddbb1aa04dd2217db0603e6a201378a5e7b145 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 1 Sep 2018 23:30:53 +0200 Subject: [PATCH 0857/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 7df1a38e..8a188501 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Type __apt_source: Add nonparallel marker (Darko Poljak) * Type __package_update_index: Fix error when using OS not using apt (Stu Zhao) * Type __package_update_index: Support --maxage for type pacman (Stu Zhao) + * Type __letsencrypt_cert: Fix explorers: check that certbot exists before using it (Darko Poljak) 4.10.1: 2018-06-21 * Type __letsencrypt_cert: Fix temp file location and removal (Darko Poljak) From 3782656569547b775f3b310ff6a226e49c0a7581 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 4 Sep 2018 08:27:20 +0200 Subject: [PATCH 0858/1332] Report encoding errors nicely. --- cdist/__init__.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index b7602ff8..000a571c 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -100,17 +100,23 @@ class CdistEntityError(Error): for name, path in stdpaths: if name not in result: result[name] = [] - if os.path.exists(path) and os.path.getsize(path) > 0: - output = [] - label_begin = name + ":" + header_name - output.append(label_begin) - output.append('\n') - output.append('-' * len(label_begin)) - output.append('\n') - with open(path, 'r') as fd: - output.append(fd.read()) - output.append('\n') - result[name].append(''.join(output)) + try: + if os.path.exists(path) and os.path.getsize(path) > 0: + output = [] + label_begin = name + ":" + header_name + output.append(label_begin) + output.append('\n') + output.append('-' * len(label_begin)) + output.append('\n') + with open(path, 'r') as fd: + output.append(fd.read()) + output.append('\n') + result[name].append(''.join(output)) + except UnicodeError as ue: + result[name].append(('Cannot output {}:{} due to: {}.\n' + 'You can try to read the error file "{}"' + ' yourself.').format( + name, header_name, ue, path)) return result def _stderr(self): From 55dcaecafe53cbc54b89346e3ab37ae85a3d7c6d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 6 Sep 2018 07:11:04 +0200 Subject: [PATCH 0859/1332] Release 4.10.2 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 8a188501..c58e445b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.2: 2018-09-06 * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) * Type __systemd_unit: Fix minor issues and add masking unit files support (Adam Dej) * Type __grafana_dashboard: Fix devuan ascii support (Dominique Roux) From c2f8c7abb33ff971c30a00a29ef2c6f4016ebcca Mon Sep 17 00:00:00 2001 From: Adam Dej Date: Sat, 21 Jul 2018 14:52:50 +0200 Subject: [PATCH 0860/1332] Add explorer for info in /etc/os-release --- cdist/conf/explorer/os_release | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 cdist/conf/explorer/os_release diff --git a/cdist/conf/explorer/os_release b/cdist/conf/explorer/os_release new file mode 100644 index 00000000..cfc01004 --- /dev/null +++ b/cdist/conf/explorer/os_release @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2018 Adam Dej (dejko.a 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 . +# +# + +# See os-release(5) and http://0pointer.de/blog/projects/os-release + +set +e + +cat /etc/os-release || cat /usr/lib/os-release || true From 2e653409c132f9869e962dc05c905f2204d9f0b7 Mon Sep 17 00:00:00 2001 From: Adam Dej Date: Sat, 21 Jul 2018 14:53:53 +0200 Subject: [PATCH 0861/1332] Update __docker type - Update installation method, following official installation instructions. - docker-engine was renamed to Docker CE around March 2017. Update manpage to reflect that change. - Remove flag `--experimental` since it is no longer necessary to install a different binary to get experimental features. Experimental features are included in the stable binary and can be enabled by a flag or in a config file. --- cdist/conf/type/__docker/man.rst | 16 ++---- cdist/conf/type/__docker/manifest | 66 ++++++++-------------- cdist/conf/type/__docker/parameter/boolean | 1 - 3 files changed, 28 insertions(+), 55 deletions(-) delete mode 100644 cdist/conf/type/__docker/parameter/boolean diff --git a/cdist/conf/type/__docker/man.rst b/cdist/conf/type/__docker/man.rst index 70b92cc7..5cb28ee1 100644 --- a/cdist/conf/type/__docker/man.rst +++ b/cdist/conf/type/__docker/man.rst @@ -3,12 +3,12 @@ cdist-type__docker(7) NAME ---- -cdist-type__docker - install docker-engine +cdist-type__docker - install Docker CE DESCRIPTION ----------- -Installs latest docker-engine package from dockerproject.org. +Installs latest Docker Community Edition package. REQUIRED PARAMETERS @@ -18,16 +18,13 @@ None. OPTIONAL PARAMETERS ------------------- -None. +state + 'present' or 'absent', defaults to 'present' BOOLEAN PARAMETERS ------------------ -experimental - Install the experimental docker-engine package instead of the latest stable release. - -state - 'present' or 'absent', defaults to 'present' +None. EXAMPLES @@ -38,9 +35,6 @@ EXAMPLES # Install docker __docker - # Install experimental - __docker --experimental - # Remove docker __docker --state absent diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index 1b1b1fb7..d501a9f1 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -24,57 +24,37 @@ state=$(cat "$__object/parameter/state") case "$os" in centos) - component="main" - if [ -f "$__object/parameter/experimental" ]; then - component="experimental" + if (source "$__global/explorer/os_release" && [ "${VERSION_ID}" = "7" ]); then + __yum_repo docker-ce-stable \ + --name 'Docker CE Stable' \ + --baseurl "https://download.docker.com/linux/centos/7/\$basearch/stable" \ + --enabled \ + --gpgcheck 1 \ + --gpgkey 'https://download.docker.com/linux/centos/gpg' \ + --state ${state} + require="__yum_repo/docker-ce-stable" __package docker-ce --state ${state} + else + echo "CentOS version 7 is required!" >&2 + exit 1 fi - __yum_repo docker \ - --name 'Docker Repository' \ - --baseurl "https://yum.dockerproject.org/repo/$component/centos/\$releasever/" \ - --enabled \ - --gpgcheck 1 \ - --gpgkey 'https://yum.dockerproject.org/gpg' \ - --state ${state} - require="__yum_repo/docker" __package docker-engine --state ${state} ;; - ubuntu) - component="main" - if [ -f "$__object/parameter/experimental" ]; then - component="experimental" + ubuntu|debian) + if [ "${state}" = "present" ]; then + __package apt-transport-https + __package ca-certificates + __package gnupg2 fi - __package apparmor --state ${state} - __package ca-certificates --state ${state} - __package apt-transport-https --state ${state} - __apt_key docker --keyid 58118E89F3A912897C070ADBF76221572C52609D --state ${state} + __apt_key_uri docker --name "Docker Release (CE deb) " \ + --uri "https://download.docker.com/linux/${os}/gpg" --state ${state} export CDIST_ORDER_DEPENDENCY=on __apt_source docker \ - --uri https://apt.dockerproject.org/repo \ - --distribution "ubuntu-$(cat "$__global/explorer/lsb_codename")" \ + --uri "https://download.docker.com/linux/${os}" \ + --distribution "$(cat "$__global/explorer/lsb_codename")" \ --state ${state} \ - --component "$component" - __package docker-engine --state ${state} + --component "stable" + __package docker-ce --state ${state} unset CDIST_ORDER_DEPENDENCY ;; - debian) - component="main" - if [ -f "$__object/parameter/experimental" ]; then - component="experimental" - fi - - __package apt-transport-https --state ${state} - __package ca-certificates --state ${state} - __package gnupg2 --state ${state} - __apt_key docker --keyid 58118E89F3A912897C070ADBF76221572C52609D --state ${state} - export CDIST_ORDER_DEPENDENCY=on - __apt_source docker \ - --uri https://apt.dockerproject.org/repo \ - --distribution "debian-$(cat "$__global/explorer/lsb_codename")" \ - --state ${state} \ - --component "$component" - __package docker-engine --state ${state} - unset CDIST_ORDER_DEPENDENCY - - ;; *) echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 echo "Please contribute an implementation for it if you can." >&2 diff --git a/cdist/conf/type/__docker/parameter/boolean b/cdist/conf/type/__docker/parameter/boolean deleted file mode 100644 index 9839eb20..00000000 --- a/cdist/conf/type/__docker/parameter/boolean +++ /dev/null @@ -1 +0,0 @@ -experimental From 19a55ac75a9c555033b8c46e5987baee52dac685 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 9 Sep 2018 19:27:39 +0200 Subject: [PATCH 0862/1332] ++changelog --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index c58e445b..6c4a69a9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,10 @@ Changelog --------- +next: + * New global explorer: os_release (Ľubomír Kučera) + * Type __docker: Update type, install docker CE (Ľubomír Kučera) + 4.10.2: 2018-09-06 * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) * Type __systemd_unit: Fix minor issues and add masking unit files support (Adam Dej) From 346f1f8af34de7a6a8fd21dc521211d31b2f33c0 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Wed, 12 Sep 2018 11:36:06 +0200 Subject: [PATCH 0863/1332] Send messages when installing packages via __package_apt --- cdist/conf/type/__package_apt/gencode-remote | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index d9cc52b7..39584e30 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -78,9 +78,11 @@ case "$state_should" in name="${name}=${version}" fi echo $aptget install $target_release \"$name\" + echo "installed" >> "$__messages_out" ;; absent) echo $aptget remove $purgeparam \"$name\" + echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 From b3f3b907a49759db18f95ed48b7890328a755e96 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Wed, 12 Sep 2018 11:35:23 +0200 Subject: [PATCH 0864/1332] Quote aptget command and params, simplify explorer --- cdist/conf/type/__package_apt/explorer/state | 2 +- cdist/conf/type/__package_apt/gencode-remote | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__package_apt/explorer/state b/cdist/conf/type/__package_apt/explorer/state index 658429ac..7ccd6fce 100755 --- a/cdist/conf/type/__package_apt/explorer/state +++ b/cdist/conf/type/__package_apt/explorer/state @@ -30,7 +30,7 @@ fi # Except dpkg failing, if package is not known / installed packages="$(apt-cache showpkg "$name" | sed -e "1,/Reverse Provides:/d" | cut -d ' ' -f 1) $name" for p in $packages; do - if [ -n "$(dpkg -s "$p" 2>/dev/null | grep "^Status: install ok installed$")" ]; then + if dpkg -s "$p" 2>/dev/null | grep --quiet "^Status: install ok installed$" ; then version=$(dpkg -s "$p" 2>/dev/null | grep "^Version:" | cut -d ' ' -f 2) echo "present $p $version" exit 0 diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index 39584e30..cbe14787 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -77,11 +77,11 @@ case "$state_should" in if [ -n "$version" ]; then name="${name}=${version}" fi - echo $aptget install $target_release \"$name\" + echo "$aptget install $target_release \"$name\"" echo "installed" >> "$__messages_out" ;; absent) - echo $aptget remove $purgeparam \"$name\" + echo "$aptget remove $purgeparam \"$name\"" echo "removed" >> "$__messages_out" ;; *) From aa80e8f87deaf4348296306ae26504fe19dbdd03 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 12 Sep 2018 11:53:46 +0200 Subject: [PATCH 0865/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 6c4a69a9..682544ff 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * New global explorer: os_release (Ľubomír Kučera) * Type __docker: Update type, install docker CE (Ľubomír Kučera) + * Type __package_apt: Write a message when a package is installed or removed; shellcheck (Jonas Weber) 4.10.2: 2018-09-06 * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) From d6952543a74e523a248342452cd4ecd4df81116b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 6 Sep 2018 07:06:25 +0200 Subject: [PATCH 0866/1332] Add 'real world example' walkthrough docs chapter. --- docs/changelog | 1 + docs/src/cdist-real-world.rst | 573 ++++++++++++++++++++++++++++++++++ docs/src/index.rst | 1 + 3 files changed, 575 insertions(+) create mode 100644 docs/src/cdist-real-world.rst diff --git a/docs/changelog b/docs/changelog index 682544ff..62d44fbe 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * New global explorer: os_release (Ľubomír Kučera) * Type __docker: Update type, install docker CE (Ľubomír Kučera) * Type __package_apt: Write a message when a package is installed or removed; shellcheck (Jonas Weber) + * Documentation: Add 'Dive into real world cdist' walkthrough chapter (Darko Poljak) 4.10.2: 2018-09-06 * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) diff --git a/docs/src/cdist-real-world.rst b/docs/src/cdist-real-world.rst new file mode 100644 index 00000000..8ccb0fc9 --- /dev/null +++ b/docs/src/cdist-real-world.rst @@ -0,0 +1,573 @@ +Dive into real world cdist +========================== + +Introduction +------------ + +This walkthrough shows real world cdist configuration example. + +Sample target host is named **test.ungleich.ch**. +Just replace **test.ungleich.ch** with your target hostname. + +Our goal is to configure python application hosting. For writing sample +application we will use `Bottle `_ WSGI micro web-framework. +It will use PostgreSQL database and it will list items from **items** table. +It will be served by uWSGI server. We will also use the Nginx web server +as a reverse proxy and we want HTTPS. +For HTTPS we will use Let's Encrypt certificate. + +For setting up hosting we want to use cdist so we will write a new type +for that. This type will: + +- install required packages +- create OS user, user home directory and application home directory +- create PostgreSQL database +- configure uWSGI +- configure Let's Encrypt certificate +- configure nginx. + +Our type will not create the actual python application. Its intention is only +to configure hosing for specified user and project. It is up to the user to +create his/her applications. + +So let's start. + +Creating type layout +-------------------- + +We will create a new custom type. Let's call it **__sample_bottle_hosting**. + +Go to **~/.cdist/type** directory (create it if it does not exist) and create +new type layout:: + + cd ~/.cdist/type + mkdir __sample_bottle_hosting + cd __sample_bottle_hosting + touch manifest gencode-remote + mkdir parameter + touch parameter/required + +Creating __sample_bottle_hosting type parameters +------------------------------------------------ + +Our type will be configurable through the means of parameters. Let's define +the following parameters: + +projectname + name for the project, needed for uWSGI ini file + +user + user name + +domain + target host domain, needed for Let's Encrypt certificate. + +We define parameters to make our type reusable for different projects, user and domain. + +Define required parameters:: + + printf "projectname\n" >> parameter/required + printf "user\n" >> parameter/required + printf "domain\n" >> parameter/required + +For details on type parameters see `Defining parameters `_. + +Creating __sample_bottle_hosting type manifest +---------------------------------------------- + +Next step is to define manifest (~/.cdist/type/__sample_bottle_hosting/manifest). +We also want our type to currently support only Devuan. So we will start by +checking target host OS. We will use `os `_ +global explorer:: + + os=$(cat "$__global/explorer/os") + + case "$os" in + devuan) + : + ;; + *) + echo "OS $os currently not supported" >&2 + exit 1 + ;; + esac + +If target host OS is not Devuan then we print error message to stderr +and exit. For other OS-es support we should check and change package names +we should install, because packages differ in different OS-es and in different +OS distributions like GNU/Linux distributions. There can also be a different +configuration locations (e.g. nginx config directory could be in /usr/local tree). +If we detected unsupported OS we should error out. cdist will stop configuration +process and output error message. + +Creating user and user directories +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Then we create user and his/her home directory and application home directory. +We will use existing cdist types `__user `_ and `__directory `_:: + + user="$(cat "$__object/parameter/user")" + home="/home/$user" + apphome="$home/app" + + # create user + __user "$user" --home "$home" --shell /bin/bash + # create user home dir + require="__user/$user" __directory "$home" \ + --owner "$user" --group "$user" --mode 0755 + # create app home dir + require="__user/$user __directory/$home" __directory "$apphome" \ + --state present --owner "$user" --group "$user" --mode 0755 + +First we define *user*, *home* and *apphome* variables. User is defined by type's +**user** parameter. Here we use **require** which is cdist's way to define dependencies. +User home directory should be created **after** user is created. And application +home directory is created **after** both user and user home directory are created. +For details on **require** see `Dependencies `_. + +Installing packages +~~~~~~~~~~~~~~~~~~~ + +Install required packages using existing `__package `_ type. +Before installing package we want to update apt package index using +`__apt_update_index `_:: + + # define packages that need to be installed + packages_to_install="nginx uwsgi-plugin-python3 python3-dev python3-pip postgresql postgresql-contrib libpq-dev python3-venv uwsgi python3-psycopg2" + + # update package index + __apt_update_index + # install packages + for package in $packages_to_install + do require="__apt_update_index" __package $package --state=present + done + +Here we use shell for loop. It executes **require="__apt_update_index" __package** +for each member in a list we define in **packages_to_install** variable. +This is much nicer then having as many **require="__apt_update_index" __package** +lines as there are packages we want to install. + +For python packages we use `__package_pip `_:: + + # install pip3 packages + for package in bottle bottle-pgsql; do + __package_pip --pip pip3 $package + done + +Creating PostgreSQL database +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create PostgreSQL database using `__postgres_database `_ +and `__postgres_role `_ for creating database user:: + + #PostgreSQL db & user + postgres_server=postgresql + + # create PostgreSQL db user + require="__package/postgresql" __postgres_role $user --login --createdb + # create PostgreSQL db + require="__postgres_role/$user __package/postgresql" __postgres_database $user \ + --owner $user + +Configuring uWSGI +~~~~~~~~~~~~~~~~~ + +Configure uWSGI using `__file `_ type:: + + # configure uWSGI + projectname="$(cat "$__object/parameter/projectname")" + require="__package/uwsgi" __file /etc/uwsgi/apps-enabled/$user.ini \ + --owner root --group root --mode 0644 \ + --state present \ + --source - << EOF + [uwsgi] + socket = $apphome/uwsgi.sock + chdir = $apphome + wsgi-file = $projectname/wsgi.py + touch-reload = $projectname/wsgi.py + processes = 4 + threads = 2 + chmod-socket = 666 + daemonize=true + vacuum = true + uid = $user + gid = $user + EOF + +We require package uWSGI present in order to create **/etc/uwsgi/apps-enabled/$user.ini** file. +Installation of uWSGI also creates configuration layout: **/etc/uwsgi/apps-enabled**. +If this directory does not exist then **__file** type would error. +We also use stdin as file content source. For details see `Input from stdin `_. +For feading stdin we use here-document (**<<** operator). It allows redirection of subsequent +lines read by the shell to the input of a command until a line containing only the delimiter +and a newline, with no blank characters in between (EOF in our case). + +Configuring nginx for Let's Encrypt and HTTPS redirection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Next configure nginx for Let's Encrypt and for HTTP -> HTTPS redirection. For this +purpose we will create new type **__sample_nginx_http_letsencrypt_and_ssl_redirect** +and use it here:: + + domain="$(cat "$__object/parameter/domain")" + webroot="/var/www/html" + __sample_nginx_http_letsencrypt_and_ssl_redirect "$domain" --webroot "$webroot" + +Configuring certificate creation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After HTTP nginx configuration we will create Let's Encrypt certificate using +`__letsencrypt_cert `_ type. +For Let's Encrypt cert configuration ensure that there is a DNS entry for your +domain. We assure that cert creation is applied after nginx HTTP is configured +for Let's Encrypt to work:: + + # create SSL cert + require="__package/nginx __sample_nginx_http_letsencrypt_and_ssl_redirect/$domain" \ + __letsencrypt_cert --admin-email admin@test.ungleich.ch \ + --webroot "$webroot" \ + --automatic-renewal \ + --renew-hook "service nginx reload" \ + --domain "$domain" \ + "$domain" + +Configuring nginx HTTPS server with uWSGI upstream +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Then we can configure nginx HTTPS server that will use created Let's Encrypt certificate:: + + # configure nginx + require="__package/nginx __letsencrypt_cert/$domain" \ + __file "/etc/nginx/sites-enabled/https-$domain" \ + --source - --mode 0644 << EOF + upstream _bottle { + server unix:$apphome/uwsgi.sock; + } + + server { + listen 443; + listen [::]:443; + + server_name $domain; + + access_log /var/log/nginx/access.log; + + ssl on; + ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem; + + client_max_body_size 256m; + + location / { + try_files \$uri @uwsgi; + } + + location @uwsgi { + include uwsgi_params; + uwsgi_pass _bottle; + } + } + EOF + +Now our manifest is finished. + +Complete __sample_bottle_hosting type manifest listing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Here is complete __sample_bottle_hosting type manifest listing, +located in ~/.cdist/type/__sample_bottle_hosting/manifest:: + + #!/bin/sh + + os=$(cat "$__global/explorer/os") + + case "$os" in + devuan) + : + ;; + *) + echo "OS $os currently not supported" >&2 + exit 1 + ;; + esac + + projectname="$(cat "$__object/parameter/projectname")" + user="$(cat "$__object/parameter/user")" + home="/home/$user" + apphome="$home/app" + domain="$(cat "$__object/parameter/domain")" + + # create user + __user "$user" --home "$home" --shell /bin/bash + # create user home dir + require="__user/$user" __directory "$home" \ + --owner "$user" --group "$user" --mode 0755 + # create app home dir + require="__user/$user __directory/$home" __directory "$apphome" \ + --state present --owner "$user" --group "$user" --mode 0755 + + # define packages that need to be installed + packages_to_install="nginx uwsgi-plugin-python3 python3-dev python3-pip postgresql postgresql-contrib libpq-dev python3-venv uwsgi python3-psycopg2" + + # update package index + __apt_update_index + # install packages + for package in $packages_to_install + do require="__apt_update_index" __package $package --state=present + done + # install pip3 packages + for package in bottle bottle-pgsql; do + __package_pip --pip pip3 $package + done + + #PostgreSQL db & user + postgres_server=postgresql + + # create PostgreSQL db user + require="__package/postgresql" __postgres_role $user --login --createdb + # create PostgreSQL db + require="__postgres_role/$user __package/postgresql" __postgres_database $user \ + --owner $user + # configure uWSGI + require="__package/uwsgi" __file /etc/uwsgi/apps-enabled/$user.ini \ + --owner root --group root --mode 0644 \ + --state present \ + --source - << EOF + [uwsgi] + socket = $apphome/uwsgi.sock + chdir = $apphome + wsgi-file = $projectname/wsgi.py + touch-reload = $projectname/wsgi.py + processes = 4 + threads = 2 + chmod-socket = 666 + daemonize=true + vacuum = true + uid = $user + gid = $user + EOF + + # setup nginx HTTP for Let's Encrypt and SSL redirect + domain="$(cat "$__object/parameter/domain")" + webroot="/var/www/html" + __sample_nginx_http_letsencrypt_and_ssl_redirect "$domain" --webroot "$webroot" + + # create SSL cert + require="__package/nginx __sample_nginx_http_letsencrypt_and_ssl_redirect/$domain" \ + __letsencrypt_cert --admin-email admin@test.ungleich.ch \ + --webroot "$webroot" \ + --automatic-renewal \ + --renew-hook "service nginx reload" \ + --domain "$domain" \ + "$domain" + + # configure nginx + require="__package/nginx __letsencrypt_cert/$domain" \ + __file "/etc/nginx/sites-enabled/https-$domain" \ + --source - --mode 0644 << EOF + upstream _bottle { + server unix:$apphome/uwsgi.sock; + } + + server { + listen 443; + listen [::]:443; + + server_name $domain; + + access_log /var/log/nginx/access.log; + + ssl on; + ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem; + + client_max_body_size 256m; + + location / { + try_files \$uri @uwsgi; + } + + location @uwsgi { + include uwsgi_params; + uwsgi_pass _bottle; + } + } + EOF + +Creating __sample_bottle_hosting type gencode-remote +---------------------------------------------------- + +Now define **gencode-remote** script: ~/.cdist/type/__sample_bottle_hosting/gencode-remote. +After manifest is applied it should restart uWSGI and nginx services so that our +configuration is active. Our gencode-remote looks like the following:: + + echo "service uwsgi restart" + echo "service nginx restart" + +Our **__sample_bottle_hosting** type is now finished. + +Creating __sample_nginx_http_letsencrypt_and_ssl_redirect type +-------------------------------------------------------------- + +Let's now create **__sample_nginx_http_letsencrypt_and_ssl_redirect** type:: + + cd ~/.cdist/type + mkdir __sample_nginx_http_letsencrypt_and_ssl_redirect + cd __sample_nginx_http_letsencrypt_and_ssl_redirect + mkdir parameter + echo webroot > parameter/required + touch manifest + touch gencode-remote + +Edit manifest:: + + domain="$__object_id" + webroot="$(cat "$__object/parameter/webroot")" + # make sure we have nginx package + __package nginx + # setup Let's Encrypt HTTP acme challenge, redirect HTTP to HTTPS + require="__package/nginx" __file "/etc/nginx/sites-enabled/http-$domain" \ + --source - --mode 0644 << EOF + server { + listen *:80; + listen [::]:80; + + server_name $domain; + + # Let's Encrypt + location /.well-known/acme-challenge/ { + root $webroot; + } + + # Everything else -> SSL + location / { + return 301 https://\$host\$request_uri; + } + } + + EOF + +Edit gencode-remote:: + + echo "service nginx reload" + +Creating init manifest +---------------------- + +Next create init manifest:: + + cd ~/.cdist/manifest + printf "__sample_bottle_hosting --projectname sample --user app --domain \$__target_host sample\n" > sample + +Using this init manifest our target host will be configured using our **__sample_bottle_hosting** +type with projectname *sample*, user *app* and domain equal to **__target_host**. +Here the last positional argument *sample* is type's object id. For details on +**__target_host** and **__object_id** see +`Environment variables (for reading) `_ +reference. + +Configuring host +---------------- + +Finally configure test.ungleich.ch:: + + cdist config -v -i ~/.cdist/manifest/sample test.ungleich.ch + +After cdist configuration is successfully finished our host is ready. + +Creating python bottle application +---------------------------------- + +We now need to create Bottle application. As you remember from the beginning +of this walkthrough our type does not create the actual python application, +its intention is only to configure hosing for specified user and project. +It is up to the user to create his/her applications. + +Become app user:: + + su -l app + +Preparing database +~~~~~~~~~~~~~~~~~~ + +We need to prepare database for our application. Create table and +insert some items:: + + psql -c "create table items (item varchar(255));" + + psql -c "insert into items(item) values('spam');" + psql -c "insert into items(item) values('eggs');" + psql -c "insert into items(item) values('sausage');" + +Creating application +~~~~~~~~~~~~~~~~~~~~ + +Next create sample app:: + + cd /home/app/app + mkdir sample + cd sample + +Create app.py with the following content:: + + #!/usr/bin/env python3 + + import bottle + import bottle_pgsql + + app = application = bottle.Bottle() + plugin = bottle_pgsql.Plugin('dbname=app user=app password=') + app.install(plugin) + + @app.route('/') + def show_index(db): + db.execute('select * from items') + items = db.fetchall() or [] + rv = '

Items:

' + return rv + + if __name__ == '__main__': + bottle.run(app=app, host='0.0.0.0', port=8080) + +Create wsgi.py with the following content:: + + import os + + os.chdir(os.path.dirname(__file__)) + + import app + application = app.app + +We have configured uWSGI with **touch-reload = $projectname/wsgi.py** so after +we have changed our **wsgi.py** file uWSGI reloads the application. + +Our application selects and lists items from **items** table. + +Openning application +~~~~~~~~~~~~~~~~~~~~ + +Finally try the application:: + + http://test.ungleich.ch/ + +It should redirect to HTTPS and return: + +.. container:: highlight + + .. raw:: html + +

Items:

+ +
    +
  • spam
  • +
  • eggs
  • +
  • sausage
  • +
+ +What's next? +------------ + +Continue reading next sections ;) diff --git a/docs/src/index.rst b/docs/src/index.rst index 5d0bb537..bef91e1c 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -16,6 +16,7 @@ Contents: cdist-support cdist-features cdist-quickstart + cdist-real-world man1/cdist cdist-bootstrap cdist-configuration From f918acd725f911aa71afc14af5bf38d9c44fa6cc Mon Sep 17 00:00:00 2001 From: dhivael Date: Fri, 21 Sep 2018 22:54:37 +0200 Subject: [PATCH 0867/1332] don't duplicate Remote::mkdir in explorer transfer Remote::transfer contains a call to mkdir(destination) if the source is a directory. since the destination must also be a directory we can omit extra mkdir calls in Explorer. this saves about 10% on my manifests in sequential mode, and about 6% in parallel mode. --- cdist/core/explorer.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 8c18a19f..a42b0117 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -147,7 +147,6 @@ class Explorer(object): def transfer_global_explorers(self): """Transfer the global explorers to the remote side.""" - self.remote.mkdir(self.remote.global_explorer_path) self.remote.transfer(self.local.global_explorer_path, self.remote.global_explorer_path, self.jobs) @@ -223,7 +222,6 @@ class Explorer(object): cdist_type.explorer_path) destination = os.path.join(self.remote.type_path, cdist_type.explorer_path) - self.remote.mkdir(destination) self.remote.transfer(source, destination) self.remote.run(["chmod", "0700", "%s/*" % (destination)]) self._type_explorers_transferred.append(cdist_type.name) @@ -235,5 +233,4 @@ class Explorer(object): cdist_object.parameter_path) destination = os.path.join(self.remote.object_path, cdist_object.parameter_path) - self.remote.mkdir(destination) self.remote.transfer(source, destination) From c021cd15cdac8d7a474107531df71dd211c1c6d4 Mon Sep 17 00:00:00 2001 From: dhivael Date: Fri, 21 Sep 2018 23:17:41 +0200 Subject: [PATCH 0868/1332] transfer all files of a directory at once instead of calling the copy command once per file in a directory (eg a type explorer dir), call the copy command only once with all files of the directory. batch copy saves 20% of dry-run time on my test manifest in sequential mode, and 15% in parallel mode. --- cdist/exec/remote.py | 40 +++++++--------------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 4466545e..ffb3ee00 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -203,46 +203,20 @@ class Remote(object): os.remove(tarpath) used_archiving = True if not used_archiving: - if jobs: - self._transfer_dir_parallel(source, destination, jobs) - else: - self._transfer_dir_sequential(source, destination) + self._transfer_dir(source, destination) elif jobs: raise cdist.Error("Source {} is not a directory".format(source)) else: self._transfer_file(source, destination) - def _transfer_dir_commands(self, source, destination): + def _transfer_dir(self, source, destination): + command = self._copy.split() for f in glob.glob1(source, '*'): - command = self._copy.split() path = os.path.join(source, f) - command.extend([path, '{0}:{1}'.format( - _wrap_addr(self.target_host[0]), destination)]) - yield command - - def _transfer_dir_sequential(self, source, destination): - for command in self._transfer_dir_commands(source, destination): - self._run_command(command) - - def _transfer_dir_parallel(self, source, destination, jobs): - """Transfer a directory to the remote side in parallel mode.""" - self.log.debug("Remote transfer in {} parallel jobs".format( - jobs)) - self.log.trace("Multiprocessing start method is {}".format( - multiprocessing.get_start_method())) - self.log.trace(("Starting multiprocessing Pool for parallel " - "remote transfer")) - args = [ - (command, ) - for command in self._transfer_dir_commands(source, destination) - ] - if len(args) == 1: - self.log.debug("Only one dir entry, transfering sequentially") - self._run_command(args[0]) - else: - mp_pool_run(self._run_command, args, jobs=jobs) - self.log.trace(("Multiprocessing for parallel transfer " - "finished")) + command.extend([path]) + command.extend(['{0}:{1}'.format( + _wrap_addr(self.target_host[0]), destination)]) + self._run_command(command) def run_script(self, script, env=None, return_output=False, stdout=None, stderr=None): From 1f703ab42ef4a1bc1730577c213cef5f980e921d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 22 Sep 2018 20:52:43 +0200 Subject: [PATCH 0869/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 62d44fbe..d25c4462 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Type __docker: Update type, install docker CE (Ľubomír Kučera) * Type __package_apt: Write a message when a package is installed or removed; shellcheck (Jonas Weber) * Documentation: Add 'Dive into real world cdist' walkthrough chapter (Darko Poljak) + * Core: Remove duplicate remote mkdir calls in explorer transfer (myeisha) 4.10.2: 2018-09-06 * Type __letsencrypt_cert: Add support for devuan ascii (Darko Poljak) From 02982ca8bee500a0d0cdf1975074953278f4109e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 23 Sep 2018 12:04:57 +0200 Subject: [PATCH 0870/1332] Release 4.10.3 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index d25c4462..8c310a22 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) * Type __docker: Update type, install docker CE (Ľubomír Kučera) * Type __package_apt: Write a message when a package is installed or removed; shellcheck (Jonas Weber) From 6acf6f64dcf6a5768be6f2874a719b16b5ba6a4f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 23 Sep 2018 20:34:42 +0200 Subject: [PATCH 0871/1332] Add timestamp to log messages. --- cdist/argparse.py | 5 +++++ cdist/config.py | 8 +++++++- cdist/log.py | 28 ++++++++++++++++++++++++++++ docs/src/man1/cdist.rst | 10 ++++++++-- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 29620751..0ee9d7b1 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -251,6 +251,11 @@ def get_parsers(): 'line). If no host or host file is specified then, by ' 'default, read hosts from stdin.'), dest='hostfile', required=False) + parser['config_args'].add_argument( + '-P', '--timestamp', + help=('Timestamp log messages with the current local date and time ' + 'in the format: YYYYMMDDHHMMSS.us.'), + action='store_true', dest='timestamp') parser['config_args'].add_argument( '-p', '--parallel', nargs='?', metavar='HOST_MAX', type=functools.partial(check_lower_bounded_int, lower_bound=1, diff --git a/cdist/config.py b/cdist/config.py index 2dcb1005..bfb89419 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -175,7 +175,13 @@ class Config(object): if args.parallel or args.jobs: # If parallel execution then also log process id - cdist.log.setupParallelLogging() + if args.timestamp: + cdist.log.setupTimestampingParallelLogging() + else: + cdist.log.setupParallelLogging() + log = logging.getLogger("cdist") + elif args.timestamp: + cdist.log.setupTimestampingLogging() log = logging.getLogger("cdist") if args.parallel: diff --git a/cdist/log.py b/cdist/log.py index dba1ad2f..5d431130 100644 --- a/cdist/log.py +++ b/cdist/log.py @@ -22,6 +22,7 @@ import logging import sys +import datetime # Define additional cdist logging levels. @@ -95,15 +96,42 @@ class DefaultLog(logging.Logger): self.log(logging.TRACE, msg, *args, **kwargs) +class TimestampingLog(DefaultLog): + + def filter(self, record): + """Add timestamp to messages""" + + super().filter(record) + now = datetime.datetime.now() + timestamp = now.strftime("%Y%m%d%H%M%S.%f") + record.msg = "[" + timestamp + "] " + str(record.msg) + + return True + + class ParallelLog(DefaultLog): FORMAT = '%(levelname)s: [%(process)d]: %(message)s' +class TimestampingParallelLog(TimestampingLog, ParallelLog): + pass + + def setupDefaultLogging(): del logging.getLogger().handlers[:] logging.setLoggerClass(DefaultLog) +def setupTimestampingLogging(): + del logging.getLogger().handlers[:] + logging.setLoggerClass(TimestampingLog) + + +def setupTimestampingParallelLogging(): + del logging.getLogger().handlers[:] + logging.setLoggerClass(TimestampingParallelLog) + + def setupParallelLogging(): del logging.getLogger().handlers[:] logging.setLoggerClass(ParallelLog) diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 79683883..0a628660 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -20,7 +20,8 @@ SYNOPSIS [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-4] [-6] - [-A] [-a] [-f HOSTFILE] [-p [HOST_MAX]] [-S] [-s] [-t] + [-A] [-a] [-f HOSTFILE] [-P] [-p [HOST_MAX]] [-S] [-s] + [-t] [host [host ...]] cdist install [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] @@ -28,7 +29,8 @@ SYNOPSIS [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-4] [-6] - [-A] [-a] [-f HOSTFILE] [-p [HOST_MAX]] [-S] [-s] [-t] + [-A] [-a] [-f HOSTFILE] [-P] [-p [HOST_MAX]] [-S] [-s] + [-t] [host [host ...]] cdist inventory [-h] {add-host,add-tag,del-host,del-tag,list} ... @@ -171,6 +173,10 @@ Install command is currently in beta. **-o OUT_PATH, --out-dir OUT_PATH** Directory to save cdist output in. +**-P, --timestamp** + Timestamp log messages with the current local date and time + in the format: YYYYMMDDHHMMSS.us. + **-p [HOST_MAX], --parallel [HOST_MAX]** Operate on multiple hosts in parallel for specified maximum hosts at a time. Without argument CPU count is From 0c57b3083ec4f43ff6fc56345a3007cfbd4dc3f6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 23 Sep 2018 21:38:03 +0200 Subject: [PATCH 0872/1332] Fix getting loggers. --- cdist/config.py | 21 ++++++++------------- cdist/core/cdist_type.py | 2 +- scripts/cdist | 3 +-- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index bfb89419..e8fd5384 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -165,25 +165,20 @@ class Config(object): def commandline(cls, args): """Configure remote system""" - # FIXME: Refactor relict - remove later - log = logging.getLogger("cdist") + if (args.parallel and args.parallel != 1) or args.jobs: + if args.timestamp: + cdist.log.setupTimestampingParallelLogging() + else: + cdist.log.setupParallelLogging() + elif args.timestamp: + cdist.log.setupTimestampingLogging() + log = logging.getLogger("config") # No new child process if only one host at a time. if args.parallel == 1: log.debug("Only 1 parallel process, doing it sequentially") args.parallel = 0 - if args.parallel or args.jobs: - # If parallel execution then also log process id - if args.timestamp: - cdist.log.setupTimestampingParallelLogging() - else: - cdist.log.setupParallelLogging() - log = logging.getLogger("cdist") - elif args.timestamp: - cdist.log.setupTimestampingLogging() - log = logging.getLogger("cdist") - if args.parallel: import signal diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 40194f94..99e40e70 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -47,7 +47,7 @@ class CdistType(object): """ - log = logging.getLogger("cdist") + log = logging.getLogger("cdist-type") def __init__(self, base_path, name): self.base_path = base_path diff --git a/scripts/cdist b/scripts/cdist index 088e4dc2..3110e657 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -69,8 +69,6 @@ if __name__ == "__main__": import re import os - log = logging.getLogger("cdist") - if re.match("__", os.path.basename(sys.argv[0])): import cdist.emulator emulator = cdist.emulator.Emulator(sys.argv) @@ -82,6 +80,7 @@ if __name__ == "__main__": exit_code = 2 except cdist.Error as e: + log = logging.getLogger("cdist") log.error(e) exit_code = 1 From c04325fdc5e2fb96aa7d3fbb26a06f13ec7e75ce Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 23 Sep 2018 22:26:16 +0200 Subject: [PATCH 0873/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 8c310a22..6d2ef147 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) + 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) * Type __docker: Update type, install docker CE (Ľubomír Kučera) From e404ff4836f91956d7367363bf6217d3af623b3d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 26 Sep 2018 20:35:32 +0200 Subject: [PATCH 0874/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 6d2ef147..8fd2ea49 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) + * Core: Add timestamp (optional) to log messages (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 82077aff251c9d13e1aac4608ba7bf0a58ea5712 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 27 Sep 2018 18:55:33 +0200 Subject: [PATCH 0875/1332] Add timestamping log option to config file. --- cdist/configuration.py | 2 + cdist/test/configuration/__init__.py | 112 +++++++++++++++++++++++++++ docs/src/cdist-configuration.rst | 4 + docs/src/man1/cdist.rst | 4 + 4 files changed, 122 insertions(+) diff --git a/cdist/configuration.py b/cdist/configuration.py index 8df43f9f..f05a5963 100644 --- a/cdist/configuration.py +++ b/cdist/configuration.py @@ -261,6 +261,7 @@ _ARG_OPTION_MAPPING = { 'verbose': 'verbosity', 'use_archiving': 'archiving', 'save_output_streams': 'save_output_streams', + 'timestamp': 'timestamp', } @@ -304,6 +305,7 @@ class Configuration(metaclass=Singleton): 'archiving': ArchivingOption(), 'save_output_streams': BooleanOption('save_output_streams', default_overrides=False), + 'timestamp': BooleanOption('timestamp'), }, } diff --git a/cdist/test/configuration/__init__.py b/cdist/test/configuration/__init__.py index 3319d320..182868a6 100644 --- a/cdist/test/configuration/__init__.py +++ b/cdist/test/configuration/__init__.py @@ -1296,6 +1296,118 @@ class ConfigurationTestCase(test.CdistTestCase): self.fail("Exception should not have been raised: {}".format( e)) + def test_configuration_timestamping_log_1(self): + config = newConfigParser() + config['GLOBAL'] = { + 'timestamp': 'True', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'timestamp': True, + 'verbosity': 0, + }, + } + + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + args = argparse.Namespace() + args.timestamp = True + configuration = cc.Configuration(args, env=None, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration_timestamping_log_2(self): + config = newConfigParser() + config['GLOBAL'] = { + 'timestamp': 'False', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'timestamp': True, + 'verbosity': 0, + }, + } + + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + args = argparse.Namespace() + args.timestamp = True + configuration = cc.Configuration(args, env=None, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration_timestamping_log_3(self): + config = newConfigParser() + config['GLOBAL'] = { + 'timestamp': 'False', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'timestamp': False, + 'verbosity': 0, + }, + } + + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + args = argparse.Namespace() + args.timestamp = False + configuration = cc.Configuration(args, env=None, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + + def test_configuration_timestamping_log_4(self): + config = newConfigParser() + config['GLOBAL'] = { + 'timestamp': 'True', + } + + global_config_file = os.path.join(fixtures, 'cdist-global.cfg') + with open(global_config_file, 'w') as f: + config.write(f) + + expected_config_dict = { + 'GLOBAL': { + 'timestamp': False, + 'verbosity': 0, + }, + } + + config_files = (global_config_file, ) + + # bypass singleton so we can test further + cc.Configuration.instance = None + + args = argparse.Namespace() + args.timestamp = False + configuration = cc.Configuration(args, env=None, + config_files=config_files) + self.assertEqual(configuration.config, expected_config_dict) + if __name__ == "__main__": import unittest diff --git a/docs/src/cdist-configuration.rst b/docs/src/cdist-configuration.rst index cf1e373b..4c9b4d33 100644 --- a/docs/src/cdist-configuration.rst +++ b/docs/src/cdist-configuration.rst @@ -94,6 +94,10 @@ The possible keywords and their meanings are as follows: It recognizes boolean values from 'yes'/'no', 'on'/'off', 'true'/'false' and '1'/'0'. +:strong:`timestamp` + Timestamp log messages with the current local date and time + in the format: YYYYMMDDHHMMSS.us. + :strong:`verbosity` Set verbosity level. Valid values are: 'ERROR', 'WARNING', 'INFO', 'VERBOSE', 'DEBUG', 'TRACE' and 'OFF'. diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 0a628660..3a74f1ef 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -521,6 +521,10 @@ The possible keywords and their meanings are as follows: It recognizes boolean values from 'yes'/'no', 'on'/'off', 'true'/'false' and '1'/'0'. +:strong:`timestamp` + Timestamp log messages with the current local date and time + in the format: YYYYMMDDHHMMSS.us. + :strong:`verbosity` Set verbosity level. Valid values are: 'ERROR', 'WARNING', 'INFO', 'VERBOSE', 'DEBUG', 'TRACE' and 'OFF'. From 9cb9771e3347a7ab5830021822c04121130bfb29 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 29 Sep 2018 11:15:20 +0200 Subject: [PATCH 0876/1332] Exclude man7 empty directory from archive. --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 76eac516..aeaab8b9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,4 @@ .gitkeep export-ignore docs/speeches export-ignore docs/video export-ignore +docs/src/man7 export-ignore From e551348cd74be0c6506af183fa242021567b2849 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 29 Sep 2018 11:15:48 +0200 Subject: [PATCH 0877/1332] Create man7 directory if needed. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index d727bccc..3a1819be 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,7 @@ MANTYPES=$(subst /man.rst,.rst,$(MANTYPEPREFIX)) # Link manpage: do not create man.html but correct named file $(MAN7DSTDIR)/cdist-type%.rst: $(TYPEDIR)/%/man.rst + mkdir -p $(MAN7DSTDIR) ln -sf "../../../$^" $@ # Manpages #2: reference From 6326eae1bb724a2ecb8eb45099472f93c9852cbf Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Mon, 1 Oct 2018 22:13:24 +0200 Subject: [PATCH 0878/1332] Fix SC2166 on all manfest/gencode/explorers --- cdist/conf/type/__ccollect_source/gencode-remote | 2 +- cdist/conf/type/__consul_agent/manifest | 2 +- cdist/conf/type/__consul_check/manifest | 2 +- cdist/conf/type/__consul_service/manifest | 6 +++--- cdist/conf/type/__consul_template_template/manifest | 4 ++-- cdist/conf/type/__consul_watch_checks/manifest | 2 +- cdist/conf/type/__file/gencode-local | 6 +++--- cdist/conf/type/__file/gencode-remote | 2 +- cdist/conf/type/__git/gencode-remote | 12 ++++++------ cdist/conf/type/__hostname/gencode-remote | 4 ++-- .../__install_partition_msdos_apply/gencode-remote | 2 +- cdist/conf/type/__jail_freebsd10/gencode-remote | 4 ++-- cdist/conf/type/__jail_freebsd9/gencode-remote | 4 ++-- cdist/conf/type/__key_value/manifest | 2 +- cdist/conf/type/__line/gencode-remote | 2 +- cdist/conf/type/__link/gencode-remote | 2 +- cdist/conf/type/__package/manifest | 2 +- cdist/conf/type/__package_emerge/gencode-remote | 4 ++-- cdist/conf/type/__package_pkg_freebsd/gencode-remote | 2 +- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 2 +- .../conf/type/__package_update_index/gencode-remote | 2 +- cdist/conf/type/__pyvenv/gencode-remote | 12 ++++++------ cdist/conf/type/__ssh_authorized_keys/manifest | 2 +- 23 files changed, 42 insertions(+), 42 deletions(-) diff --git a/cdist/conf/type/__ccollect_source/gencode-remote b/cdist/conf/type/__ccollect_source/gencode-remote index 56003fef..763f219e 100755 --- a/cdist/conf/type/__ccollect_source/gencode-remote +++ b/cdist/conf/type/__ccollect_source/gencode-remote @@ -71,7 +71,7 @@ case "$state_should" in fi value_is="$(get_current_value "$attribute" "$value_should")" - if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then + if [ -f "$__object/files/set-attributes" ] || [ "$value_should" != "$value_is" ]; then "set_$attribute" "$value_should" fi fi diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index 820018c9..a696894b 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -66,7 +66,7 @@ require="__directory/etc/consul" \ __directory "$conf_dir" \ --owner root --group "$group" --mode 750 --state "$state" -if [ -f "$__object/parameter/ca-file-source" -o -f "$__object/parameter/cert-file-source" -o -f "$__object/parameter/key-file-source" ]; then +if [ -f "$__object/parameter/ca-file-source" ] || [ -f "$__object/parameter/cert-file-source" ] || [ -f "$__object/parameter/key-file-source" ]; then # create directory for ssl certs require="__directory/etc/consul" \ __directory /etc/consul/ssl \ diff --git a/cdist/conf/type/__consul_check/manifest b/cdist/conf/type/__consul_check/manifest index 8149b130..554c0680 100755 --- a/cdist/conf/type/__consul_check/manifest +++ b/cdist/conf/type/__consul_check/manifest @@ -40,7 +40,7 @@ if [ ! -f "$__object/parameter/interval" ]; then fi done fi -if [ -f "$__object/parameter/docker-container-id" -a ! -f "$__object/parameter/script" ]; then +if [ -f "$__object/parameter/docker-container-id" ] && [ ! -f "$__object/parameter/script" ]; then echo "When using --docker-container-id you must also define --script." >&2 exit 1 fi diff --git a/cdist/conf/type/__consul_service/manifest b/cdist/conf/type/__consul_service/manifest index d7a1b6e3..f6d29b4a 100755 --- a/cdist/conf/type/__consul_service/manifest +++ b/cdist/conf/type/__consul_service/manifest @@ -24,15 +24,15 @@ conf_file="service_${name}.json" state="$(cat "$__object/parameter/state")" # Sanity checks -if [ -f "$__object/parameter/check-script" -a -f "$__object/parameter/check-ttl" ]; then +if [ -f "$__object/parameter/check-script" ] && [ -f "$__object/parameter/check-ttl" ]; then echo "Use either --check-script together with --check-interval OR --check-ttl, but not both" >&2 exit 1 fi -if [ -f "$__object/parameter/check-script" -a ! -f "$__object/parameter/check-interval" ]; then +if [ -f "$__object/parameter/check-script" ] && [ ! -f "$__object/parameter/check-interval" ]; then echo "When using --check-script you must also define --check-interval" >&2 exit 1 fi -if [ -f "$__object/parameter/check-http" -a ! -f "$__object/parameter/check-interval" ]; then +if [ -f "$__object/parameter/check-http" ] && [ ! -f "$__object/parameter/check-interval" ]; then echo "When using --check-http you must also define --check-interval" >&2 exit 1 fi diff --git a/cdist/conf/type/__consul_template_template/manifest b/cdist/conf/type/__consul_template_template/manifest index 5fe657d0..488a0f5d 100755 --- a/cdist/conf/type/__consul_template_template/manifest +++ b/cdist/conf/type/__consul_template_template/manifest @@ -26,11 +26,11 @@ template_dir="/etc/consul-template/template" require="" # Sanity checks -if [ -f "$__object/parameter/source" -a -f "$__object/parameter/source-file" ]; then +if [ -f "$__object/parameter/source" ] && [ -f "$__object/parameter/source-file" ]; then echo "Use either --source OR --source-file, but not both." >&2 exit 1 fi -if [ ! -f "$__object/parameter/source" -a ! -f "$__object/parameter/source-file" ]; then +if [ ! -f "$__object/parameter/source" ] && [ ! -f "$__object/parameter/source-file" ]; then echo "Either --source OR --source-file must be given." >&2 exit 1 fi diff --git a/cdist/conf/type/__consul_watch_checks/manifest b/cdist/conf/type/__consul_watch_checks/manifest index ebb49e2e..146f609e 100755 --- a/cdist/conf/type/__consul_watch_checks/manifest +++ b/cdist/conf/type/__consul_watch_checks/manifest @@ -25,7 +25,7 @@ conf_file="watch_${watch_type}_${__object_id}.json" state="$(cat "$__object/parameter/state")" # Sanity checks -if [ -f "$__object/parameter/filter-service" -a -f "$__object/parameter/filter-state" ]; then +if [ -f "$__object/parameter/filter-service" ] && [ -f "$__object/parameter/filter-state" ]; then echo "Use either --filter-service or --filter-state but not both." >&2 exit 1 fi diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 15a9ee0e..3f60b4b3 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -23,7 +23,7 @@ destination="/$__object_id" state_should="$(cat "$__object/parameter/state")" type="$(cat "$__object/explorer/type")" -[ "$state_should" = "exists" -a "$type" = "file" ] && exit 0 # nothing to do +[ "$state_should" = "exists" ] && [ "$type" = "file" ] && exit 0 # nothing to do if [ "$state_should" = "pre-exists" ]; then if [ -f "$__object/parameter/source" ]; then @@ -41,7 +41,7 @@ fi upload_file= create_file= -if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then +if [ "$state_should" = "present" ] || [ "$state_should" = "exists" ]; then if [ ! -f "$__object/parameter/source" ]; then remote_stat="$(cat "$__object/explorer/stat")" if [ -z "$remote_stat" ]; then @@ -70,7 +70,7 @@ if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then fi fi fi - if [ "$create_file" -o "$upload_file" ]; then + if [ "$create_file" ] || [ "$upload_file" ]; then # tell gencode-remote that we created or uploaded a file and that it must # set all attributes no matter what the explorer retreived mkdir "$__object/files" diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index c90be0be..9dfd1833 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -72,7 +72,7 @@ case "$state_should" in fi value_is="$(get_current_value "$attribute" "$value_should")" - if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then + if [ -f "$__object/files/set-attributes" ] || [ "$value_should" != "$value_is" ]; then "set_$attribute" "$value_should" fi fi diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote index d0d0d4ed..5a9e23fc 100755 --- a/cdist/conf/type/__git/gencode-remote +++ b/cdist/conf/type/__git/gencode-remote @@ -35,10 +35,10 @@ owner="$(cat "$__object/parameter/owner")" group="$(cat "$__object/parameter/group")" mode="$(cat "$__object/parameter/mode")" -[ "$state_should" = "$state_is" -a \ - "$owner" = "$owner_is" -a \ - "$group" = "$group_is" -a \ - -n "$mode" ] && exit 0 +[ "$state_should" = "$state_is" ] && \ +[ "$owner" = "$owner_is" ] && \ +[ "$group" = "$group_is" ] && \ +[ -n "$mode" ] && exit 0 case $state_should in present) @@ -46,8 +46,8 @@ case $state_should in if [ "$state_should" != "$state_is" ]; then echo git clone --quiet --branch "$branch" "$source" "$destination" fi - if [ \( -n "$owner" -a "$owner_is" != "$owner" \) -o \ - \( -n "$group" -a "$group_is" != "$group" \) ]; then + if { [ -n "$owner" ] && [ "$owner_is" != "$owner" ]; } || \ + { [ -n "$group" ] && [ "$group_is" != "$group" ]; }; then echo chown -R "${owner}:${group}" "$destination" fi if [ -n "$mode" ]; then diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 89bf7b3f..3f784188 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -36,12 +36,12 @@ has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") # case "$os" in archlinux|debian|suse|ubuntu|devuan|coreos) - if [ "$name_config" = "$name_should" -a "$name_running" = "$name_should" ]; then + if [ "$name_config" = "$name_should" ] && [ "$name_running" = "$name_should" ]; then exit 0 fi ;; scientific|centos|freebsd|openbsd) - if [ "$name_sysconfig" = "$name_should" -a "$name_running" = "$name_should" ]; then + if [ "$name_sysconfig" = "$name_should" ] && [ "$name_running" = "$name_should" ]; then exit 0 fi ;; diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index 090a5d86..bed40ffa 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -127,7 +127,7 @@ for object in $objects; do if [ "${minor}" -lt "5" ]; then # Primary partitions available_device_size=$available_size - if [ "$type" = "extended" -o "$type" = "5" ]; then + if [ "$type" = "extended" ] || [ "$type" = "5" ]; then # Extended partition available_extended_size=$partition_size fi diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index 76241e0e..d8bc5eb7 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -36,7 +36,7 @@ state="$(cat "$__object/parameter/state")" started="true" # If the user wants the jail gone, it implies it shouldn't be started. -[ -f "$__object/parameter/stopped" -o "$state" = "absent" ] && started="false" +{ [ -f "$__object/parameter/stopped" ] || [ "$state" = "absent" ]; } && started="false" if [ -f "$__object/parameter/ip" ]; then ip="$(cat "$__object/parameter/ip")" @@ -66,7 +66,7 @@ devfsruleset="$(cat "$__object/parameter/devfs-ruleset")" # devfs_ruleset being defined without devfs_enable being true # is pointless. Treat this as an error. -if [ -n "$devfsruleset" -a "$devfsenable" = "false" ]; then +if [ -n "$devfsruleset" ] && [ "$devfsenable" = "false" ]; then exec >&2 echo "Can't have --devfs-ruleset defined with --devfs-disable" exit 1 diff --git a/cdist/conf/type/__jail_freebsd9/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote index 63b48e5c..d883dec4 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -36,7 +36,7 @@ state="$(cat "$__object/parameter/state")" started="true" # If the user wants the jail gone, it implies it shouldn't be started. -[ -f "$__object/parameter/stopped" -o "$state" = "absent" ] && started="false" +{ [ -f "$__object/parameter/stopped" ] || [ "$state" = "absent" ]; } && started="false" if [ -f "$__object/parameter/ip" ]; then ip="$(cat "$__object/parameter/ip")" @@ -70,7 +70,7 @@ devfsruleset="$(cat "$__object/parameter/devfs-ruleset")" # devfs_ruleset being defined without devfs_enable being true # is pointless. Treat this as an error. -if [ -n "$devfsruleset" -a "$devfsenable" = "false" ]; then +if [ -n "$devfsruleset" ] && [ "$devfsenable" = "false" ]; then exec >&2 echo "Can't have --devfs-ruleset defined with --devfs-disable" exit 1 diff --git a/cdist/conf/type/__key_value/manifest b/cdist/conf/type/__key_value/manifest index c7801c89..5a91f60c 100755 --- a/cdist/conf/type/__key_value/manifest +++ b/cdist/conf/type/__key_value/manifest @@ -21,7 +21,7 @@ state_should="$(cat "$__object/parameter/state")" -if [ "$state_should" = "present" -a ! -f "$__object/parameter/value" ]; then +if [ "$state_should" = "present" ] && [ ! -f "$__object/parameter/value" ]; then echo "Missing required parameter 'value'" >&2 exit 1 fi diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index 996029f5..044ebe90 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -18,7 +18,7 @@ # along with cdist. If not, see . # -if [ -f "$__object/parameter/before" -a -f "$__object/parameter/after" ]; then +if [ -f "$__object/parameter/before" ] && [ -f "$__object/parameter/after" ]; then echo "Use either --before OR --after but not both." >&2 exit 1 fi diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index 4467fb8e..dc7f3193 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -61,7 +61,7 @@ case "$state_should" in ;; absent) # only delete if it is a sym/hard link - if [ "$file_type" = "symlink" -o "$file_type" = "hardlink" ]; then + if [ "$file_type" = "symlink" ] || [ "$file_type" = "hardlink" ]; then printf 'rm -f "%s"\n' "$destination" fi ;; diff --git a/cdist/conf/type/__package/manifest b/cdist/conf/type/__package/manifest index fe7abedc..3ab0f546 100755 --- a/cdist/conf/type/__package/manifest +++ b/cdist/conf/type/__package/manifest @@ -56,7 +56,7 @@ state="$(cat "$__object/parameter/state")" set -- "$@" "$__object_id" "--state" "$state" cd "$__object/parameter" for property in $(ls .); do - if [ "$property" != "type" -a "$property" != "state" ]; then + if [ "$property" != "type" ] && [ "$property" != "state" ]; then set -- "$@" "--$property" "$(cat "$property")" fi done diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote index 6abe2d61..ada2b414 100755 --- a/cdist/conf/type/__package_emerge/gencode-remote +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -38,11 +38,11 @@ fi pkg_version="$(cat "$__object/explorer/pkg_version")" if [ -z "$pkg_version" ]; then state_is="absent" -elif [ -z "$version" -a $(echo "$pkg_version" | wc -l) -gt 1 ]; then +elif [ -z "$version" ] && [ $(echo "$pkg_version" | wc -l) -gt 1 ]; then echo "Package name is not unique! The following packages are installed:" echo "$pkg_version" exit 1 -elif [ -n "$version" -a $(echo "$pkg_version" | cut -d " " -f 1 | sort | uniq | wc -l) -gt 1 ]; then +elif [ -n "$version" ] && [ $(echo "$pkg_version" | cut -d " " -f 1 | sort | uniq | wc -l) -gt 1 ]; then echo "Package name is not unique! The following packages are installed:" echo "$pkg_version" exit 1 diff --git a/cdist/conf/type/__package_pkg_freebsd/gencode-remote b/cdist/conf/type/__package_pkg_freebsd/gencode-remote index b51c3153..012bf2ad 100755 --- a/cdist/conf/type/__package_pkg_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_freebsd/gencode-remote @@ -66,7 +66,7 @@ cmd="" # FIXME: This is ugly. execcmd(){ # Set the PACKAGESITE if we're ADDing a new package - if [ "$1" = "add" -a -n "$pkgsite" ]; then + if [ "$1" = "add" ] && [ -n "$pkgsite" ]; then # Use http.../All/ if we know the exact version we want, use .../Latest/ otherwise pkgsite="export PACKAGESITE=${pkgsite}" [ -n "$version" ] && pkgsite="${pkgsite}/All/" || pkgsite="${pkgsite}/Latest/" diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 4a6763cd..61383edb 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -46,7 +46,7 @@ else name="$__object_id" fi -if [ -n "$version" -a -n "$flavor" ]; then +if [ -n "$version" ] && [ -n "$flavor" ]; then pkgid="$name-$version-$flavor" elif [ -n "$version" ]; then pkgid="$name-$version" diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index 2cc76b81..8589c6d1 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -28,7 +28,7 @@ if [ -f "$__object/parameter/maxage" ]; then fi if [ -n "$maxage" ]; then - if [ "$type" != "apt" -a "$type" != "pacman" ]; then + if [ "$type" != "apt" ] && [ "$type" != "pacman" ]; then echo "ERROR: \"--maxage\" only supported for \"apt\" or \"pacman\" pkg-manager." >&2 exit 1 elif [ $currage -lt $maxage ]; then diff --git a/cdist/conf/type/__pyvenv/gencode-remote b/cdist/conf/type/__pyvenv/gencode-remote index a4f078c5..4cba5987 100755 --- a/cdist/conf/type/__pyvenv/gencode-remote +++ b/cdist/conf/type/__pyvenv/gencode-remote @@ -29,10 +29,10 @@ owner="$(cat "$__object/parameter/owner")" group="$(cat "$__object/parameter/group")" mode="$(cat "$__object/parameter/mode")" -[ "$state_should" = "$state_is" -a \ - "$owner" = "$owner_is" -a \ - "$group" = "$group_is" -a \ - -n "$mode" ] && exit 0 +[ "$state_should" = "$state_is" ] && \ +[ "$owner" = "$owner_is" ] && \ +[ "$group" = "$group_is" ] && \ +[ -n "$mode" ] && exit 0 destination="/$__object_id" venvparams="$(cat "$__object/parameter/venvparams")" @@ -49,8 +49,8 @@ case $state_should in if [ "$state_should" != "$state_is" ]; then echo $pyvenv $venvparams "$destination" fi - if [ \( -n "$owner" -a "$owner_is" != "$owner" \) -o \ - \( -n "$group" -a "$group_is" != "$group" \) ]; then + if { [ -n "$owner" ] && [ "$owner_is" != "$owner" ]; } || \ + { [ -n "$group" ] && [ "$group_is" != "$group" ]; }; then echo chown -R "${owner}:${group}" "$destination" fi if [ -n "$mode" ]; then diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 9fad8896..8cac3449 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -23,7 +23,7 @@ owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" state="$(cat "$__object/parameter/state" 2>/dev/null)" file="$(cat "$__object/explorer/file")" -if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; then +if [ ! -f "$__object/parameter/noparent" ] || [ ! -f "$__object/parameter/nofile" ]; then group="$(cut -d':' -f 1 "$__object/explorer/group")" if [ -z "$group" ]; then echo "Failed to get owners group from explorer." >&2 From aef14ad39e9428299cc7dd05305209773ad4fcc6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 2 Oct 2018 17:21:24 +0200 Subject: [PATCH 0879/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8fd2ea49..a3d60fbb 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) * Core: Add timestamp (optional) to log messages (Darko Poljak) + * Explorers, manifests, gencodes: Fix SC2166: and/or operators in test (shellcheck) (Jonas Weber) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 5ed95ce93b145e41079e9458129f4b82614314bd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 2 Oct 2018 20:22:44 +0200 Subject: [PATCH 0880/1332] Fix SC2005 --- cdist/conf/explorer/cpu_cores | 2 +- cdist/conf/explorer/cpu_sockets | 2 +- cdist/conf/type/__zypper_repo/explorer/all_repo_ids | 2 +- cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids | 2 +- cdist/conf/type/__zypper_repo/explorer/repo_id | 2 +- cdist/conf/type/__zypper_service/explorer/repo_ids | 2 +- cdist/conf/type/__zypper_service/explorer/service_id | 2 +- cdist/conf/type/__zypper_service/explorer/service_ids | 2 +- cdist/conf/type/__zypper_service/explorer/service_uri | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cdist/conf/explorer/cpu_cores b/cdist/conf/explorer/cpu_cores index 7f7a955e..2f676f7a 100755 --- a/cdist/conf/explorer/cpu_cores +++ b/cdist/conf/explorer/cpu_cores @@ -25,7 +25,7 @@ os=$("$__explorer/os") case "$os" in "macosx") - echo "$(sysctl -n hw.physicalcpu)" + sysctl -n hw.physicalcpu ;; *) diff --git a/cdist/conf/explorer/cpu_sockets b/cdist/conf/explorer/cpu_sockets index 8a8194df..903cc743 100755 --- a/cdist/conf/explorer/cpu_sockets +++ b/cdist/conf/explorer/cpu_sockets @@ -25,7 +25,7 @@ os=$("$__explorer/os") case "$os" in "macosx") - echo "$(system_profiler SPHardwareDataType | grep "Number of Processors" | awk -F': ' '{print $2}')" + system_profiler SPHardwareDataType | grep "Number of Processors" | awk -F': ' '{print $2}' ;; *) diff --git a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids index b37d8ac5..dde6d554 100644 --- a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids @@ -21,4 +21,4 @@ # Retrieve all repo id nummbers - parsed zypper output # # -echo $(zypper lr | cut -d'|' -f 1 | grep -E '^[0-9]') +zypper lr | cut -d'|' -f 1 | grep -E '^[0-9]' diff --git a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids index 2dfb946f..b011c258 100644 --- a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids @@ -23,4 +23,4 @@ # # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper lr -E | cut -d'|' -f 1 | grep -E '^[0-9]') -echo $(zypper lr | grep -E '^[0-9]([^|]+\|){3,3} Yes' | cut -d'|' -f 1) +zypper lr | grep -E '^[0-9]([^|]+\|){3,3} Yes' | cut -d'|' -f 1 diff --git a/cdist/conf/type/__zypper_repo/explorer/repo_id b/cdist/conf/type/__zypper_repo/explorer/repo_id index 6a4791e6..114c6fe7 100644 --- a/cdist/conf/type/__zypper_repo/explorer/repo_id +++ b/cdist/conf/type/__zypper_repo/explorer/repo_id @@ -26,4 +26,4 @@ if [ -f "$__object/parameter/uri" ]; then else uri="$__object_id" fi -echo $(zypper lr -u | grep -F "$uri" | cut -d'|' -f 1 | grep -E '^[0-9]' ) +zypper lr -u | grep -F "$uri" | cut -d'|' -f 1 | grep -E '^[0-9]' diff --git a/cdist/conf/type/__zypper_service/explorer/repo_ids b/cdist/conf/type/__zypper_service/explorer/repo_ids index e831b76c..787e9869 100644 --- a/cdist/conf/type/__zypper_service/explorer/repo_ids +++ b/cdist/conf/type/__zypper_service/explorer/repo_ids @@ -24,4 +24,4 @@ # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper lr -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') # on older systems, zypper doesn't know the parameter -E -echo $(zypper lr -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') +zypper lr -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]' diff --git a/cdist/conf/type/__zypper_service/explorer/service_id b/cdist/conf/type/__zypper_service/explorer/service_id index bf5f0260..91858d84 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_id +++ b/cdist/conf/type/__zypper_service/explorer/service_id @@ -27,4 +27,4 @@ else fi # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 1 ) -echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\<$uri\>" | cut -d'|' -f 1 ) +zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\<$uri\>" | cut -d'|' -f 1 diff --git a/cdist/conf/type/__zypper_service/explorer/service_ids b/cdist/conf/type/__zypper_service/explorer/service_ids index 0f1f4186..6491ab90 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_ids +++ b/cdist/conf/type/__zypper_service/explorer/service_ids @@ -22,4 +22,4 @@ # # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') -echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') +zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]' diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri index 6eee47fb..b8de0dcd 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_uri +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -25,4 +25,4 @@ if [ -f "$__object/parameter/uri" ]; then else uri="/$__object_id" fi -echo $(zypper ls -u | awk 'BEGIN { FS = "[ ]+\\|[ ]+" } ; $4 == "Yes" && $NF == "'$uri'" {print $NF}') +zypper ls -u | awk 'BEGIN { FS = "[ ]+\\|[ ]+" } ; $4 == "Yes" && $NF == "'$uri'" {print $NF}' From 0928708d19b77a1ca0ad7f0b3f7c0d74c81bfa9a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 2 Oct 2018 20:34:54 +0200 Subject: [PATCH 0881/1332] Fix SC2004 --- .../__install_partition_msdos_apply/gencode-remote | 10 +++++----- cdist/conf/type/__prometheus_alertmanager/manifest | 2 +- cdist/conf/type/__prometheus_server/manifest | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index 090a5d86..7e8eef4e 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -40,16 +40,16 @@ size_to_mb() { case "$suffix" in K|k) - size="$(( $number / 1024 ))" + size="$(( number / 1024 ))" ;; M|m) size="$number" ;; G|g) - size="$(( $number * 1024 ))" + size="$(( number * 1024 ))" ;; %) - size="$(( $available_size * $number / 100 ))" + size="$(( available_size * number / 100 ))" ;; *) size="-1" @@ -108,7 +108,7 @@ for object in $objects; do if [ "${minor}" -lt "5" ]; then # Primary partitions - primary_count=$(( $primary_count + 1 )) + primary_count=$(( primary_count + 1 )) available_size=$available_device_size else # Logical partitions @@ -121,7 +121,7 @@ for object in $objects; do available_size=0 else partition_size=$(size_to_mb "$size" "$available_size") - available_size="$(( $available_size - $partition_size ))" + available_size="$(( available_size - partition_size ))" fi if [ "${minor}" -lt "5" ]; then diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index be50b71e..054e44cb 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -48,7 +48,7 @@ __key_value alertmanager_fix_init_script --file /etc/init.d/prometheus-alertmana ##### CONFIGURE ############################################################# -FLAGS="--storage.path $storage_path --data.retention $(($retention_days*24))h --web.listen-address [::]:9093" +FLAGS="--storage.path $storage_path --data.retention $((retention_days*24))h --web.listen-address [::]:9093" require="$require $require_pkg" \ __key_value alertmanager_args --file /etc/default/prometheus-alertmanager \ diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index 84ba53cf..e2f32fd5 100755 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -45,7 +45,7 @@ require="$require $require_pkg" __directory "$storage_path" --owner prometheus - ##### CONFIGURE ############################################################# -FLAGS="--storage.tsdb.path $storage_path --storage.tsdb.retention $(($retention_days*24))h --web.listen-address [::]:9090" +FLAGS="--storage.tsdb.path $storage_path --storage.tsdb.retention $((retention_days*24))h --web.listen-address [::]:9090" # TODO it would be neat to restart prometheus on change -- __key_value really should have an --onchange parameter require="$require $require_pkg" \ From 3757e8c2c504367bdd2d6b69a5aafbbf0fdba772 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 2 Oct 2018 21:50:17 +0200 Subject: [PATCH 0882/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index a3d60fbb..e51c198c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,8 @@ next: * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) * Core: Add timestamp (optional) to log messages (Darko Poljak) * Explorers, manifests, gencodes: Fix SC2166: and/or operators in test (shellcheck) (Jonas Weber) + * Explorers and types: Fix SC2004: $/${} is unnecessary on arithmetic variables (shellcheck) (Darko Poljak) + * Explorers and types: Fix SC2005: Useless echo? Instead of echo $(cmd), just use cmd (shellcheck) (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 44acfcdd12a8e1d8cfaa91c38c87e277c79f819d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 2 Oct 2018 20:44:46 +0200 Subject: [PATCH 0883/1332] Fix SC2002 --- cdist/conf/explorer/cpu_sockets | 4 ++-- cdist/conf/explorer/machine_type | 2 +- cdist/conf/type/__ccollect_source/manifest | 2 +- cdist/conf/type/__consul/gencode-remote | 2 +- cdist/conf/type/__golang_from_vendor/gencode-remote | 2 +- cdist/conf/type/__ssh_authorized_key/explorer/entry | 2 +- cdist/conf/type/__ssh_authorized_key/gencode-remote | 2 +- cdist/conf/type/__staged_file/gencode-local | 2 +- cdist/conf/type/__zypper_service/gencode-remote | 2 +- cdist/conf/type/__zypper_service/manifest | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cdist/conf/explorer/cpu_sockets b/cdist/conf/explorer/cpu_sockets index 903cc743..2d577043 100755 --- a/cdist/conf/explorer/cpu_sockets +++ b/cdist/conf/explorer/cpu_sockets @@ -30,9 +30,9 @@ case "$os" in *) if [ -r /proc/cpuinfo ]; then - sockets="$(grep "physical id" /proc/cpuinfo | sort | uniq | wc -l)" + sockets="$(grep "physical id" /proc/cpuinfo | sort -u | wc -l)" if [ ${sockets} -eq 0 ]; then - sockets="$(cat /proc/cpuinfo | grep "processor" | wc -l)" + sockets="$(grep -c "processor" /proc/cpuinfo)" fi echo "${sockets}" fi diff --git a/cdist/conf/explorer/machine_type b/cdist/conf/explorer/machine_type index 3b4f0308..3a3cd0c1 100755 --- a/cdist/conf/explorer/machine_type +++ b/cdist/conf/explorer/machine_type @@ -28,7 +28,7 @@ if [ -d "/proc/vz" -a ! -d "/proc/bc" ]; then fi if [ -e "/proc/1/environ" ] && - cat "/proc/1/environ" | tr '\000' '\n' | grep -Eiq '^container='; then + tr '\000' '\n' < "/proc/1/environ" | grep -Eiq '^container='; then echo lxc exit fi diff --git a/cdist/conf/type/__ccollect_source/manifest b/cdist/conf/type/__ccollect_source/manifest index 238c7e76..26c6cc99 100755 --- a/cdist/conf/type/__ccollect_source/manifest +++ b/cdist/conf/type/__ccollect_source/manifest @@ -22,7 +22,7 @@ name="$__object_id" state="$(cat "$__object/parameter/state")" source="$(cat "$__object/parameter/source")" destination="$(cat "$__object/parameter/destination")" -ccollectconf="$(cat "$__object/parameter/ccollectconf" | sed 's,/$,,')" +ccollectconf="$(sed 's,/$,,' "$__object/parameter/ccollectconf")" sourcedir="$ccollectconf/sources" basedir="$sourcedir/$name" diff --git a/cdist/conf/type/__consul/gencode-remote b/cdist/conf/type/__consul/gencode-remote index 22e9eea1..1d2244ea 100755 --- a/cdist/conf/type/__consul/gencode-remote +++ b/cdist/conf/type/__consul/gencode-remote @@ -39,7 +39,7 @@ version_dir="$versions_dir/$version" source=$(cat "$version_dir/source") source_file_name="${source##*/}" -cksum_should=$(cat "$version_dir/cksum" | cut -d' ' -f1,2) +cksum_should=$(cut -d' ' -f1,2 "$version_dir/cksum") cat << eof tmpdir=\$(mktemp -d --tmpdir="/tmp" "${__type##*/}.XXXXXXXXXX") diff --git a/cdist/conf/type/__golang_from_vendor/gencode-remote b/cdist/conf/type/__golang_from_vendor/gencode-remote index 1654978b..5200e9e3 100755 --- a/cdist/conf/type/__golang_from_vendor/gencode-remote +++ b/cdist/conf/type/__golang_from_vendor/gencode-remote @@ -2,7 +2,7 @@ version=$(cat "$__object/parameter/version") -kernel_name=$(cat "$__global/explorer/kernel_name" | tr '[:upper:]' '[:lower:]') +kernel_name=$(tr '[:upper:]' '[:lower:]' < "$__global/explorer/kernel_name") machine=$(cat "$__global/explorer/machine") case $machine in x86_64|amd64) diff --git a/cdist/conf/type/__ssh_authorized_key/explorer/entry b/cdist/conf/type/__ssh_authorized_key/explorer/entry index 1535d348..157d70f1 100755 --- a/cdist/conf/type/__ssh_authorized_key/explorer/entry +++ b/cdist/conf/type/__ssh_authorized_key/explorer/entry @@ -19,7 +19,7 @@ # # extract the keytype and base64 encoded key ignoring any options and comment -type_and_key="$(cat "$__object/parameter/key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" +type_and_key="$(tr ' ' '\n' < "$__object/parameter/key"| awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" # If type_and_key is empty, which is the case with an invalid key, do not grep $file because it results # in greping everything in file and all entries from file are removed. if [ -n "${type_and_key}" ] diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index 7ded7dc6..333dfa03 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -59,7 +59,7 @@ mkdir "$__object/files" ( if [ -f "$__object/parameter/option" ]; then # comma seperated list of options - options="$(cat "$__object/parameter/option" | tr '\n' ',')" + options="$(tr '\n' ',' < "$__object/parameter/option")" printf '%s ' "${options%*,}" fi if [ -f "$__object/parameter/comment" ]; then diff --git a/cdist/conf/type/__staged_file/gencode-local b/cdist/conf/type/__staged_file/gencode-local index 8e2003af..18bf09f5 100755 --- a/cdist/conf/type/__staged_file/gencode-local +++ b/cdist/conf/type/__staged_file/gencode-local @@ -74,7 +74,7 @@ fetch_and_prepare_file() { cat << DONE verify_cksum() { cksum_is="\$(cksum "$stage_file" | cut -d' ' -f1,2)" - cksum_should="$(cat "$__object/parameter/cksum" | cut -d' ' -f1,2)" + cksum_should="$(cut -d' ' -f1,2 "$__object/parameter/cksum")" if [ "\$cksum_is" = "\$cksum_should" ]; then return 0 else diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote index e5b41cc6..955698d1 100755 --- a/cdist/conf/type/__zypper_service/gencode-remote +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -46,7 +46,7 @@ exp_uri="$(cat "$__object/explorer/service_uri")" exp_id="$(cat "$__object/explorer/service_id")" # we need this list to remove ids, but we must do this in reverse order -exp_ids="$(cat "$__object/explorer/service_ids" | rev)" +exp_ids="$(rev "$__object/explorer/service_ids")" if [ "$uri" = "$exp_uri" ] ; then state_is="present" diff --git a/cdist/conf/type/__zypper_service/manifest b/cdist/conf/type/__zypper_service/manifest index e4f0bcf6..42a56830 100755 --- a/cdist/conf/type/__zypper_service/manifest +++ b/cdist/conf/type/__zypper_service/manifest @@ -47,7 +47,7 @@ fi [ "$state_is" = "$state_should" ] && exit 0 # we need this list to remove ids, but we must do this in reverse order -exp_repos="$(cat "$__object/explorer/repo_ids" | rev)" +exp_repos="$(rev "$__object/explorer/repo_ids")" # boolean parameter if [ -f "$__object/parameter/remove-all-repos" ]; then From 8ef2773c0db54179ccb456961758aaea53aef2ee Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 3 Oct 2018 14:32:28 +0200 Subject: [PATCH 0884/1332] Fix SC2039 --- cdist/conf/type/__docker/manifest | 2 +- cdist/conf/type/__group/gencode-remote | 6 +++--- .../files/lib.sh | 20 +++++++++---------- .../gencode-remote | 10 +++++----- .../explorer/pkg_version | 2 +- .../explorer/pkg_version | 2 +- .../__package_pkgng_freebsd/gencode-remote | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index d501a9f1..e0558b46 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -24,7 +24,7 @@ state=$(cat "$__object/parameter/state") case "$os" in centos) - if (source "$__global/explorer/os_release" && [ "${VERSION_ID}" = "7" ]); then + if (. "$__global/explorer/os_release" && [ "${VERSION_ID}" = "7" ]); then __yum_repo docker-ce-stable \ --name 'Docker CE Stable' \ --baseurl "https://download.docker.com/linux/centos/7/\$basearch/stable" \ diff --git a/cdist/conf/type/__group/gencode-remote b/cdist/conf/type/__group/gencode-remote index 5847cb66..68475178 100755 --- a/cdist/conf/type/__group/gencode-remote +++ b/cdist/conf/type/__group/gencode-remote @@ -30,9 +30,9 @@ state="$(cat "$__object/parameter/state")" # Use short option names for portability shorten_property() { case "$1" in - gid) echo "-g";; - password) echo "-p";; - system) echo "-r";; + gid) echo -- "-g";; + password) echo -- "-p";; + system) echo -- "-r";; esac } diff --git a/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh b/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh index cddc575d..13ead401 100644 --- a/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh +++ b/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh @@ -8,8 +8,8 @@ debug() { } fdisk_command() { - local device="$1" - local cmd="$2" + device="$1" + cmd="$2" debug fdisk_command "running fdisk command '${cmd}' on device ${device}" printf "${cmd}\nw\n" | fdisk -c -u "$device" @@ -20,7 +20,7 @@ fdisk_command() { } create_disklabel() { - local device=$1 + device=$1 debug create_disklabel "creating new msdos disklabel" fdisk_command ${device} "o" @@ -28,18 +28,18 @@ create_disklabel() { } toggle_bootable() { - local device="$1" - local minor="$2" + device="$1" + minor="$2" fdisk_command ${device} "a\n${minor}\n" return $? } create_partition() { - local device="$1" - local minor="$2" - local size="$3" - local type="$4" - local primary_count="$5" + device="$1" + minor="$2" + size="$3" + type="$4" + primary_count="$5" if [ "$type" = "extended" -o "$type" = "5" ]; then # Extended partition diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index 312e6f81..9e5fcd00 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -31,12 +31,12 @@ debug() { # Convert a size specifier 1G 100M or 50% into the corresponding numeric MB. size_to_mb() { - local size=$1 - local available_size="$2" + size=$1 + available_size="$2" - local number_suffix="$(echo ${size} | sed -e 's:\.[0-9]\+::' -e 's:\([0-9]\+\)\([KkMmGg%]\)[Bb]\?:\1|\2:')" - local number="$(echo ${number_suffix} | cut -d '|' -f1)" - local suffix="$(echo ${number_suffix} | cut -d '|' -f2)" + number_suffix="$(echo ${size} | sed -e 's:\.[0-9]\+::' -e 's:\([0-9]\+\)\([KkMmGg%]\)[Bb]\?:\1|\2:')" + number="$(echo ${number_suffix} | cut -d '|' -f1)" + suffix="$(echo ${number_suffix} | cut -d '|' -f2)" case "$suffix" in K|k) diff --git a/cdist/conf/type/__package_pkg_freebsd/explorer/pkg_version b/cdist/conf/type/__package_pkg_freebsd/explorer/pkg_version index 1335ba79..0a1ab75c 100755 --- a/cdist/conf/type/__package_pkg_freebsd/explorer/pkg_version +++ b/cdist/conf/type/__package_pkg_freebsd/explorer/pkg_version @@ -30,7 +30,7 @@ fi # Don't produce "no pkgs installed" output -- breaks things PKG_OUTPUT=$(pkg_info 2>&1) if [ ! "$PKG_OUTPUT" = "pkg_info: no packages installed" ]; then - echo -n "$(echo "$PKG_OUTPUT" \ + printf "%s" "$(echo "$PKG_OUTPUT" \ | awk '{print $1}' \ | sed 's/^\(.*\)-\([^-]*\)$/name:\1 ver:\2/g' \ | grep "name:$name ver:" \ diff --git a/cdist/conf/type/__package_pkgng_freebsd/explorer/pkg_version b/cdist/conf/type/__package_pkgng_freebsd/explorer/pkg_version index 947857b9..92ce0623 100755 --- a/cdist/conf/type/__package_pkgng_freebsd/explorer/pkg_version +++ b/cdist/conf/type/__package_pkgng_freebsd/explorer/pkg_version @@ -29,7 +29,7 @@ fi # Don't produce "no pkgs installed" output -- breaks things PKG_OUTPUT=$(pkg info 2>&1) -echo -n "$(echo "$PKG_OUTPUT" \ +printf "%s" "$(echo "$PKG_OUTPUT" \ | awk '{print $1}' \ | sed 's/^\(.*\)-\([^-]*\)$/name:\1 ver:\2/g' \ | grep "name:$name ver:" \ diff --git a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote index d21e9e2a..b59e3648 100755 --- a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote @@ -52,7 +52,7 @@ cmd="" # Parms: $1 -- mode, "rm", "add", or "upg" # $2 -- the command to be echoed execcmd(){ - local _cmd="" + _cmd="" case "$1" in add) From 383af6736f968cd79d742b300fffaf97a0c82713 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 3 Oct 2018 14:52:17 +0200 Subject: [PATCH 0885/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e51c198c..ecd52327 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: * Explorers, manifests, gencodes: Fix SC2166: and/or operators in test (shellcheck) (Jonas Weber) * Explorers and types: Fix SC2004: $/${} is unnecessary on arithmetic variables (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2005: Useless echo? Instead of echo $(cmd), just use cmd (shellcheck) (Darko Poljak) + * Explorers and types: Fix SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead (shellcheck) (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From ab9e2264df73c9f97db502ab4efa7701a2c90371 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 4 Oct 2018 09:10:31 +0200 Subject: [PATCH 0886/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ecd52327..100b914d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Explorers and types: Fix SC2004: $/${} is unnecessary on arithmetic variables (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2005: Useless echo? Instead of echo $(cmd), just use cmd (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead (shellcheck) (Darko Poljak) + * Explorers and types: Fix SC2039: In POSIX sh, something is undefined (shellcheck) (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 134c84607f0ae90666ca17d7454462cb111fde90 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 4 Oct 2018 12:28:59 +0200 Subject: [PATCH 0887/1332] fix another SC2166 (test `[ .. -a.. ]` replaced by `[ .. ] && ]`) --- cdist/conf/explorer/machine_type | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/explorer/machine_type b/cdist/conf/explorer/machine_type index 3a3cd0c1..bb21f69c 100755 --- a/cdist/conf/explorer/machine_type +++ b/cdist/conf/explorer/machine_type @@ -22,7 +22,7 @@ # FIXME: other system types (not linux ...) -if [ -d "/proc/vz" -a ! -d "/proc/bc" ]; then +if [ -d "/proc/vz" ] && [ ! -d "/proc/bc" ]; then echo openvz exit fi From 31bf6ab230f68b55bd53b7646c3abd3487fc7303 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 4 Oct 2018 12:38:40 +0200 Subject: [PATCH 0888/1332] ++changelog --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 100b914d..5fccbc55 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog next: * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) * Core: Add timestamp (optional) to log messages (Darko Poljak) - * Explorers, manifests, gencodes: Fix SC2166: and/or operators in test (shellcheck) (Jonas Weber) + * Explorers, manifests, gencodes: Fix SC2166: and/or operators in test (shellcheck) (Jonas Weber, Thomas Eckert) * Explorers and types: Fix SC2004: $/${} is unnecessary on arithmetic variables (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2005: Useless echo? Instead of echo $(cmd), just use cmd (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead (shellcheck) (Darko Poljak) From d950ddada3a43c8c3d1498a533c91abb6604b51e Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 4 Oct 2018 16:01:45 +0200 Subject: [PATCH 0889/1332] fix SC2045 (use globs instead of `ls`) --- cdist/conf/type/__config_file/manifest | 3 ++- cdist/conf/type/__consul_agent/manifest | 3 ++- cdist/conf/type/__consul_check/manifest | 3 ++- cdist/conf/type/__consul_service/manifest | 3 ++- cdist/conf/type/__consul_template/manifest | 3 ++- cdist/conf/type/__consul_template_template/manifest | 3 ++- cdist/conf/type/__consul_watch_checks/manifest | 3 ++- cdist/conf/type/__consul_watch_event/manifest | 3 ++- cdist/conf/type/__consul_watch_key/manifest | 3 ++- cdist/conf/type/__consul_watch_keyprefix/manifest | 3 ++- cdist/conf/type/__consul_watch_nodes/manifest | 3 ++- cdist/conf/type/__consul_watch_service/manifest | 3 ++- cdist/conf/type/__consul_watch_services/manifest | 3 ++- cdist/conf/type/__jail/manifest | 2 +- cdist/conf/type/__package/manifest | 2 +- cdist/conf/type/__user/gencode-remote | 4 ++-- 16 files changed, 30 insertions(+), 17 deletions(-) diff --git a/cdist/conf/type/__config_file/manifest b/cdist/conf/type/__config_file/manifest index 3155f79b..be8f9f67 100755 --- a/cdist/conf/type/__config_file/manifest +++ b/cdist/conf/type/__config_file/manifest @@ -19,7 +19,8 @@ # set -- "/${__object_id}" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in source) source="$(cat "$__object/parameter/source")" diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index a696894b..3951f728 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -84,7 +84,8 @@ echo "{" # parameters we define ourself printf ' "data_dir": "%s"\n' "$data_dir" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state|user|group|json-config) continue ;; ca-file-source|cert-file-source|key-file-source) diff --git a/cdist/conf/type/__consul_check/manifest b/cdist/conf/type/__consul_check/manifest index 554c0680..c9f7add9 100755 --- a/cdist/conf/type/__consul_check/manifest +++ b/cdist/conf/type/__consul_check/manifest @@ -50,7 +50,8 @@ fi echo "{" printf ' "check": {\n' printf ' "name": "%s"\n' "$name" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state|name) continue ;; *) diff --git a/cdist/conf/type/__consul_service/manifest b/cdist/conf/type/__consul_service/manifest index f6d29b4a..60397db7 100755 --- a/cdist/conf/type/__consul_service/manifest +++ b/cdist/conf/type/__consul_service/manifest @@ -42,7 +42,8 @@ fi echo "{" printf ' "service": {\n' printf ' "name": "%s"\n' "$name" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state|name|check-interval) continue ;; check-script) diff --git a/cdist/conf/type/__consul_template/manifest b/cdist/conf/type/__consul_template/manifest index 2236e5bd..b02fc332 100755 --- a/cdist/conf/type/__consul_template/manifest +++ b/cdist/conf/type/__consul_template/manifest @@ -75,7 +75,8 @@ require="__directory/etc/consul-template" \ # Generate hcl config file ( -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in auth-password|state|ssl-*|syslog-*|version|vault-token|vault-ssl*) continue ;; auth-username) diff --git a/cdist/conf/type/__consul_template_template/manifest b/cdist/conf/type/__consul_template_template/manifest index 488a0f5d..7834ae9c 100755 --- a/cdist/conf/type/__consul_template_template/manifest +++ b/cdist/conf/type/__consul_template_template/manifest @@ -38,7 +38,8 @@ fi # Generate hcl config file ( printf 'template {\n' -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in source-file) source="$(cat "$__object/parameter/$param")" diff --git a/cdist/conf/type/__consul_watch_checks/manifest b/cdist/conf/type/__consul_watch_checks/manifest index 146f609e..5fdd7a74 100755 --- a/cdist/conf/type/__consul_watch_checks/manifest +++ b/cdist/conf/type/__consul_watch_checks/manifest @@ -35,7 +35,8 @@ fi echo "{" printf ' "watches": [{\n' printf ' "type": "%s"\n' "$watch_type" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state) continue ;; filter-*) diff --git a/cdist/conf/type/__consul_watch_event/manifest b/cdist/conf/type/__consul_watch_event/manifest index 099054a5..61934656 100755 --- a/cdist/conf/type/__consul_watch_event/manifest +++ b/cdist/conf/type/__consul_watch_event/manifest @@ -29,7 +29,8 @@ state="$(cat "$__object/parameter/state")" echo "{" printf ' "watches": [{\n' printf ' "type": "%s"\n' "$watch_type" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state) continue ;; *) diff --git a/cdist/conf/type/__consul_watch_key/manifest b/cdist/conf/type/__consul_watch_key/manifest index 099054a5..61934656 100755 --- a/cdist/conf/type/__consul_watch_key/manifest +++ b/cdist/conf/type/__consul_watch_key/manifest @@ -29,7 +29,8 @@ state="$(cat "$__object/parameter/state")" echo "{" printf ' "watches": [{\n' printf ' "type": "%s"\n' "$watch_type" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state) continue ;; *) diff --git a/cdist/conf/type/__consul_watch_keyprefix/manifest b/cdist/conf/type/__consul_watch_keyprefix/manifest index 099054a5..61934656 100755 --- a/cdist/conf/type/__consul_watch_keyprefix/manifest +++ b/cdist/conf/type/__consul_watch_keyprefix/manifest @@ -29,7 +29,8 @@ state="$(cat "$__object/parameter/state")" echo "{" printf ' "watches": [{\n' printf ' "type": "%s"\n' "$watch_type" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state) continue ;; *) diff --git a/cdist/conf/type/__consul_watch_nodes/manifest b/cdist/conf/type/__consul_watch_nodes/manifest index 099054a5..61934656 100755 --- a/cdist/conf/type/__consul_watch_nodes/manifest +++ b/cdist/conf/type/__consul_watch_nodes/manifest @@ -29,7 +29,8 @@ state="$(cat "$__object/parameter/state")" echo "{" printf ' "watches": [{\n' printf ' "type": "%s"\n' "$watch_type" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state) continue ;; *) diff --git a/cdist/conf/type/__consul_watch_service/manifest b/cdist/conf/type/__consul_watch_service/manifest index 2825c716..db38eb18 100755 --- a/cdist/conf/type/__consul_watch_service/manifest +++ b/cdist/conf/type/__consul_watch_service/manifest @@ -29,7 +29,8 @@ state="$(cat "$__object/parameter/state")" echo "{" printf ' "watches": [{\n' printf ' "type": "%s"\n' "$watch_type" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state) continue ;; passingonly) diff --git a/cdist/conf/type/__consul_watch_services/manifest b/cdist/conf/type/__consul_watch_services/manifest index 099054a5..61934656 100755 --- a/cdist/conf/type/__consul_watch_services/manifest +++ b/cdist/conf/type/__consul_watch_services/manifest @@ -29,7 +29,8 @@ state="$(cat "$__object/parameter/state")" echo "{" printf ' "watches": [{\n' printf ' "type": "%s"\n' "$watch_type" -for param in $(ls "$__object/parameter/"); do +cd "$__object/parameter/" +for param in *; do case "$param" in state) continue ;; *) diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index c3d9dfbe..7564be26 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -39,7 +39,7 @@ __directory ${jaildir} --parents set -- "$@" "$__object_id" "--state" "$state" cd "$__object/parameter" -for property in $(ls .); do +for property in *; do set -- "$@" "--$property" "$(cat "$property")" done diff --git a/cdist/conf/type/__package/manifest b/cdist/conf/type/__package/manifest index 3ab0f546..f9de1145 100755 --- a/cdist/conf/type/__package/manifest +++ b/cdist/conf/type/__package/manifest @@ -55,7 +55,7 @@ state="$(cat "$__object/parameter/state")" set -- "$@" "$__object_id" "--state" "$state" cd "$__object/parameter" -for property in $(ls .); do +for property in *; do if [ "$property" != "type" ] && [ "$property" != "state" ]; then set -- "$@" "--$property" "$(cat "$property")" fi diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index 23762065..332e93f1 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -52,7 +52,7 @@ shorten_property() { if [ "$state" = "present" ]; then cd "$__object/parameter" if grep -q "^${name}:" "$__object/explorer/passwd"; then - for property in $(ls .); do + for property in *; do new_value="$(cat "$property")" unset current_value @@ -113,7 +113,7 @@ if [ "$state" = "present" ]; then fi else echo add >> "$__messages_out" - for property in $(ls .); do + for property in *; do [ "$property" = "state" ] && continue [ "$property" = "remove-home" ] && continue new_value="$(cat "$property")" From d49d38481fb996e47c51f50fad60097c9068c067 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 4 Oct 2018 17:31:37 +0200 Subject: [PATCH 0890/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 5fccbc55..47639dd5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Explorers and types: Fix SC2005: Useless echo? Instead of echo $(cmd), just use cmd (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2039: In POSIX sh, something is undefined (shellcheck) (Darko Poljak) + * Explorers and types: Fix SC2045: Iterating over ls output is fragile. Use globs. (shellcheck) (Thomas Eckert) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From a46da35bbcb9aef6e0106e764f2a3332048896d6 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 4 Oct 2018 12:20:50 +0200 Subject: [PATCH 0891/1332] fix SC2148 (missing shebang) and make executable --- cdist/conf/explorer/disks | 1 + cdist/conf/explorer/is-freebsd-jail | 1 + cdist/conf/explorer/kernel_name | 1 + cdist/conf/type/__daemontools_service/explorer/svc | 1 + cdist/conf/type/__go_get/explorer/go-executable | 1 + 5 files changed, 5 insertions(+) mode change 100644 => 100755 cdist/conf/explorer/disks mode change 100644 => 100755 cdist/conf/explorer/is-freebsd-jail mode change 100644 => 100755 cdist/conf/explorer/kernel_name mode change 100644 => 100755 cdist/conf/type/__daemontools_service/explorer/svc mode change 100644 => 100755 cdist/conf/type/__go_get/explorer/go-executable diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks old mode 100644 new mode 100755 index 52fef81e..6febdbb4 --- a/cdist/conf/explorer/disks +++ b/cdist/conf/explorer/disks @@ -1,2 +1,3 @@ +#!/bin/sh -e cd /dev echo sd? hd? vd? diff --git a/cdist/conf/explorer/is-freebsd-jail b/cdist/conf/explorer/is-freebsd-jail old mode 100644 new mode 100755 index a6d11d1a..d8f8b0ac --- a/cdist/conf/explorer/is-freebsd-jail +++ b/cdist/conf/explorer/is-freebsd-jail @@ -1 +1,2 @@ +#!/bin/sh -e sysctl -n security.jail.jailed 2>/dev/null | grep "1" || true diff --git a/cdist/conf/explorer/kernel_name b/cdist/conf/explorer/kernel_name old mode 100644 new mode 100755 index 98ebac2a..365b5029 --- a/cdist/conf/explorer/kernel_name +++ b/cdist/conf/explorer/kernel_name @@ -1 +1,2 @@ +#!/bin/sh -e uname -s diff --git a/cdist/conf/type/__daemontools_service/explorer/svc b/cdist/conf/type/__daemontools_service/explorer/svc old mode 100644 new mode 100755 index d33fcea4..fdca5e34 --- a/cdist/conf/type/__daemontools_service/explorer/svc +++ b/cdist/conf/type/__daemontools_service/explorer/svc @@ -1 +1,2 @@ +#!/bin/sh -e command -v svc || true diff --git a/cdist/conf/type/__go_get/explorer/go-executable b/cdist/conf/type/__go_get/explorer/go-executable old mode 100644 new mode 100755 index 4c84ce07..b1dc0984 --- a/cdist/conf/type/__go_get/explorer/go-executable +++ b/cdist/conf/type/__go_get/explorer/go-executable @@ -1,3 +1,4 @@ +#!/bin/sh -e [ -f /etc/environment ] && . /etc/environment [ -f /etc/profile ] && . /etc/profile go version 2>/dev/null || true From 085b2a2b104cdeeac8200e5d991137f248244a44 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 4 Oct 2018 15:15:57 +0200 Subject: [PATCH 0892/1332] remove `set -e` on explorers (they should be able to fail gracefully) --- cdist/conf/explorer/disks | 2 +- cdist/conf/explorer/is-freebsd-jail | 2 +- cdist/conf/explorer/kernel_name | 2 +- cdist/conf/type/__daemontools_service/explorer/svc | 2 +- cdist/conf/type/__go_get/explorer/go-executable | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks index 6febdbb4..7a5c0da0 100755 --- a/cdist/conf/explorer/disks +++ b/cdist/conf/explorer/disks @@ -1,3 +1,3 @@ -#!/bin/sh -e +#!/bin/sh cd /dev echo sd? hd? vd? diff --git a/cdist/conf/explorer/is-freebsd-jail b/cdist/conf/explorer/is-freebsd-jail index d8f8b0ac..010917f5 100755 --- a/cdist/conf/explorer/is-freebsd-jail +++ b/cdist/conf/explorer/is-freebsd-jail @@ -1,2 +1,2 @@ -#!/bin/sh -e +#!/bin/sh sysctl -n security.jail.jailed 2>/dev/null | grep "1" || true diff --git a/cdist/conf/explorer/kernel_name b/cdist/conf/explorer/kernel_name index 365b5029..1f9cfca4 100755 --- a/cdist/conf/explorer/kernel_name +++ b/cdist/conf/explorer/kernel_name @@ -1,2 +1,2 @@ -#!/bin/sh -e +#!/bin/sh uname -s diff --git a/cdist/conf/type/__daemontools_service/explorer/svc b/cdist/conf/type/__daemontools_service/explorer/svc index fdca5e34..9ba462f2 100755 --- a/cdist/conf/type/__daemontools_service/explorer/svc +++ b/cdist/conf/type/__daemontools_service/explorer/svc @@ -1,2 +1,2 @@ -#!/bin/sh -e +#!/bin/sh command -v svc || true diff --git a/cdist/conf/type/__go_get/explorer/go-executable b/cdist/conf/type/__go_get/explorer/go-executable index b1dc0984..bdce7559 100755 --- a/cdist/conf/type/__go_get/explorer/go-executable +++ b/cdist/conf/type/__go_get/explorer/go-executable @@ -1,4 +1,4 @@ -#!/bin/sh -e +#!/bin/sh [ -f /etc/environment ] && . /etc/environment [ -f /etc/profile ] && . /etc/profile go version 2>/dev/null || true From ef8ec8641e4959f6536f6f5d5caa417954195468 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 4 Oct 2018 18:47:28 +0200 Subject: [PATCH 0893/1332] ++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 47639dd5..1405ad3c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Explorers and types: Fix SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2039: In POSIX sh, something is undefined (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2045: Iterating over ls output is fragile. Use globs. (shellcheck) (Thomas Eckert) + * Explorers and types: Fix SC2148: Tips depend on target shell and yours is unknown. Add a shebang. (shellcheck) (Thomas Eckert) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 6b0f8fba22a56e853b97706813e59e98963bc7a5 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Wed, 3 Oct 2018 21:11:59 +0200 Subject: [PATCH 0894/1332] Remove unused variables (almost, found bugs?) Solves SC2034 references #540. --- cdist/conf/type/__apt_ppa/manifest | 2 -- cdist/conf/type/__block/manifest | 2 -- cdist/conf/type/__ccollect_source/gencode-remote | 1 - cdist/conf/type/__file/gencode-remote | 1 - cdist/conf/type/__firewalld_rule/gencode-remote | 1 - cdist/conf/type/__group/gencode-remote | 2 -- cdist/conf/type/__install_generate_fstab/gencode-local | 1 - cdist/conf/type/__install_mkfs/manifest | 8 +------- cdist/conf/type/__install_reboot/gencode-remote | 2 -- cdist/conf/type/__install_reboot/manifest | 6 ++++-- cdist/conf/type/__install_umount/manifest | 6 ++++-- cdist/conf/type/__jail_freebsd10/gencode-remote | 1 + cdist/conf/type/__jail_freebsd9/gencode-remote | 1 + cdist/conf/type/__pacman_conf_integrate/manifest | 2 -- cdist/conf/type/__postfix_master/manifest | 1 - cdist/conf/type/__qemu_img/manifest | 1 - cdist/conf/type/__rvm_gem/gencode-remote | 2 -- cdist/conf/type/__rvm_gemset/explorer/state | 3 --- cdist/conf/type/__rvm_ruby/gencode-remote | 1 - cdist/conf/type/__staged_file/gencode-local | 1 - cdist/conf/type/__staged_file/manifest | 4 ---- 21 files changed, 11 insertions(+), 38 deletions(-) diff --git a/cdist/conf/type/__apt_ppa/manifest b/cdist/conf/type/__apt_ppa/manifest index e1af21bd..c6f4e876 100755 --- a/cdist/conf/type/__apt_ppa/manifest +++ b/cdist/conf/type/__apt_ppa/manifest @@ -18,8 +18,6 @@ # along with cdist. If not, see . # -name="$__object_id" - __package software-properties-common require="__package/software-properties-common" \ diff --git a/cdist/conf/type/__block/manifest b/cdist/conf/type/__block/manifest index 8fea3e83..726950d3 100755 --- a/cdist/conf/type/__block/manifest +++ b/cdist/conf/type/__block/manifest @@ -18,8 +18,6 @@ # along with cdist. If not, see . # - -file="$(cat "$__object/parameter/file" 2>/dev/null || echo "/$__object_id")" prefix=$(cat "$__object/parameter/prefix" 2>/dev/null || echo "#cdist:__block/$__object_id") suffix=$(cat "$__object/parameter/suffix" 2>/dev/null || echo "#/cdist:__block/$__object_id") text=$(cat "$__object/parameter/text") diff --git a/cdist/conf/type/__ccollect_source/gencode-remote b/cdist/conf/type/__ccollect_source/gencode-remote index 763f219e..c8892c9e 100755 --- a/cdist/conf/type/__ccollect_source/gencode-remote +++ b/cdist/conf/type/__ccollect_source/gencode-remote @@ -56,7 +56,6 @@ set_mode() { echo chmod $1 >> "$__messages_out" } -set_attributes= case "$state_should" in present|exists) # Note: Mode - needs to happen last as a chown/chgrp can alter mode by diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 9dfd1833..6632935c 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -57,7 +57,6 @@ set_mode() { echo chmod $1 >> "$__messages_out" } -set_attributes= case "$state_should" in present|exists|pre-exists) # Note: Mode - needs to happen last as a chown/chgrp can alter mode by diff --git a/cdist/conf/type/__firewalld_rule/gencode-remote b/cdist/conf/type/__firewalld_rule/gencode-remote index 4c824d39..b9b930e7 100755 --- a/cdist/conf/type/__firewalld_rule/gencode-remote +++ b/cdist/conf/type/__firewalld_rule/gencode-remote @@ -19,7 +19,6 @@ # # -name="$__object_id" state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/rule")" diff --git a/cdist/conf/type/__group/gencode-remote b/cdist/conf/type/__group/gencode-remote index 68475178..033228c5 100755 --- a/cdist/conf/type/__group/gencode-remote +++ b/cdist/conf/type/__group/gencode-remote @@ -40,11 +40,9 @@ shorten_property() { if [ "$state" = "present" ]; then case "$os" in freebsd) - supported_add_properties="gid" supported_change_properties="gid" ;; *) - supported_add_properties="gid password system" supported_change_properties="gid password" ;; esac diff --git a/cdist/conf/type/__install_generate_fstab/gencode-local b/cdist/conf/type/__install_generate_fstab/gencode-local index 5cc7d877..b5158a39 100755 --- a/cdist/conf/type/__install_generate_fstab/gencode-local +++ b/cdist/conf/type/__install_generate_fstab/gencode-local @@ -28,7 +28,6 @@ $__remote_exec $__target_host blkid > "$__object/files/blkid" for object in $(find "$__global/object/__install_mount" -type d -name "$__cdist_object_marker"); do device="$(cat "$object/parameter/device")" dir="$(cat "$object/parameter/dir")" - prefix="$(cat "$object/parameter/prefix")" type="$(cat "$object/parameter/type")" if [ -f "$object/parameter/options" ]; then options="$(cat "$object/parameter/options")" diff --git a/cdist/conf/type/__install_mkfs/manifest b/cdist/conf/type/__install_mkfs/manifest index eb65757f..b0a21dae 100755 --- a/cdist/conf/type/__install_mkfs/manifest +++ b/cdist/conf/type/__install_mkfs/manifest @@ -19,13 +19,7 @@ # # set defaults -if [ -f "$__object/parameter/device" ]; then - device="(cat "$__object/parameter/device")" -else +if [ ! -f "$__object/parameter/device" ]; then device="/$__object_id" echo "$device" > "$__object/parameter/device" fi - -type="(cat "$__object/parameter/type")" - -options="(cat "$__object/parameter/options")" diff --git a/cdist/conf/type/__install_reboot/gencode-remote b/cdist/conf/type/__install_reboot/gencode-remote index 00c04523..9a6322c1 100755 --- a/cdist/conf/type/__install_reboot/gencode-remote +++ b/cdist/conf/type/__install_reboot/gencode-remote @@ -18,8 +18,6 @@ # along with cdist. If not, see . # -options="$(cat "$__object/parameter/options")" - #echo "reboot $options" cat << DONE echo 1 > /proc/sys/kernel/sysrq diff --git a/cdist/conf/type/__install_reboot/manifest b/cdist/conf/type/__install_reboot/manifest index 02689d82..46a6356e 100755 --- a/cdist/conf/type/__install_reboot/manifest +++ b/cdist/conf/type/__install_reboot/manifest @@ -19,5 +19,7 @@ # # set defaults -options="$(cat "$__object/parameter/options" 2>/dev/null \ - || echo "" | tee "$__object/parameter/options")" +# TODO is this neccesary or should this be handled using the usual parameter/default workflow? +if [ ! -f "$__object/parameter/options" ]; then + touch "$__object/parameter/options" +fi diff --git a/cdist/conf/type/__install_umount/manifest b/cdist/conf/type/__install_umount/manifest index 42cd19bf..d900df1b 100755 --- a/cdist/conf/type/__install_umount/manifest +++ b/cdist/conf/type/__install_umount/manifest @@ -19,5 +19,7 @@ # # set defaults -target="$(cat "$__object/parameter/target" 2>/dev/null \ - || echo "/target" | tee "$__object/parameter/target")" +# TODO is this neccesary or should this be handled using the usual parameter/default workflow? +if [ ! -f "$__object/parameter/target" ]; then + echo "/target" > "$__object/parameter/target" +fi diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index d8bc5eb7..8ce77768 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -87,6 +87,7 @@ if [ $(expr "${ip}" : ".*, .*") -gt "0" ]; then SAVE_IFS="$IFS" IFS=", " for cur_ip in ${ip}; do + # TODO BUG? Why is cur_ip unused in the following line? # Just get the last IP address for SSH to listen on mgmt_ip=$(echo "${ip}" | cut '-d ' -f1) # In case using "ip netmask" format rather than CIDR done diff --git a/cdist/conf/type/__jail_freebsd9/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote index d883dec4..c76bb014 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -92,6 +92,7 @@ if [ $(expr "${ip}" : ".*|.*") -gt "0" ]; then SAVE_IFS="$IFS" IFS=", " for cur_ip in ${ip}; do + # TODO BUG? Why is cur_ip unused in the following line? # Just get the last IP address for SSH to listen on mgmt_ip=$(echo "${ip}" | sed -E -e 's/^.*\|(.*)\/[0-9]+$/\1/') done diff --git a/cdist/conf/type/__pacman_conf_integrate/manifest b/cdist/conf/type/__pacman_conf_integrate/manifest index b26bca50..829fb34b 100755 --- a/cdist/conf/type/__pacman_conf_integrate/manifest +++ b/cdist/conf/type/__pacman_conf_integrate/manifest @@ -20,8 +20,6 @@ state=$(cat $__object/parameter/state 2>/dev/null) -path="/etc/" - if [ "${state}" = "present" ]; then __file /etc/pacman.conf\ --owner root --group root --mode 644 --source $__type/files/pacman.conf.cdist diff --git a/cdist/conf/type/__postfix_master/manifest b/cdist/conf/type/__postfix_master/manifest index 4991a13d..94b5044f 100755 --- a/cdist/conf/type/__postfix_master/manifest +++ b/cdist/conf/type/__postfix_master/manifest @@ -36,7 +36,6 @@ __postfix # Default to object_id service="$(cat "$__object/parameter/service" 2>/dev/null || echo "$__object_id")" -state="$(cat "$__object/parameter/state")" # NOTE: keep variables in sync in manifest,explorer,gencode-* prefix="#cdist:$__object_name" diff --git a/cdist/conf/type/__qemu_img/manifest b/cdist/conf/type/__qemu_img/manifest index e7417389..55f3bf16 100755 --- a/cdist/conf/type/__qemu_img/manifest +++ b/cdist/conf/type/__qemu_img/manifest @@ -4,7 +4,6 @@ # Default settings # -format="$(cat "$__object/parameter/format")" state_should="$(cat "$__object/parameter/state")" diskimage="/$__object_id" diff --git a/cdist/conf/type/__rvm_gem/gencode-remote b/cdist/conf/type/__rvm_gem/gencode-remote index 1fe6e78e..9212de91 100755 --- a/cdist/conf/type/__rvm_gem/gencode-remote +++ b/cdist/conf/type/__rvm_gem/gencode-remote @@ -20,8 +20,6 @@ gem="$__object_id" gemset="$(cat "$__object/parameter/gemset")" -ruby="$(echo "$gemset" | cut -d '@' -f 1)" -gemsetname="$(echo "$gemset" | cut -d '@' -f 2)" state_is="$(cat "$__object/explorer/state")" user="$(cat "$__object/parameter/user")" state_should="$(cat "$__object/parameter/state")" diff --git a/cdist/conf/type/__rvm_gemset/explorer/state b/cdist/conf/type/__rvm_gemset/explorer/state index fa643a6e..d1462134 100755 --- a/cdist/conf/type/__rvm_gemset/explorer/state +++ b/cdist/conf/type/__rvm_gemset/explorer/state @@ -18,9 +18,6 @@ # along with cdist. If not, see . # -gemset="$__object_id" -ruby="$(echo "$gemset" | cut -d '@' -f 1)" -gemsetname="$(echo "$gemset" | cut -d '@' -f2)" user="$(cat "$__object/parameter/user")" if [ ! -e "~$user/.rvm/scripts/rvm" ] ; then diff --git a/cdist/conf/type/__rvm_ruby/gencode-remote b/cdist/conf/type/__rvm_ruby/gencode-remote index 9bbc6031..f2fd41ef 100755 --- a/cdist/conf/type/__rvm_ruby/gencode-remote +++ b/cdist/conf/type/__rvm_ruby/gencode-remote @@ -21,7 +21,6 @@ ruby="$__object_id" state_is="$(cat "$__object/explorer/state")" user="$(cat "$__object/parameter/user")" -default="$(cat "$__object/parameter/default" 2>/dev/null || true)" state_should="$(cat "$__object/parameter/state")" [ "$state_is" = "$state_should" ] && exit 0 diff --git a/cdist/conf/type/__staged_file/gencode-local b/cdist/conf/type/__staged_file/gencode-local index 18bf09f5..851970e8 100755 --- a/cdist/conf/type/__staged_file/gencode-local +++ b/cdist/conf/type/__staged_file/gencode-local @@ -23,7 +23,6 @@ destination="$__object_id" source="$(cat "$__object/parameter/source")" -cksum="$(cat "$__object/parameter/cksum")" stage_dir="$(cat "$__object/parameter/stage-dir")" state="$(cat "$__object/parameter/state")" fetch_command="$(cat "$__object/parameter/fetch-command")" diff --git a/cdist/conf/type/__staged_file/manifest b/cdist/conf/type/__staged_file/manifest index 1654e1d9..c8e1fbbb 100755 --- a/cdist/conf/type/__staged_file/manifest +++ b/cdist/conf/type/__staged_file/manifest @@ -19,11 +19,7 @@ # destination="$__object_id" -source="$(cat "$__object/parameter/source")" -cksum="$(cat "$__object/parameter/cksum")" stage_dir="$(cat "$__object/parameter/stage-dir")" -state="$(cat "$__object/parameter/state")" -fetch_command="$(cat "$__object/parameter/fetch-command")" stage_file="${stage_dir}/${destination}" set -- "/${destination}" From b3f4d3849a687a1795302cb25d3c50c251a4417c Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 4 Oct 2018 13:34:11 +0200 Subject: [PATCH 0895/1332] Fix __install_umount target parameter --- cdist/conf/type/__install_umount/manifest | 25 ------------------- .../__install_umount/parameter/default/target | 1 + .../type/__install_umount/parameter/optional | 1 + 3 files changed, 2 insertions(+), 25 deletions(-) delete mode 100755 cdist/conf/type/__install_umount/manifest create mode 100644 cdist/conf/type/__install_umount/parameter/default/target create mode 100644 cdist/conf/type/__install_umount/parameter/optional diff --git a/cdist/conf/type/__install_umount/manifest b/cdist/conf/type/__install_umount/manifest deleted file mode 100755 index d900df1b..00000000 --- a/cdist/conf/type/__install_umount/manifest +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -e -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# 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 . -# - -# set defaults -# TODO is this neccesary or should this be handled using the usual parameter/default workflow? -if [ ! -f "$__object/parameter/target" ]; then - echo "/target" > "$__object/parameter/target" -fi diff --git a/cdist/conf/type/__install_umount/parameter/default/target b/cdist/conf/type/__install_umount/parameter/default/target new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/cdist/conf/type/__install_umount/parameter/default/target @@ -0,0 +1 @@ +/target diff --git a/cdist/conf/type/__install_umount/parameter/optional b/cdist/conf/type/__install_umount/parameter/optional new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/cdist/conf/type/__install_umount/parameter/optional @@ -0,0 +1 @@ +target From 352679386dc9acd18b7e98de0dfb3d2b8a75b81c Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 4 Oct 2018 13:36:45 +0200 Subject: [PATCH 0896/1332] Drop unused options parameter in __install_reboot --- cdist/conf/type/__install_reboot/man.rst | 3 +-- cdist/conf/type/__install_reboot/manifest | 25 ----------------------- 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100755 cdist/conf/type/__install_reboot/manifest diff --git a/cdist/conf/type/__install_reboot/man.rst b/cdist/conf/type/__install_reboot/man.rst index ecf78ca7..9a53b37a 100644 --- a/cdist/conf/type/__install_reboot/man.rst +++ b/cdist/conf/type/__install_reboot/man.rst @@ -18,8 +18,7 @@ None OPTIONAL PARAMETERS ------------------- -options - options to pass to the reboot command. e.g. -f +None EXAMPLES diff --git a/cdist/conf/type/__install_reboot/manifest b/cdist/conf/type/__install_reboot/manifest deleted file mode 100755 index 46a6356e..00000000 --- a/cdist/conf/type/__install_reboot/manifest +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -e -# -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# -# 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 . -# - -# set defaults -# TODO is this neccesary or should this be handled using the usual parameter/default workflow? -if [ ! -f "$__object/parameter/options" ]; then - touch "$__object/parameter/options" -fi From 23debd5b6f27bcafd6b91149af9280f4398016df Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 4 Oct 2018 19:21:59 +0200 Subject: [PATCH 0897/1332] Use cur_ip in jail for freebsd --- cdist/conf/type/__jail_freebsd10/gencode-remote | 3 +-- cdist/conf/type/__jail_freebsd9/gencode-remote | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index 8ce77768..5be04bc6 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -87,9 +87,8 @@ if [ $(expr "${ip}" : ".*, .*") -gt "0" ]; then SAVE_IFS="$IFS" IFS=", " for cur_ip in ${ip}; do - # TODO BUG? Why is cur_ip unused in the following line? # Just get the last IP address for SSH to listen on - mgmt_ip=$(echo "${ip}" | cut '-d ' -f1) # In case using "ip netmask" format rather than CIDR + mgmt_ip=$(echo "${cur_ip}" | cut '-d ' -f1) # In case using "ip netmask" format rather than CIDR done IFS="$SAVE_IFS" else diff --git a/cdist/conf/type/__jail_freebsd9/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote index c76bb014..177bdf74 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -92,9 +92,8 @@ if [ $(expr "${ip}" : ".*|.*") -gt "0" ]; then SAVE_IFS="$IFS" IFS=", " for cur_ip in ${ip}; do - # TODO BUG? Why is cur_ip unused in the following line? # Just get the last IP address for SSH to listen on - mgmt_ip=$(echo "${ip}" | sed -E -e 's/^.*\|(.*)\/[0-9]+$/\1/') + mgmt_ip=$(echo "${cur_ip}" | sed -E -e 's/^.*\|(.*)\/[0-9]+$/\1/') done IFS="$SAVE_IFS" else From ae7ccc59959ce45948bd6b767d8559ff9715cdbf Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Tue, 2 Oct 2018 21:44:27 +0200 Subject: [PATCH 0898/1332] Fix SC2086 on all scripts Relevant documentation: https://github.com/koalaman/shellcheck/wiki/SC2086 relates to: #540 This commit addresses 241 separate cases of missing quotes around variables. --- cdist/conf/explorer/cpu_cores | 2 +- cdist/conf/explorer/cpu_sockets | 2 +- cdist/conf/explorer/lsb_codename | 2 +- cdist/conf/explorer/lsb_description | 2 +- cdist/conf/explorer/lsb_id | 2 +- cdist/conf/explorer/lsb_release | 2 +- cdist/conf/explorer/os_version | 2 +- cdist/conf/type/__apt_ppa/gencode-remote | 4 ++-- .../type/__ccollect_source/gencode-remote | 16 ++++++------- cdist/conf/type/__ccollect_source/manifest | 2 +- cdist/conf/type/__cron/explorer/entry | 4 ++-- cdist/conf/type/__daemontools/manifest | 4 ++-- .../conf/type/__daemontools_service/manifest | 4 ++-- cdist/conf/type/__directory/gencode-remote | 16 ++++++------- cdist/conf/type/__docker/manifest | 10 ++++---- .../conf/type/__docker_compose/gencode-remote | 4 ++-- cdist/conf/type/__docker_compose/manifest | 4 ++-- cdist/conf/type/__file/gencode-remote | 16 ++++++------- .../conf/type/__firewalld_rule/explorer/rule | 2 +- .../conf/type/__firewalld_rule/gencode-remote | 8 +++---- cdist/conf/type/__git/explorer/group | 2 +- cdist/conf/type/__git/explorer/owner | 2 +- cdist/conf/type/__grafana_dashboard/manifest | 4 ++-- cdist/conf/type/__group/explorer/gshadow | 2 +- cdist/conf/type/__group/gencode-remote | 8 +++---- .../__install_bootloader_grub/gencode-remote | 2 +- .../__install_generate_fstab/gencode-local | 4 ++-- .../gencode-remote | 14 +++++------ cdist/conf/type/__jail/manifest | 2 +- cdist/conf/type/__link/explorer/type | 2 +- .../conf/type/__package/explorer/pkgng_exists | 2 +- .../type/__package_luarocks/gencode-remote | 4 ++-- cdist/conf/type/__package_opkg/gencode-remote | 4 ++-- .../conf/type/__package_pacman/gencode-remote | 4 ++-- .../type/__package_pkg_freebsd/gencode-remote | 2 +- .../type/__package_rubygem/gencode-remote | 4 ++-- .../__package_update_index/explorer/currage | 2 +- .../type/__package_update_index/explorer/type | 2 +- .../__package_update_index/gencode-remote | 2 +- .../type/__package_upgrade_all/gencode-remote | 4 ++-- cdist/conf/type/__package_yum/gencode-remote | 4 ++-- .../conf/type/__package_zypper/gencode-remote | 6 ++--- cdist/conf/type/__pacman_conf/manifest | 24 +++++++++---------- .../type/__pacman_conf_integrate/manifest | 10 ++++---- cdist/conf/type/__pf_apply/explorer/rcvar | 2 +- cdist/conf/type/__pf_ruleset/explorer/cksum | 2 +- cdist/conf/type/__pf_ruleset/explorer/rcvar | 2 +- .../type/__prometheus_alertmanager/manifest | 2 +- .../conf/type/__prometheus_exporter/manifest | 8 +++---- cdist/conf/type/__prometheus_server/manifest | 6 ++--- cdist/conf/type/__pyvenv/explorer/group | 2 +- cdist/conf/type/__pyvenv/explorer/owner | 2 +- cdist/conf/type/__pyvenv/gencode-remote | 2 +- cdist/conf/type/__qemu_img/gencode-remote | 2 +- cdist/conf/type/__rsync/gencode-local | 2 +- cdist/conf/type/__rvm/explorer/state | 2 +- .../type/__ssh_authorized_key/explorer/entry | 2 +- .../type/__ssh_authorized_key/gencode-remote | 2 +- .../conf/type/__start_on_boot/gencode-remote | 10 ++++---- cdist/conf/type/__start_on_boot/manifest | 2 +- cdist/conf/type/__user/explorer/shadow | 2 +- cdist/conf/type/__user/gencode-remote | 6 ++--- cdist/conf/type/__zypper_repo/gencode-remote | 8 +++---- .../__zypper_service/explorer/service_uri | 2 +- .../conf/type/__zypper_service/gencode-remote | 16 ++++++------- 65 files changed, 154 insertions(+), 154 deletions(-) diff --git a/cdist/conf/explorer/cpu_cores b/cdist/conf/explorer/cpu_cores index 2f676f7a..27cc6800 100755 --- a/cdist/conf/explorer/cpu_cores +++ b/cdist/conf/explorer/cpu_cores @@ -31,7 +31,7 @@ case "$os" in *) if [ -r /proc/cpuinfo ]; then cores="$(grep "core id" /proc/cpuinfo | sort | uniq | wc -l)" - if [ ${cores} -eq 0 ]; then + if [ "${cores}" -eq 0 ]; then cores="1" fi echo "$cores" diff --git a/cdist/conf/explorer/cpu_sockets b/cdist/conf/explorer/cpu_sockets index 2d577043..a32e2f00 100755 --- a/cdist/conf/explorer/cpu_sockets +++ b/cdist/conf/explorer/cpu_sockets @@ -31,7 +31,7 @@ case "$os" in *) if [ -r /proc/cpuinfo ]; then sockets="$(grep "physical id" /proc/cpuinfo | sort -u | wc -l)" - if [ ${sockets} -eq 0 ]; then + if [ "${sockets}" -eq 0 ]; then sockets="$(grep -c "processor" /proc/cpuinfo)" fi echo "${sockets}" diff --git a/cdist/conf/explorer/lsb_codename b/cdist/conf/explorer/lsb_codename index eebd3e0f..bfabd444 100755 --- a/cdist/conf/explorer/lsb_codename +++ b/cdist/conf/explorer/lsb_codename @@ -20,7 +20,7 @@ # set +e -case "$($__explorer/os)" in +case "$("$__explorer/os")" in openwrt) (. /etc/openwrt_release && echo "$DISTRIB_CODENAME") ;; diff --git a/cdist/conf/explorer/lsb_description b/cdist/conf/explorer/lsb_description index 23f45421..441fdbf3 100755 --- a/cdist/conf/explorer/lsb_description +++ b/cdist/conf/explorer/lsb_description @@ -20,7 +20,7 @@ # set +e -case "$($__explorer/os)" in +case "$("$__explorer/os")" in openwrt) (. /etc/openwrt_release && echo "$DISTRIB_DESCRIPTION") ;; diff --git a/cdist/conf/explorer/lsb_id b/cdist/conf/explorer/lsb_id index 9754eb63..1a12b610 100755 --- a/cdist/conf/explorer/lsb_id +++ b/cdist/conf/explorer/lsb_id @@ -20,7 +20,7 @@ # set +e -case "$($__explorer/os)" in +case "$("$__explorer/os")" in openwrt) (. /etc/openwrt_release && echo "$DISTRIB_ID") ;; diff --git a/cdist/conf/explorer/lsb_release b/cdist/conf/explorer/lsb_release index 35b5547c..25eb95b1 100755 --- a/cdist/conf/explorer/lsb_release +++ b/cdist/conf/explorer/lsb_release @@ -20,7 +20,7 @@ # set +e -case "$($__explorer/os)" in +case "$("$__explorer/os")" in openwrt) (. /etc/openwrt_release && echo "$DISTRIB_RELEASE") ;; diff --git a/cdist/conf/explorer/os_version b/cdist/conf/explorer/os_version index 380782cc..4c41695b 100755 --- a/cdist/conf/explorer/os_version +++ b/cdist/conf/explorer/os_version @@ -22,7 +22,7 @@ # # -case "$($__explorer/os)" in +case "$("$__explorer/os")" in amazon) cat /etc/system-release ;; diff --git a/cdist/conf/type/__apt_ppa/gencode-remote b/cdist/conf/type/__apt_ppa/gencode-remote index f60cb7ac..25dec58d 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 \"$name\"" ;; absent) - echo remove-apt-repository \"$name\" + echo "remove-apt-repository \"$name\"" ;; esac diff --git a/cdist/conf/type/__ccollect_source/gencode-remote b/cdist/conf/type/__ccollect_source/gencode-remote index 763f219e..5f2f97e3 100755 --- a/cdist/conf/type/__ccollect_source/gencode-remote +++ b/cdist/conf/type/__ccollect_source/gencode-remote @@ -42,18 +42,18 @@ get_current_value() { } set_group() { - echo chgrp \"$1\" \"$destination\" - echo chgrp $1 >> "$__messages_out" + echo chgrp \""$1"\" \""$destination"\" + echo chgrp "$1" >> "$__messages_out" } set_owner() { - echo chown \"$1\" \"$destination\" - echo chown $1 >> "$__messages_out" + echo chown \""$1"\" \""$destination"\" + echo chown "$1" >> "$__messages_out" } set_mode() { - echo chmod \"$1\" \"$destination\" - echo chmod $1 >> "$__messages_out" + echo chmod \""$1"\" \""$destination"\" + echo chmod "$1" >> "$__messages_out" } set_attributes= @@ -67,7 +67,7 @@ case "$state_should" in # change 0xxx format to xxx format => same as stat returns if [ "$attribute" = mode ]; then - value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" + value_should="$(echo "$value_should" | sed 's/^0\(...\)/\1/')" fi value_is="$(get_current_value "$attribute" "$value_should")" @@ -81,7 +81,7 @@ case "$state_should" in absent) if [ "$type" = "file" ]; then - echo rm -f \"$destination\" + echo rm -f \""$destination"\" echo remove >> "$__messages_out" fi ;; diff --git a/cdist/conf/type/__ccollect_source/manifest b/cdist/conf/type/__ccollect_source/manifest index 26c6cc99..727a4c97 100755 --- a/cdist/conf/type/__ccollect_source/manifest +++ b/cdist/conf/type/__ccollect_source/manifest @@ -55,5 +55,5 @@ if [ -f "$__object/parameter/exclude" ]; then fi if [ -f "$__object/parameter/create-destination" ]; then - __directory "${destination}" --parents --state ${state} + __directory "${destination}" --parents --state "${state}" fi diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry index 2167e045..801861a3 100644 --- a/cdist/conf/type/__cron/explorer/entry +++ b/cdist/conf/type/__cron/explorer/entry @@ -24,7 +24,7 @@ user="$(cat "$__object/parameter/user")" if [ -f "$__object/parameter/raw_command" ]; then command="$(cat "$__object/parameter/command")" - crontab -u $user -l 2>/dev/null | grep "^$command\$" || true + crontab -u "$user" -l 2>/dev/null | grep "^$command\$" || true else - crontab -u $user -l 2>/dev/null | grep "# $name\$" || true + crontab -u "$user" -l 2>/dev/null | grep "# $name\$" || true fi diff --git a/cdist/conf/type/__daemontools/manifest b/cdist/conf/type/__daemontools/manifest index 45ce3df6..656f4984 100755 --- a/cdist/conf/type/__daemontools/manifest +++ b/cdist/conf/type/__daemontools/manifest @@ -3,8 +3,8 @@ pkg=$(cat "$__object/parameter/from-package") servicedir=$(cat "$__object/parameter/servicedir") -__package $pkg -__directory $servicedir --mode 700 +__package "$pkg" +__directory "$servicedir" --mode 700 os=$(cat "$__global/explorer/os") init=$(cat "$__global/explorer/init") diff --git a/cdist/conf/type/__daemontools_service/manifest b/cdist/conf/type/__daemontools_service/manifest index 9e8e0bee..78bae285 100755 --- a/cdist/conf/type/__daemontools_service/manifest +++ b/cdist/conf/type/__daemontools_service/manifest @@ -25,14 +25,14 @@ badusage() { [ -z "$run$runfile" ] && badusage [ -n "$run" ] && [ -n "$runfile" ] && badusage -__directory $servicedir/$name/log/main --parents +__directory "$servicedir/$name/log/main" --parents echo "$RUN_PREFIX$run" | require="__directory/$servicedir/$name/log/main" __config_file "$servicedir/$name/run" \ --onchange "svc -t '$servicedir/$name' 2>/dev/null" \ --mode 755 \ --source "${runfile:--}" -echo "$RUN_PREFIX$logrun" | require="__directory/$servicedir/$name/log/main" __config_file $servicedir/$name/log/run \ +echo "$RUN_PREFIX$logrun" | require="__directory/$servicedir/$name/log/main" __config_file "$servicedir/$name/log/run" \ --onchange "svc -t '$servicedir/$name/log' 2>/dev/null" \ --mode 755 \ --source "-" diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index cced4624..35866eb4 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -57,18 +57,18 @@ get_current_value() { } set_group() { - echo chgrp $recursive \"$1\" \"$destination\" - echo chgrp $recursive $1 >> "$__messages_out" + echo chgrp "$recursive" \""$1"\" \""$destination"\" + echo chgrp "$recursive" "$1" >> "$__messages_out" } set_owner() { - echo chown $recursive \"$1\" \"$destination\" - echo chown $recursive $1 >> "$__messages_out" + echo chown "$recursive" \""$1"\" \""$destination"\" + echo chown "$recursive" "$1" >> "$__messages_out" } set_mode() { - echo chmod $recursive \"$1\" \"$destination\" - echo chmod $recursive $1 >> "$__messages_out" + echo chmod "$recursive" \""$1"\" \""$destination"\" + echo chmod "$recursive" "$1" >> "$__messages_out" } case "$state_should" in @@ -94,7 +94,7 @@ case "$state_should" in # change 0xxx format to xxx format => same as stat returns if [ "$attribute" = mode ]; then - value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" + value_should="$(echo "$value_should" | sed 's/^0\(...\)/\1/')" fi if [ "$set_attributes" = 1 ] || [ "$value_should" != "$value_is" ]; then @@ -105,7 +105,7 @@ case "$state_should" in ;; absent) if [ "$type" = "directory" ]; then - echo rm -rf \"$destination\" + echo rm -rf \""$destination"\" echo remove >> "$__messages_out" fi ;; diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index e0558b46..35760cef 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -31,8 +31,8 @@ case "$os" in --enabled \ --gpgcheck 1 \ --gpgkey 'https://download.docker.com/linux/centos/gpg' \ - --state ${state} - require="__yum_repo/docker-ce-stable" __package docker-ce --state ${state} + --state "${state}" + require="__yum_repo/docker-ce-stable" __package docker-ce --state "${state}" else echo "CentOS version 7 is required!" >&2 exit 1 @@ -45,14 +45,14 @@ case "$os" in __package gnupg2 fi __apt_key_uri docker --name "Docker Release (CE deb) " \ - --uri "https://download.docker.com/linux/${os}/gpg" --state ${state} + --uri "https://download.docker.com/linux/${os}/gpg" --state "${state}" export CDIST_ORDER_DEPENDENCY=on __apt_source docker \ --uri "https://download.docker.com/linux/${os}" \ --distribution "$(cat "$__global/explorer/lsb_codename")" \ - --state ${state} \ + --state "${state}" \ --component "stable" - __package docker-ce --state ${state} + __package docker-ce --state "${state}" unset CDIST_ORDER_DEPENDENCY ;; *) diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote index 2b8267a9..396c93ac 100755 --- a/cdist/conf/type/__docker_compose/gencode-remote +++ b/cdist/conf/type/__docker_compose/gencode-remote @@ -22,9 +22,9 @@ version="$(cat "$__object/parameter/version")" state="$(cat "$__object/parameter/state")" -if [ ${state} = "present" ]; then +if [ "${state}" = "present" ]; then # Download docker-compose file - echo 'curl -L "https://github.com/docker/compose/releases/download/'${version}'/docker-compose-$(uname -s)-$(uname -m)" -o /tmp/docker-compose' + echo 'curl -L "https://github.com/docker/compose/releases/download/'"${version}"'/docker-compose-$(uname -s)-$(uname -m)" -o /tmp/docker-compose' echo 'mv /tmp/docker-compose /usr/local/bin/docker-compose' # Change permissions echo 'chmod +x /usr/local/bin/docker-compose' diff --git a/cdist/conf/type/__docker_compose/manifest b/cdist/conf/type/__docker_compose/manifest index c17f0f33..f7de3a76 100755 --- a/cdist/conf/type/__docker_compose/manifest +++ b/cdist/conf/type/__docker_compose/manifest @@ -22,10 +22,10 @@ state="$(cat "$__object/parameter/state")" # Needed packages -if [ ${state} = "present" ]; then +if [ "${state}" = "present" ]; then __docker __package curl -elif [ ${state} = "absent" ]; then +elif [ "${state}" = "absent" ]; then __file /usr/local/bin/docker-compose --state absent else echo "Unknown state: ${state}" >&2 diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 9dfd1833..ebc30fd9 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -43,18 +43,18 @@ get_current_value() { } set_group() { - echo chgrp \"$1\" \"$destination\" - echo chgrp $1 >> "$__messages_out" + echo chgrp \""$1"\" \""$destination"\" + echo chgrp "$1" >> "$__messages_out" } set_owner() { - echo chown \"$1\" \"$destination\" - echo chown $1 >> "$__messages_out" + echo chown \""$1"\" \""$destination"\" + echo chown "$1" >> "$__messages_out" } set_mode() { - echo chmod \"$1\" \"$destination\" - echo chmod $1 >> "$__messages_out" + echo chmod \""$1"\" \""$destination"\" + echo chmod "$1" >> "$__messages_out" } set_attributes= @@ -68,7 +68,7 @@ case "$state_should" in # change 0xxx format to xxx format => same as stat returns if [ "$attribute" = mode ]; then - value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" + value_should="$(echo "$value_should" | sed 's/^0\(...\)/\1/')" fi value_is="$(get_current_value "$attribute" "$value_should")" @@ -82,7 +82,7 @@ case "$state_should" in absent) if [ "$type" = "file" ]; then - echo rm -f \"$destination\" + echo rm -f \""$destination"\" echo remove >> "$__messages_out" fi ;; diff --git a/cdist/conf/type/__firewalld_rule/explorer/rule b/cdist/conf/type/__firewalld_rule/explorer/rule index 5a0e0265..0234e5b6 100644 --- a/cdist/conf/type/__firewalld_rule/explorer/rule +++ b/cdist/conf/type/__firewalld_rule/explorer/rule @@ -25,7 +25,7 @@ chain="$(cat "$__object/parameter/chain")" priority="$(cat "$__object/parameter/priority")" rule="$(cat "$__object/parameter/rule")" -if firewall-cmd --permanent --direct --query-rule "$protocol" "$table" "$chain" "$priority" $rule >/dev/null; then +if firewall-cmd --permanent --direct --query-rule "$protocol" "$table" "$chain" "$priority" "$rule" >/dev/null; then echo present else echo absent diff --git a/cdist/conf/type/__firewalld_rule/gencode-remote b/cdist/conf/type/__firewalld_rule/gencode-remote index 4c824d39..bc218d9a 100755 --- a/cdist/conf/type/__firewalld_rule/gencode-remote +++ b/cdist/conf/type/__firewalld_rule/gencode-remote @@ -33,13 +33,13 @@ rule="$(cat "$__object/parameter/rule")" case "$state_should" in present) - echo firewall-cmd --quiet --permanent --direct --add-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule - echo firewall-cmd --quiet --direct --add-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule + echo "firewall-cmd --quiet --permanent --direct --add-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule" + echo "firewall-cmd --quiet --direct --add-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule" ;; absent) - echo firewall-cmd --quiet --permanent --direct --remove-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule - echo firewall-cmd --quiet --direct --remove-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule + echo "firewall-cmd --quiet --permanent --direct --remove-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule" + echo "firewall-cmd --quiet --direct --remove-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule" ;; *) echo "Unknown state $state_should" >&2 diff --git a/cdist/conf/type/__git/explorer/group b/cdist/conf/type/__git/explorer/group index 1308c710..3ddf9656 100644 --- a/cdist/conf/type/__git/explorer/group +++ b/cdist/conf/type/__git/explorer/group @@ -2,4 +2,4 @@ destination="/$__object_id/.git" -stat --print "%G" ${destination} 2>/dev/null || exit 0 +stat --print "%G" "${destination}" 2>/dev/null || exit 0 diff --git a/cdist/conf/type/__git/explorer/owner b/cdist/conf/type/__git/explorer/owner index 8c36b035..4c3cd431 100644 --- a/cdist/conf/type/__git/explorer/owner +++ b/cdist/conf/type/__git/explorer/owner @@ -2,4 +2,4 @@ destination="/$__object_id/.git" -stat --print "%U" ${destination} 2>/dev/null || exit 0 +stat --print "%U" "${destination}" 2>/dev/null || exit 0 diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest index 308af59a..2e9bd115 100755 --- a/cdist/conf/type/__grafana_dashboard/manifest +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -1,7 +1,7 @@ #!/bin/sh -e -os=$(cat $__global/explorer/os) -os_version=$(cat $__global/explorer/os_version) +os=$(cat "$__global/explorer/os") +os_version=$(cat "$__global/explorer/os_version") case $os in debian|devuan) diff --git a/cdist/conf/type/__group/explorer/gshadow b/cdist/conf/type/__group/explorer/gshadow index 2e2ab29d..ef40b7bc 100755 --- a/cdist/conf/type/__group/explorer/gshadow +++ b/cdist/conf/type/__group/explorer/gshadow @@ -22,7 +22,7 @@ # name=$__object_id -os="$($__explorer/os)" +os="$("$__explorer/os")" case "$os" in "freebsd"|"netbsd") diff --git a/cdist/conf/type/__group/gencode-remote b/cdist/conf/type/__group/gencode-remote index 68475178..5b3947dc 100755 --- a/cdist/conf/type/__group/gencode-remote +++ b/cdist/conf/type/__group/gencode-remote @@ -63,8 +63,8 @@ if [ "$state" = "present" ]; then ;; esac if [ "$new_value" != "$current_value" ]; then - set -- "$@" "$(shorten_property $property)" \'$new_value\' - echo change $property $new_value $current_value >> "$__messages_out" + set -- "$@" "$(shorten_property "$property")" \'"$new_value"\' + echo "change $property $new_value $current_value" >> "$__messages_out" fi fi done @@ -83,9 +83,9 @@ if [ "$state" = "present" ]; then new_value="$(cat "$__object/parameter/$property")" if [ -z "$new_value" ]; then # Boolean parameters have no value - set -- "$@" "$(shorten_property $property)" + set -- "$@" "$(shorten_property "$property")" else - set -- "$@" "$(shorten_property $property)" \'$new_value\' + set -- "$@" "$(shorten_property "$property")" \'"$new_value"\' fi fi done diff --git a/cdist/conf/type/__install_bootloader_grub/gencode-remote b/cdist/conf/type/__install_bootloader_grub/gencode-remote index 6e6e5e85..1caebbbf 100755 --- a/cdist/conf/type/__install_bootloader_grub/gencode-remote +++ b/cdist/conf/type/__install_bootloader_grub/gencode-remote @@ -28,7 +28,7 @@ install_script="$__object/files/install_script" # Link file descriptor #6 with stdout exec 6>&1 # Link stdout with $install_script -exec > $install_script +exec > "$install_script" # Generate script to install bootloader on distro printf '#!/bin/sh -l\n' diff --git a/cdist/conf/type/__install_generate_fstab/gencode-local b/cdist/conf/type/__install_generate_fstab/gencode-local index 5cc7d877..d0f99f61 100755 --- a/cdist/conf/type/__install_generate_fstab/gencode-local +++ b/cdist/conf/type/__install_generate_fstab/gencode-local @@ -23,7 +23,7 @@ cat "$__type/files/fstab.header" > "$destination" mkdir "$__object/files" # get current UUID's from target_host -$__remote_exec $__target_host blkid > "$__object/files/blkid" +$__remote_exec "$__target_host" blkid > "$__object/files/blkid" for object in $(find "$__global/object/__install_mount" -type d -name "$__cdist_object_marker"); do device="$(cat "$object/parameter/device")" @@ -54,7 +54,7 @@ for object in $(find "$__global/object/__install_mount" -type d -name "$__cdist_ ;; esac if [ -f "$__object/parameter/uuid" ]; then - uuid="$(grep -w $device "$__object/files/blkid" | awk '{print $2}')" + uuid="$(grep -w "$device" "$__object/files/blkid" | awk '{print $2}')" if [ -n "$uuid" ]; then echo "# $dir was on $device during installation" >> "$destination" device="$uuid" diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index 9e5fcd00..b8100c52 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -34,9 +34,9 @@ size_to_mb() { size=$1 available_size="$2" - number_suffix="$(echo ${size} | sed -e 's:\.[0-9]\+::' -e 's:\([0-9]\+\)\([KkMmGg%]\)[Bb]\?:\1|\2:')" - number="$(echo ${number_suffix} | cut -d '|' -f1)" - suffix="$(echo ${number_suffix} | cut -d '|' -f2)" + number_suffix="$(echo "${size}" | sed -e 's:\.[0-9]\+::' -e 's:\([0-9]\+\)\([KkMmGg%]\)[Bb]\?:\1|\2:')" + number="$(echo "${number_suffix}" | cut -d '|' -f1)" + suffix="$(echo "${number_suffix}" | cut -d '|' -f2)" case "$suffix" in K|k) @@ -62,10 +62,10 @@ get_objects() { for object in $(find "$__global/object/__install_partition_msdos" -type d -name "$__cdist_object_marker"); do object_device="$(cat "$object/parameter/device")" object_minor="$(cat "$object/parameter/minor")" - echo "$object_device $object_minor $object" >> $objects_file + echo "$object_device $object_minor $object" >> "$objects_file" done - sort -k 1,2 $objects_file | cut -d' ' -f 3 - rm $objects_file + sort -k 1,2 "$objects_file" | cut -d' ' -f 3 + rm "$objects_file" unset objects_file unset object unset object_device @@ -87,7 +87,7 @@ for object in $objects; do if [ "$current_device" != "$device" ]; then echo "create_disklabel \"$device\" || die 'Failed to create disklabel for $device'" current_device="$device" - device_name=$(echo ${device} | sed -e 's:^/dev/::;s:/:\\/:g') + device_name=$(echo "${device}" | sed -e 's:^/dev/::;s:/:\\/:g') available_device_size=$(( $(awk "/${device_name}\$/ { print \$3; }" "$partitions") / 1024)) # make sure we don't go past the end of the drive available_device_size=$((available_device_size - 2)) diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index 7564be26..222cb859 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -35,7 +35,7 @@ fi jaildir="$(cat "$__object/parameter/jaildir")" -__directory ${jaildir} --parents +__directory "${jaildir}" --parents set -- "$@" "$__object_id" "--state" "$state" cd "$__object/parameter" diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type index 579fd081..48a79bf0 100755 --- a/cdist/conf/type/__link/explorer/type +++ b/cdist/conf/type/__link/explorer/type @@ -32,7 +32,7 @@ elif [ -f "$destination" ]; then case "$type" in hard) link_count=$(ls -l "$destination" | awk '{ print $2 }') - if [ $link_count -gt 1 ]; then + if [ "$link_count" -gt 1 ]; then echo hardlink exit 0 fi diff --git a/cdist/conf/type/__package/explorer/pkgng_exists b/cdist/conf/type/__package/explorer/pkgng_exists index 355c5d65..6d69ba14 100755 --- a/cdist/conf/type/__package/explorer/pkgng_exists +++ b/cdist/conf/type/__package/explorer/pkgng_exists @@ -21,7 +21,7 @@ # Retrieve the status of a package - parsed dpkg output # -if [ "$($__explorer/os)" = "freebsd" ]; then +if [ "$("$__explorer/os")" = "freebsd" ]; then command -v pkg fi diff --git a/cdist/conf/type/__package_luarocks/gencode-remote b/cdist/conf/type/__package_luarocks/gencode-remote index cae06b22..e14d7a8e 100755 --- a/cdist/conf/type/__package_luarocks/gencode-remote +++ b/cdist/conf/type/__package_luarocks/gencode-remote @@ -42,10 +42,10 @@ fi case "$state_should" in present) - echo luarocks install \"$name\" + echo luarocks install \""$name"\" ;; absent) - echo luarocks remove \"$name\" + echo luarocks remove \""$name"\" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_opkg/gencode-remote b/cdist/conf/type/__package_opkg/gencode-remote index 09fe69a4..53f154a5 100755 --- a/cdist/conf/type/__package_opkg/gencode-remote +++ b/cdist/conf/type/__package_opkg/gencode-remote @@ -45,10 +45,10 @@ case "$state_should" in if [ "$present" = "notpresent" ]; then echo opkg --verbosity=0 update fi - echo opkg --verbosity=0 install \"$name\" + echo opkg --verbosity=0 install \""$name"\" ;; absent) - echo opkg --verbosity=0 remove \"$name\" + echo opkg --verbosity=0 remove \""$name"\" ;; *) echo "Unknown state: $state" >&2 diff --git a/cdist/conf/type/__package_pacman/gencode-remote b/cdist/conf/type/__package_pacman/gencode-remote index 69a5d62a..43649124 100755 --- a/cdist/conf/type/__package_pacman/gencode-remote +++ b/cdist/conf/type/__package_pacman/gencode-remote @@ -45,10 +45,10 @@ fi case "$state_should" in present) - echo pacman --needed --noconfirm --noprogressbar -S \"$name\" + echo pacman --needed --noconfirm --noprogressbar -S \""$name"\" ;; absent) - echo pacman --noconfirm --noprogressbar -R \"$name\" + echo pacman --noconfirm --noprogressbar -R \""$name"\" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_pkg_freebsd/gencode-remote b/cdist/conf/type/__package_pkg_freebsd/gencode-remote index 012bf2ad..6c6e15b1 100755 --- a/cdist/conf/type/__package_pkg_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_freebsd/gencode-remote @@ -33,7 +33,7 @@ assert () # If condition false, lineno=$2 - if [ ! $1 ] + if [ ! "$1" ] then echo "Assertion failed: \"$1\"" echo "File \"$0\", line $lineno, called by $(caller 0)" diff --git a/cdist/conf/type/__package_rubygem/gencode-remote b/cdist/conf/type/__package_rubygem/gencode-remote index 6d793ac0..d474db20 100755 --- a/cdist/conf/type/__package_rubygem/gencode-remote +++ b/cdist/conf/type/__package_rubygem/gencode-remote @@ -39,10 +39,10 @@ fi case "$state_should" in present) - echo gem install \"$name\" --no-ri --no-rdoc + echo gem install \""$name"\" --no-ri --no-rdoc ;; absent) - echo gem uninstall \"$name\" + echo gem uninstall \""$name"\" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage index 50474fb3..3539b8e1 100644 --- a/cdist/conf/type/__package_update_index/explorer/currage +++ b/cdist/conf/type/__package_update_index/explorer/currage @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . -type="$($__type_explorer/type)" +type="$("$__type_explorer/type")" case "$type" in apt) diff --git a/cdist/conf/type/__package_update_index/explorer/type b/cdist/conf/type/__package_update_index/explorer/type index 805b9f04..35254c5f 100644 --- a/cdist/conf/type/__package_update_index/explorer/type +++ b/cdist/conf/type/__package_update_index/explorer/type @@ -21,7 +21,7 @@ if [ -f "$__object/parameter/type" ]; then cat "$__object/parameter/type" else # By default determine package manager based on operating system - os="$($__explorer/os)" + os="$("$__explorer/os")" case "$os" in amazon|scientific|centos|fedora|redhat) echo "yum" ;; debian|ubuntu|devuan) echo "apt" ;; diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote index 8589c6d1..738d38eb 100755 --- a/cdist/conf/type/__package_update_index/gencode-remote +++ b/cdist/conf/type/__package_update_index/gencode-remote @@ -31,7 +31,7 @@ if [ -n "$maxage" ]; then if [ "$type" != "apt" ] && [ "$type" != "pacman" ]; then echo "ERROR: \"--maxage\" only supported for \"apt\" or \"pacman\" pkg-manager." >&2 exit 1 - elif [ $currage -lt $maxage ]; then + elif [ "$currage" -lt "$maxage" ]; then exit 0 # no need to update fi fi diff --git a/cdist/conf/type/__package_upgrade_all/gencode-remote b/cdist/conf/type/__package_upgrade_all/gencode-remote index bcad8a43..38aa001e 100755 --- a/cdist/conf/type/__package_upgrade_all/gencode-remote +++ b/cdist/conf/type/__package_upgrade_all/gencode-remote @@ -53,8 +53,8 @@ case "$type" in ;; apt) if [ -f "$apt_dist_upgrade" ] - then echo $aptget dist-upgrade - else echo $aptget upgrade + then echo "$aptget dist-upgrade" + else echo "$aptget upgrade" fi if [ -f "$apt_clean" ] diff --git a/cdist/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote index e1323dea..d860c48c 100755 --- a/cdist/conf/type/__package_yum/gencode-remote +++ b/cdist/conf/type/__package_yum/gencode-remote @@ -60,10 +60,10 @@ fi case "$state_should" in present) - echo yum $opts install \"$install_name\" + echo "yum $opts install \"$install_name\"" ;; absent) - echo yum $opts remove \"$name\" + echo "yum $opts remove \"$name\"" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote index d9372b6d..5b1b763e 100755 --- a/cdist/conf/type/__package_zypper/gencode-remote +++ b/cdist/conf/type/__package_zypper/gencode-remote @@ -61,15 +61,15 @@ case "$state_should" in present) if [ -z "$version_should" ]; then [ "$state_is" = "present" ] && exit 0 # if state is present, we dont need to do anything - echo zypper $globalopts install --type \"$ptype\" --auto-agree-with-licenses \"$name\" ">/dev/null" + echo "zypper $globalopts install --type \"$ptype\" --auto-agree-with-licenses \"$name\" >/dev/null" else [ "$state_is" = "present" ] && [ "$version_should" = "$version_is" ] && exit 0 # if state is present and version is correct, we dont need to do anything - echo zypper $globalopts install --oldpackage --type \"$ptype\" --auto-agree-with-licenses \"$name\" = \"$version_should\" ">/dev/null" + echo "zypper $globalopts install --oldpackage --type \"$ptype\" --auto-agree-with-licenses \"$name\" = \"$version_should\" >/dev/null" fi ;; absent) [ "$state_is" = "absent" ] && exit 0 # if state is absent, we dont need to do anything - echo zypper $globalopts remove --type \"$ptype\" \"$name\" ">/dev/null" + echo "zypper $globalopts remove --type \"$ptype\" \"$name\" >/dev/null" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__pacman_conf/manifest b/cdist/conf/type/__pacman_conf/manifest index 1561d613..a43f18a1 100755 --- a/cdist/conf/type/__pacman_conf/manifest +++ b/cdist/conf/type/__pacman_conf/manifest @@ -59,13 +59,13 @@ if [ "${file}" ]; then if [ "${state}" = "present" ]; then - require="__file/${sec_path}/plain_file_${file}" __key_value ${file}_${key}\ - --file ${sec_path}/plain_file_${file} --key ${key} --value ${value} --delimiter ' = ' + require="__file/${sec_path}/plain_file_${file}" __key_value "${file}_${key}" \ + --file "${sec_path}/plain_file_${file}" --key "${key}" --value "${value}" --delimiter ' = ' exit 0 elif [ "${state}" = "absent" ]; then - require="__file/${sec_path}/plain_file_${file}" __key_value ${file}_${key}\ + require="__file/${sec_path}/plain_file_${file}" __key_value "${file}_${key}" \ --state absent exit 0 @@ -87,19 +87,19 @@ eof if [ "${MATCH}" -eq 1 ]; then if [ "${value}" = "on" ]; then - require="__file/${sec_path}/${section}" __line ${key}_${value}\ - --file ${sec_path}/${section} --line ${key} + require="__file/${sec_path}/${section}" __line "${key}_${value}" \ + --file "${sec_path}/${section}" --line "${key}" elif [ "${value}" = "off" ]; then - require="__file/${sec_path}/${section}" __line ${key}_${value}\ - --file ${sec_path}/${section} --line ${key} --state absent + require="__file/${sec_path}/${section}" __line "${key}_${value}" \ + --file "${sec_path}/${section}" --line "${key}" --state absent fi else contains_element "${key}" "${allowed_option_keys}" if [ "${MATCH}" -eq 1 ]; then - require="__file/${sec_path}/${section}" __key_value ${section}_${key}\ - --file ${sec_path}/${section} --key ${key} --value ${value} --delimiter ' = ' + require="__file/${sec_path}/${section}" __key_value "${section}_${key}" \ + --file "${sec_path}/${section}" --key "${key}" --value "${value}" --delimiter ' = ' else echo "Key: ${key} is not valid. Have a look at man pacman.conf" >&2 fi @@ -118,12 +118,12 @@ eof exit fi - require="__file/${sec_path}/repo_${section}" __key_value ${section}_${key}\ - --file ${sec_path}/repo_${section} --key ${key} --value ${value} --delimiter ' = ' + require="__file/${sec_path}/repo_${section}" __key_value "${section}_${key}" \ + --file "${sec_path}/repo_${section}" --key "${key}" --value "${value}" --delimiter ' = ' elif [ "${state}" = "absent" ]; then - require="__file/${sec_path}/repo_${section}" __key_value ${section}_${key}\ + require="__file/${sec_path}/repo_${section}" __key_value "${section}_${key}" \ --state absent else diff --git a/cdist/conf/type/__pacman_conf_integrate/manifest b/cdist/conf/type/__pacman_conf_integrate/manifest index b26bca50..884af74d 100755 --- a/cdist/conf/type/__pacman_conf_integrate/manifest +++ b/cdist/conf/type/__pacman_conf_integrate/manifest @@ -18,16 +18,16 @@ # along with cdist. If not, see . # -state=$(cat $__object/parameter/state 2>/dev/null) +state=$(cat "$__object/parameter/state" 2>/dev/null) path="/etc/" if [ "${state}" = "present" ]; then __file /etc/pacman.conf\ - --owner root --group root --mode 644 --source $__type/files/pacman.conf.cdist + --owner root --group root --mode 644 --source "$__type/files/pacman.conf.cdist" __file /etc/pacman.d/options\ - --owner root --group root --mode 644 --source $__type/files/options + --owner root --group root --mode 644 --source "$__type/files/options" __file /etc/pacman.d/repo_empty_placeholder\ --owner root --group root --mode 644 @@ -38,10 +38,10 @@ if [ "${state}" = "present" ]; then elif [ "${state}" = "absent" ]; then __file /etc/pacman.conf\ - --owner root --group root --mode 644 --source $__type/files/pacman.conf.pacman + --owner root --group root --mode 644 --source "$__type/files/pacman.conf.pacman" __file /etc/pacman.d/mirrorlist\ - --owner root --group root --mode 644 --source $__type/files/mirrorlist + --owner root --group root --mode 644 --source "$__type/files/mirrorlist" __file /etc/pacman.d/options\ --state absent diff --git a/cdist/conf/type/__pf_apply/explorer/rcvar b/cdist/conf/type/__pf_apply/explorer/rcvar index 20e9dfcc..7c8d535f 100755 --- a/cdist/conf/type/__pf_apply/explorer/rcvar +++ b/cdist/conf/type/__pf_apply/explorer/rcvar @@ -29,7 +29,7 @@ RC="/etc/rc.conf" PFCONF="$(grep '^pf_rules=' ${RC} | cut -d= -f2 | sed 's/"//g')" -echo ${PFCONF:-"/etc/pf.conf"} +echo "${PFCONF:-"/etc/pf.conf"}" # Debug #set +x diff --git a/cdist/conf/type/__pf_ruleset/explorer/cksum b/cdist/conf/type/__pf_ruleset/explorer/cksum index f8679836..9be6c901 100755 --- a/cdist/conf/type/__pf_ruleset/explorer/cksum +++ b/cdist/conf/type/__pf_ruleset/explorer/cksum @@ -33,7 +33,7 @@ TMP="$(grep '^pf_rules=' ${RC} | cut -d= -f2 | sed 's/"//g')" PFCONF="${TMP:-"/etc/pf.conf"}" if [ -f "${PFCONF}" ]; then # The pf config file exists, find its cksum. - cksum -o 1 ${PFCONF} | cut -d= -f2 | awk '{print $1}' + cksum -o 1 "${PFCONF}" | cut -d= -f2 | awk '{print $1}' fi # Debug diff --git a/cdist/conf/type/__pf_ruleset/explorer/rcvar b/cdist/conf/type/__pf_ruleset/explorer/rcvar index 20e9dfcc..7c8d535f 100755 --- a/cdist/conf/type/__pf_ruleset/explorer/rcvar +++ b/cdist/conf/type/__pf_ruleset/explorer/rcvar @@ -29,7 +29,7 @@ RC="/etc/rc.conf" PFCONF="$(grep '^pf_rules=' ${RC} | cut -d= -f2 | sed 's/"//g')" -echo ${PFCONF:-"/etc/pf.conf"} +echo "${PFCONF:-"/etc/pf.conf"}" # Debug #set +x diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index 054e44cb..3f417526 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -57,7 +57,7 @@ __key_value alertmanager_args --file /etc/default/prometheus-alertmanager \ require="$require __directory/$storage_path $require_pkg" \ __config_file $CONF \ - --source $config \ + --source "$config" \ --group prometheus --mode 640 \ --onchange "service prometheus-alertmanager reload" # TODO when a config-check tool is available, check config here diff --git a/cdist/conf/type/__prometheus_exporter/manifest b/cdist/conf/type/__prometheus_exporter/manifest index ae4ed94a..35e654e2 100644 --- a/cdist/conf/type/__prometheus_exporter/manifest +++ b/cdist/conf/type/__prometheus_exporter/manifest @@ -2,7 +2,7 @@ export GOBIN=/opt/gocode/bin # where to find go binaries -exporter="$(cat $__object/parameter/exporter)" +exporter="$(cat "$__object/parameter/exporter")" [ -z "$exporter" ] && exporter="$__object_id" __user prometheus --system @@ -18,7 +18,7 @@ case $exporter in ;; blackbox) require="$require __daemontools_service/${exporter}-exporter __user/prometheus" __config_file "/service/${exporter}-exporter/blackbox.yml" \ - --source $__type/files/blackbox.yml \ + --source "$__type/files/blackbox.yml" \ --group prometheus --mode 640 \ --onchange "svc -h /service/${exporter}-exporter" require="$require __golang_from_vendor" __go_get github.com/prometheus/blackbox_exporter @@ -39,9 +39,9 @@ case $exporter in ;; esac -require="$require __daemontools" __daemontools_service ${exporter}-exporter --run "$run" +require="$require __daemontools" __daemontools_service "${exporter}-exporter" --run "$run" if [ -f "$__object/parameter/add-consul-service" ]; then - __consul_service ${exporter}-exporter --port $port --check-http "http://localhost:$port/metrics" --check-interval 10s + __consul_service "${exporter}-exporter" --port "$port" --check-http "http://localhost:$port/metrics" --check-interval 10s fi #__daemontools --install-init-script diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index e2f32fd5..63b7b438 100755 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -13,7 +13,7 @@ storage_path="$(cat "$__object/parameter/storage-path")" rule_files="$(cat "$__object/parameter/rule-files")" # explorer in kB => convert; by default we go with 1/2 RAM -[ "$target_heap_size" = "auto" ] && target_heap_size=$(($(cat $__global/explorer/memory)*1024/2)) +[ "$target_heap_size" = "auto" ] && target_heap_size=$(($(cat "$__global/explorer/memory")*1024/2)) ##### INSTALL THE PACKAGE ################################################### @@ -55,12 +55,12 @@ __key_value prometheus_args --file /etc/default/prometheus \ require="$require __directory/$storage_path $require_pkg" \ __config_file $CONF \ - --source $config \ + --source "$config" \ --group prometheus --mode 640 \ --onchange "promtool check config $CONF && service prometheus reload" for file in $rule_files; do - dest=$CONF_DIR/$(basename $file) + dest=$CONF_DIR/$(basename "$file") require="$require $require_pkg" \ __config_file "$dest" \ --source "$file" \ diff --git a/cdist/conf/type/__pyvenv/explorer/group b/cdist/conf/type/__pyvenv/explorer/group index ff072c5e..a655bda7 100755 --- a/cdist/conf/type/__pyvenv/explorer/group +++ b/cdist/conf/type/__pyvenv/explorer/group @@ -2,4 +2,4 @@ destination="/$__object_id" -stat --print "%G" ${destination} 2>/dev/null || exit 0 +stat --print "%G" "${destination}" 2>/dev/null || exit 0 diff --git a/cdist/conf/type/__pyvenv/explorer/owner b/cdist/conf/type/__pyvenv/explorer/owner index b77e3c6e..8b3c7f8e 100755 --- a/cdist/conf/type/__pyvenv/explorer/owner +++ b/cdist/conf/type/__pyvenv/explorer/owner @@ -2,4 +2,4 @@ destination="/$__object_id" -stat --print "%U" ${destination} 2>/dev/null || exit 0 +stat --print "%U" "${destination}" 2>/dev/null || exit 0 diff --git a/cdist/conf/type/__pyvenv/gencode-remote b/cdist/conf/type/__pyvenv/gencode-remote index 4cba5987..04700683 100755 --- a/cdist/conf/type/__pyvenv/gencode-remote +++ b/cdist/conf/type/__pyvenv/gencode-remote @@ -47,7 +47,7 @@ fi case $state_should in present) if [ "$state_should" != "$state_is" ]; then - echo $pyvenv $venvparams "$destination" + echo "$pyvenv $venvparams $destination" fi if { [ -n "$owner" ] && [ "$owner_is" != "$owner" ]; } || \ { [ -n "$group" ] && [ "$group_is" != "$group" ]; }; then diff --git a/cdist/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote index 9127e5ef..95d07b7a 100755 --- a/cdist/conf/type/__qemu_img/gencode-remote +++ b/cdist/conf/type/__qemu_img/gencode-remote @@ -18,4 +18,4 @@ format="$(cat "$__object/parameter/format")" size="$(cat "$__object/parameter/size")" diskimage="/$__object_id" -echo qemu-img create -f \"$format\" \"$diskimage\" \"$size\" +echo "qemu-img create -f \"$format\" \"$diskimage\" \"$size\"" diff --git a/cdist/conf/type/__rsync/gencode-local b/cdist/conf/type/__rsync/gencode-local index 155f3a3a..c7196175 100755 --- a/cdist/conf/type/__rsync/gencode-local +++ b/cdist/conf/type/__rsync/gencode-local @@ -31,7 +31,7 @@ set -- if [ -f "$__object/parameter/rsync-opts" ]; then while read opts; do set -- "$@" "--$opts" - done < $__object/parameter/rsync-opts + done < "$__object/parameter/rsync-opts" fi echo rsync -a \ diff --git a/cdist/conf/type/__rvm/explorer/state b/cdist/conf/type/__rvm/explorer/state index f43f5509..74d17048 100755 --- a/cdist/conf/type/__rvm/explorer/state +++ b/cdist/conf/type/__rvm/explorer/state @@ -28,7 +28,7 @@ if [ "$user" = "root" ]; then echo absent fi else - if su - $user -c "[ -d \"\$HOME/.rvm\" ]" ; then + if su - "$user" -c "[ -d \"\$HOME/.rvm\" ]" ; then echo "present" else echo "absent" diff --git a/cdist/conf/type/__ssh_authorized_key/explorer/entry b/cdist/conf/type/__ssh_authorized_key/explorer/entry index 157d70f1..b528b26e 100755 --- a/cdist/conf/type/__ssh_authorized_key/explorer/entry +++ b/cdist/conf/type/__ssh_authorized_key/explorer/entry @@ -24,7 +24,7 @@ type_and_key="$(tr ' ' '\n' < "$__object/parameter/key"| awk '/^(ssh|ecdsa)-[^ ] # in greping everything in file and all entries from file are removed. if [ -n "${type_and_key}" ] then - file="$(cat $__object/parameter/file)" + file="$(cat "$__object/parameter/file")" # get any entries that match the type and key grep ".*$type_and_key\([ \n]\|$\)" "$file" || true diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index 333dfa03..325854c2 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -88,7 +88,7 @@ fi entry="$(cat "$__object/files/should")" state_should="$(cat "$__object/parameter/state")" num_existing_entries=$(grep -c -F -x "$entry" "$__object/explorer/entry" || true) -if [ $num_existing_entries -eq 1 ]; then +if [ "$num_existing_entries" -eq 1 ]; then state_is="present" else # Posix grep does not define the -m option, so we can not remove a single diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 14ee7dab..0ecea85b 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -59,11 +59,11 @@ case "$state_should" in ;; gentoo) - echo rc-update add \"$name\" \"$target_runlevel\" + echo "rc-update add \"$name\" \"$target_runlevel\"" ;; amazon|scientific|centos|fedora|owl|redhat|suse) - echo chkconfig \"$name\" on + echo "chkconfig \"$name\" on" ;; openwrt) @@ -98,15 +98,15 @@ case "$state_should" in else case "$os" in debian|ubuntu|devuan) - echo update-rc.d -f \"$name\" remove + echo "update-rc.d -f \"$name\" remove" ;; gentoo) - echo rc-update del \"$name\" \"$target_runlevel\" + echo "rc-update del \"$name\" \"$target_runlevel\"" ;; centos|fedora|owl|redhat|suse) - echo chkconfig \"$name\" off + echo "chkconfig \"$name\" off" ;; openwrt) diff --git a/cdist/conf/type/__start_on_boot/manifest b/cdist/conf/type/__start_on_boot/manifest index b9ee20e2..c1c983ec 100644 --- a/cdist/conf/type/__start_on_boot/manifest +++ b/cdist/conf/type/__start_on_boot/manifest @@ -16,7 +16,7 @@ case "$os" in else value='NO' fi - __key_value rcconf-$name-enable \ + __key_value "rcconf-$name-enable" \ --file /etc/rc.conf \ --key "${name}_enable" \ --value "\"$value\"" \ diff --git a/cdist/conf/type/__user/explorer/shadow b/cdist/conf/type/__user/explorer/shadow index 1e6658d4..c49992d5 100755 --- a/cdist/conf/type/__user/explorer/shadow +++ b/cdist/conf/type/__user/explorer/shadow @@ -22,7 +22,7 @@ # name=$__object_id -os="$($__explorer/os)" +os="$("$__explorer/os")" # Default to using shadow passwords database="shadow" diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index 332e93f1..23f01114 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -97,7 +97,7 @@ if [ "$state" = "present" ]; then fi if [ "$new_value" != "$current_value" ]; then - set -- "$@" "$(shorten_property $property)" \'$new_value\' + set -- "$@" "$(shorten_property "$property")" \'"$new_value"\' fi done @@ -118,9 +118,9 @@ if [ "$state" = "present" ]; then [ "$property" = "remove-home" ] && continue new_value="$(cat "$property")" if [ -z "$new_value" ];then # Boolean values have no value - set -- "$@" "$(shorten_property $property)" + set -- "$@" "$(shorten_property "$property")" else - set -- "$@" "$(shorten_property $property)" \'$new_value\' + set -- "$@" "$(shorten_property "$property")" \'"$new_value"\' fi done diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index 94c3f146..b8eeef0f 100755 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -70,25 +70,25 @@ case "$state" in fi if [ -z "$repo_id" ]; then # Repo not present, so we need to create it - echo zypper $zypper_def_opts addrepo "'$uri'" "'$desc'" + echo "zypper $zypper_def_opts addrepo '$uri' '$desc'" fi ;; absent) if [ ! -z "$act_id" ]; then # Repo present (act_id not ""), so we ned to delete it - echo zypper $zypper_def_opts removerepo "$act_id" + echo "zypper $zypper_def_opts removerepo $act_id" fi ;; enabled) if [ ! -z "$act_id" ] && [ "$repostate" = "disabled" ]; then # Repo present (act_id not "") and repostate not enabled, so a enable call is needed - echo zypper $zypper_def_opts modifyrepo -e "$act_id" + echo "zypper $zypper_def_opts modifyrepo -e $act_id" fi ;; disabled) if [ ! -z "$act_id" ] && [ "$repostate" = "enabled" ]; then # Repo present (act_id not "") and repostate enabled, so a disable call is needed - echo zypper $zypper_def_opts modifyrepo -d "$act_id" + echo "zypper $zypper_def_opts modifyrepo -d $act_id" fi ;; *) diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri index b8de0dcd..2476ab71 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_uri +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -25,4 +25,4 @@ if [ -f "$__object/parameter/uri" ]; then else uri="/$__object_id" fi -zypper ls -u | awk 'BEGIN { FS = "[ ]+\\|[ ]+" } ; $4 == "Yes" && $NF == "'$uri'" {print $NF}' +zypper ls -u | awk 'BEGIN { FS = "[ ]+\\|[ ]+" } ; $4 == "Yes" && $NF == "'"$uri"'" {print $NF}' diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote index 955698d1..6701347f 100755 --- a/cdist/conf/type/__zypper_service/gencode-remote +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -59,10 +59,10 @@ if [ -f "$__object/parameter/remove-all-other-services" ]; then # file exists -> True for i in $exp_ids; do if [ "$i" != "$exp_id" ] ; then - echo zypper $zypper_def_opts removeservice "$i" "&>/dev/null" + echo "zypper $zypper_def_opts removeservice $i &>/dev/null" fi done - echo zypper $zypper_def_opts refs "&>/dev/null" + echo "zypper $zypper_def_opts refs &>/dev/null" fi @@ -71,14 +71,14 @@ fi case "$state_should" in present) - echo zypper $zypper_def_opts addservice -t "$stype" "$uri" \"$desc\" - echo zypper $zypper_def_opts refs - echo zypper $zypper_def_opts ref + echo "zypper $zypper_def_opts addservice -t $stype $uri \"$desc\"" + echo "zypper $zypper_def_opts refs" + echo "zypper $zypper_def_opts ref" ;; absent) - echo zypper $zypper_def_opts removeservice "$service_id" - echo zypper $zypper_def_opts refs - echo zypper $zypper_def_opts ref + echo "zypper $zypper_def_opts removeservice $service_id" + echo "zypper $zypper_def_opts refs" + echo "zypper $zypper_def_opts ref" ;; *) echo "Unknown state: $state_should" >&2 From 53728a7ff0c1ac16d7dddb827915390d2c59abe9 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Wed, 3 Oct 2018 19:38:47 +0200 Subject: [PATCH 0899/1332] Change backslash-dquote to single quote Slightly breaking change, but improves security and readability. --- cdist/conf/type/__apt_ppa/gencode-remote | 4 +-- .../type/__ccollect_source/gencode-remote | 14 +++++----- cdist/conf/type/__directory/gencode-remote | 18 ++++++------- cdist/conf/type/__file/gencode-remote | 14 +++++----- .../conf/type/__firewalld_rule/gencode-remote | 8 +++--- .../gencode-remote | 2 +- cdist/conf/type/__package_apt/gencode-remote | 4 +-- .../conf/type/__package_emerge/gencode-remote | 4 +-- .../type/__package_luarocks/gencode-remote | 4 +-- cdist/conf/type/__package_opkg/gencode-remote | 4 +-- .../conf/type/__package_pacman/gencode-remote | 4 +-- cdist/conf/type/__package_pip/gencode-remote | 4 +-- .../type/__package_rubygem/gencode-remote | 4 +-- cdist/conf/type/__package_yum/gencode-remote | 4 +-- .../conf/type/__package_zypper/gencode-remote | 6 ++--- cdist/conf/type/__qemu_img/gencode-remote | 2 +- .../conf/type/__start_on_boot/gencode-remote | 26 +++++++++---------- .../conf/type/__zypper_service/gencode-remote | 2 +- 18 files changed, 64 insertions(+), 64 deletions(-) diff --git a/cdist/conf/type/__apt_ppa/gencode-remote b/cdist/conf/type/__apt_ppa/gencode-remote index 25dec58d..84ebebfe 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 '$name'" ;; absent) - echo "remove-apt-repository \"$name\"" + echo "remove-apt-repository '$name'" ;; esac diff --git a/cdist/conf/type/__ccollect_source/gencode-remote b/cdist/conf/type/__ccollect_source/gencode-remote index 5f2f97e3..5daa3fd3 100755 --- a/cdist/conf/type/__ccollect_source/gencode-remote +++ b/cdist/conf/type/__ccollect_source/gencode-remote @@ -42,18 +42,18 @@ get_current_value() { } set_group() { - echo chgrp \""$1"\" \""$destination"\" - echo chgrp "$1" >> "$__messages_out" + echo "chgrp '$1' '$destination'" + echo "chgrp '$1'" >> "$__messages_out" } set_owner() { - echo chown \""$1"\" \""$destination"\" - echo chown "$1" >> "$__messages_out" + echo "chown '$1' '$destination'" + echo "chown '$1'" >> "$__messages_out" } set_mode() { - echo chmod \""$1"\" \""$destination"\" - echo chmod "$1" >> "$__messages_out" + echo "chmod '$1' '$destination'" + echo "chmod '$1'" >> "$__messages_out" } set_attributes= @@ -81,7 +81,7 @@ case "$state_should" in absent) if [ "$type" = "file" ]; then - echo rm -f \""$destination"\" + echo "rm -f '$destination'" echo remove >> "$__messages_out" fi ;; diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index 35866eb4..4220c6fb 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -57,18 +57,18 @@ get_current_value() { } set_group() { - echo chgrp "$recursive" \""$1"\" \""$destination"\" - echo chgrp "$recursive" "$1" >> "$__messages_out" + echo "chgrp '$recursive' '$1' '$destination'" + echo "chgrp '$recursive' '$1'" >> "$__messages_out" } set_owner() { - echo chown "$recursive" \""$1"\" \""$destination"\" - echo chown "$recursive" "$1" >> "$__messages_out" + echo "chown '$recursive' '$1' '$destination'" + echo "chown '$recursive' '$1'" >> "$__messages_out" } set_mode() { - echo chmod "$recursive" \""$1"\" \""$destination"\" - echo chmod "$recursive" "$1" >> "$__messages_out" + echo "chmod '$recursive' '$1' '$destination'" + echo "chmod '$recursive' '$1'" >> "$__messages_out" } case "$state_should" in @@ -78,10 +78,10 @@ case "$state_should" in if [ "$type" != "none" ]; then # our destination is not a directory, remove whatever is there # and then create our directory and set all attributes - echo rm -f "\"$destination\"" + echo "rm -f '$destination'" echo "remove non directory" >> "$__messages_out" fi - echo "mkdir $mkdiropt \"$destination\"" + echo "mkdir $mkdiropt '$destination'" echo "create" >> "$__messages_out" fi @@ -105,7 +105,7 @@ case "$state_should" in ;; absent) if [ "$type" = "directory" ]; then - echo rm -rf \""$destination"\" + echo "rm -rf '$destination'" echo remove >> "$__messages_out" fi ;; diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index ebc30fd9..ab9c2fd1 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -43,18 +43,18 @@ get_current_value() { } set_group() { - echo chgrp \""$1"\" \""$destination"\" - echo chgrp "$1" >> "$__messages_out" + echo "chgrp '$1' '$destination'" + echo "chgrp '$1'" >> "$__messages_out" } set_owner() { - echo chown \""$1"\" \""$destination"\" - echo chown "$1" >> "$__messages_out" + echo "chown '$1' '$destination'" + echo "chown '$1'" >> "$__messages_out" } set_mode() { - echo chmod \""$1"\" \""$destination"\" - echo chmod "$1" >> "$__messages_out" + echo "chmod '$1' '$destination'" + echo "chmod '$1'" >> "$__messages_out" } set_attributes= @@ -82,7 +82,7 @@ case "$state_should" in absent) if [ "$type" = "file" ]; then - echo rm -f \""$destination"\" + echo "rm -f '$destination'" echo remove >> "$__messages_out" fi ;; diff --git a/cdist/conf/type/__firewalld_rule/gencode-remote b/cdist/conf/type/__firewalld_rule/gencode-remote index bc218d9a..225a0502 100755 --- a/cdist/conf/type/__firewalld_rule/gencode-remote +++ b/cdist/conf/type/__firewalld_rule/gencode-remote @@ -33,13 +33,13 @@ rule="$(cat "$__object/parameter/rule")" case "$state_should" in present) - echo "firewall-cmd --quiet --permanent --direct --add-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule" - echo "firewall-cmd --quiet --direct --add-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule" + echo "firewall-cmd --quiet --permanent --direct --add-rule '$protocol' '$table' '$chain' '$priority' $rule" + echo "firewall-cmd --quiet --direct --add-rule '$protocol' '$table' '$chain' '$priority' $rule" ;; absent) - echo "firewall-cmd --quiet --permanent --direct --remove-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule" - echo "firewall-cmd --quiet --direct --remove-rule \"$protocol\" \"$table\" \"$chain\" \"$priority\" $rule" + echo "firewall-cmd --quiet --permanent --direct --remove-rule '$protocol' '$table' '$chain' '$priority' $rule" + echo "firewall-cmd --quiet --direct --remove-rule '$protocol' '$table' '$chain' '$priority' $rule" ;; *) echo "Unknown state $state_should" >&2 diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index b8100c52..644de33c 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -85,7 +85,7 @@ primary_count=0 for object in $objects; do device="$(cat "$object/parameter/device")" if [ "$current_device" != "$device" ]; then - echo "create_disklabel \"$device\" || die 'Failed to create disklabel for $device'" + echo "create_disklabel '$device' || die 'Failed to create disklabel for $device'" current_device="$device" device_name=$(echo "${device}" | sed -e 's:^/dev/::;s:/:\\/:g') available_device_size=$(( $(awk "/${device_name}\$/ { print \$3; }" "$partitions") / 1024)) diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index cbe14787..699eb0c9 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -77,11 +77,11 @@ case "$state_should" in if [ -n "$version" ]; then name="${name}=${version}" fi - echo "$aptget install $target_release \"$name\"" + echo "$aptget install $target_release '$name'" echo "installed" >> "$__messages_out" ;; absent) - echo "$aptget remove $purgeparam \"$name\"" + echo "$aptget remove $purgeparam '$name'" echo "removed" >> "$__messages_out" ;; *) diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote index ada2b414..8abcb5b1 100755 --- a/cdist/conf/type/__package_emerge/gencode-remote +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -63,10 +63,10 @@ fi case "$state_should" in present) - echo "emerge \"$name\" &>/dev/null || exit 1" + echo "emerge '$name' &>/dev/null || exit 1" ;; absent) - echo "emerge -C \"$name\" &>/dev/null || exit 1" + echo "emerge -C '$name' &>/dev/null || exit 1" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_luarocks/gencode-remote b/cdist/conf/type/__package_luarocks/gencode-remote index e14d7a8e..60b9bfea 100755 --- a/cdist/conf/type/__package_luarocks/gencode-remote +++ b/cdist/conf/type/__package_luarocks/gencode-remote @@ -42,10 +42,10 @@ fi case "$state_should" in present) - echo luarocks install \""$name"\" + echo "luarocks install '$name'" ;; absent) - echo luarocks remove \""$name"\" + echo "luarocks remove '$name'" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_opkg/gencode-remote b/cdist/conf/type/__package_opkg/gencode-remote index 53f154a5..7013ec9f 100755 --- a/cdist/conf/type/__package_opkg/gencode-remote +++ b/cdist/conf/type/__package_opkg/gencode-remote @@ -45,10 +45,10 @@ case "$state_should" in if [ "$present" = "notpresent" ]; then echo opkg --verbosity=0 update fi - echo opkg --verbosity=0 install \""$name"\" + echo "opkg --verbosity=0 install '$name'" ;; absent) - echo opkg --verbosity=0 remove \""$name"\" + echo "opkg --verbosity=0 remove '$name'" ;; *) echo "Unknown state: $state" >&2 diff --git a/cdist/conf/type/__package_pacman/gencode-remote b/cdist/conf/type/__package_pacman/gencode-remote index 43649124..7ba85479 100755 --- a/cdist/conf/type/__package_pacman/gencode-remote +++ b/cdist/conf/type/__package_pacman/gencode-remote @@ -45,10 +45,10 @@ fi case "$state_should" in present) - echo pacman --needed --noconfirm --noprogressbar -S \""$name"\" + echo "pacman --needed --noconfirm --noprogressbar -S '$name'" ;; absent) - echo pacman --noconfirm --noprogressbar -R \""$name"\" + echo "pacman --noconfirm --noprogressbar -R '$name'" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_pip/gencode-remote b/cdist/conf/type/__package_pip/gencode-remote index 933406f2..33556bec 100755 --- a/cdist/conf/type/__package_pip/gencode-remote +++ b/cdist/conf/type/__package_pip/gencode-remote @@ -53,7 +53,7 @@ case "$state_should" in present) if [ "$runas" ] then - echo "su -c \"$pip install -q $name\" $runas" + echo "su -c '$pip install -q $name' $runas" else echo $pip install -q "$name" fi @@ -61,7 +61,7 @@ case "$state_should" in absent) if [ "$runas" ] then - echo "su -c \"$pip uninstall -q -y $name\" $runas" + echo "su -c '$pip uninstall -q -y $name' $runas" else echo $pip uninstall -q -y "$name" fi diff --git a/cdist/conf/type/__package_rubygem/gencode-remote b/cdist/conf/type/__package_rubygem/gencode-remote index d474db20..ee563ef8 100755 --- a/cdist/conf/type/__package_rubygem/gencode-remote +++ b/cdist/conf/type/__package_rubygem/gencode-remote @@ -39,10 +39,10 @@ fi case "$state_should" in present) - echo gem install \""$name"\" --no-ri --no-rdoc + echo "gem install '$name' --no-ri --no-rdoc" ;; absent) - echo gem uninstall \""$name"\" + echo "gem uninstall '$name'" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote index d860c48c..97265827 100755 --- a/cdist/conf/type/__package_yum/gencode-remote +++ b/cdist/conf/type/__package_yum/gencode-remote @@ -60,10 +60,10 @@ fi case "$state_should" in present) - echo "yum $opts install \"$install_name\"" + echo "yum $opts install '$install_name'" ;; absent) - echo "yum $opts remove \"$name\"" + echo "yum $opts remove '$name'" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote index 5b1b763e..1f15c531 100755 --- a/cdist/conf/type/__package_zypper/gencode-remote +++ b/cdist/conf/type/__package_zypper/gencode-remote @@ -61,15 +61,15 @@ case "$state_should" in present) if [ -z "$version_should" ]; then [ "$state_is" = "present" ] && exit 0 # if state is present, we dont need to do anything - echo "zypper $globalopts install --type \"$ptype\" --auto-agree-with-licenses \"$name\" >/dev/null" + echo "zypper $globalopts install --type '$ptype' --auto-agree-with-licenses '$name' >/dev/null" else [ "$state_is" = "present" ] && [ "$version_should" = "$version_is" ] && exit 0 # if state is present and version is correct, we dont need to do anything - echo "zypper $globalopts install --oldpackage --type \"$ptype\" --auto-agree-with-licenses \"$name\" = \"$version_should\" >/dev/null" + echo "zypper $globalopts install --oldpackage --type '$ptype' --auto-agree-with-licenses '$name' = '$version_should' >/dev/null" fi ;; absent) [ "$state_is" = "absent" ] && exit 0 # if state is absent, we dont need to do anything - echo "zypper $globalopts remove --type \"$ptype\" \"$name\" >/dev/null" + echo "zypper $globalopts remove --type '$ptype' '$name' >/dev/null" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote index 95d07b7a..94816f58 100755 --- a/cdist/conf/type/__qemu_img/gencode-remote +++ b/cdist/conf/type/__qemu_img/gencode-remote @@ -18,4 +18,4 @@ format="$(cat "$__object/parameter/format")" size="$(cat "$__object/parameter/size")" diskimage="/$__object_id" -echo "qemu-img create -f \"$format\" \"$diskimage\" \"$size\"" +echo "qemu-img create -f '$format' '$diskimage' '$size'" diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 0ecea85b..122692ec 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -37,16 +37,16 @@ case "$state_should" in if [ "$init" = 'systemd' ]; then # this handles ALL linux distros with systemd # e.g. archlinux, gentoo in some cases, new RHEL and SLES versions - echo "systemctl -q enable \"$name\"" + echo "systemctl -q enable '$name'" else case "$os" in debian) case "$os_version" in [1-7]*) - echo "update-rc.d \"$name\" defaults >/dev/null" + echo "update-rc.d '$name' defaults >/dev/null" ;; 8*) - echo "systemctl enable \"$name\"" + echo "systemctl enable '$name'" ;; *) echo "Unsupported version $os_version of $os" >&2 @@ -55,26 +55,26 @@ case "$state_should" in esac ;; devuan) - echo "update-rc.d \"$name\" defaults >/dev/null" + echo "update-rc.d '$name' defaults >/dev/null" ;; gentoo) - echo "rc-update add \"$name\" \"$target_runlevel\"" + echo "rc-update add '$name' '$target_runlevel'" ;; amazon|scientific|centos|fedora|owl|redhat|suse) - echo "chkconfig \"$name\" on" + echo "chkconfig '$name' on" ;; openwrt) # 'enable' can be successful and still return a non-zero exit # code, deal with it by checking for success ourselves in that # case (the || ... part). - echo "/etc/init.d/\"$name\" enable || [ -f /etc/rc.d/S??\"$name\" ]" + echo "'/etc/init.d/$name' enable || [ -f /etc/rc.d/S??'$name' ]" ;; ubuntu) - echo "update-rc.d \"$name\" defaults >/dev/null" + echo "update-rc.d '$name' defaults >/dev/null" ;; freebsd) @@ -93,24 +93,24 @@ case "$state_should" in if [ "$init" = 'systemd' ]; then # this handles ALL linux distros with systemd # e.g. archlinux, gentoo in some cases, new RHEL and SLES versions - echo "systemctl -q disable \"$name\"" + echo "systemctl -q disable '$name'" else case "$os" in debian|ubuntu|devuan) - echo "update-rc.d -f \"$name\" remove" + echo "update-rc.d -f '$name' remove" ;; gentoo) - echo "rc-update del \"$name\" \"$target_runlevel\"" + echo "rc-update del '$name' '$target_runlevel'" ;; centos|fedora|owl|redhat|suse) - echo "chkconfig \"$name\" off" + echo "chkconfig '$name' off" ;; openwrt) - echo "\"/etc/init.d/$name\" disable" + echo "'/etc/init.d/$name' disable" ;; *) diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote index 6701347f..59ffc942 100755 --- a/cdist/conf/type/__zypper_service/gencode-remote +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -71,7 +71,7 @@ fi case "$state_should" in present) - echo "zypper $zypper_def_opts addservice -t $stype $uri \"$desc\"" + echo "zypper $zypper_def_opts addservice -t $stype $uri '$desc'" echo "zypper $zypper_def_opts refs" echo "zypper $zypper_def_opts ref" ;; From fff656d1acc596646249eb31903b5bcbb6003caf Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 4 Oct 2018 19:28:36 +0200 Subject: [PATCH 0900/1332] Unquote $recursive to support empty-case This is safe to do, as the value of $recursive is not dependent on user-supplied code. --- cdist/conf/type/__directory/gencode-remote | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index 4220c6fb..374db47a 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -57,18 +57,18 @@ get_current_value() { } set_group() { - echo "chgrp '$recursive' '$1' '$destination'" - echo "chgrp '$recursive' '$1'" >> "$__messages_out" + echo "chgrp $recursive '$1' '$destination'" + echo "chgrp $recursive '$1'" >> "$__messages_out" } set_owner() { - echo "chown '$recursive' '$1' '$destination'" - echo "chown '$recursive' '$1'" >> "$__messages_out" + echo "chown $recursive '$1' '$destination'" + echo "chown $recursive '$1'" >> "$__messages_out" } set_mode() { - echo "chmod '$recursive' '$1' '$destination'" - echo "chmod '$recursive' '$1'" >> "$__messages_out" + echo "chmod $recursive '$1' '$destination'" + echo "chmod $recursive '$1'" >> "$__messages_out" } case "$state_should" in From e2593c0dcbababa2d0f0cb1fd0d29dbbb5da24bb Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 4 Oct 2018 21:23:12 +0200 Subject: [PATCH 0901/1332] Fix SC2215 (missing brackets on if) This might have never worked as intended, but how would you know? --- cdist/conf/type/__rvm_gemset/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__rvm_gemset/gencode-remote b/cdist/conf/type/__rvm_gemset/gencode-remote index 78851f9a..3cdc66a6 100755 --- a/cdist/conf/type/__rvm_gemset/gencode-remote +++ b/cdist/conf/type/__rvm_gemset/gencode-remote @@ -33,7 +33,7 @@ case "$state_should" in cat << DONE su - "$user" -c "source ~/.rvm/scripts/rvm; rvm $gemset --create" DONE - if -f "$__object/parameter/default"; then + if [ -f "$__object/parameter/default" ]; then cat << DONE su - "$user" -c "source ~/.rvm/scripts/rvm; rvm use --default $gemset" DONE From a6fdf4255aa877850890330c91d9330617b99fb3 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 4 Oct 2018 21:17:31 +0200 Subject: [PATCH 0902/1332] Fix SC2069 (wrong stdout/stderr redirect order) In the original order, stderr was connected to the old stdout (terminal). This was _probably_ not intended. The new order fixes this by first connecting stdout to /dev/null and then attaching stderr to that as well. --- cdist/conf/explorer/machine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/explorer/machine b/cdist/conf/explorer/machine index d4a0e106..7ecb67e3 100755 --- a/cdist/conf/explorer/machine +++ b/cdist/conf/explorer/machine @@ -22,6 +22,6 @@ # # -if command -v uname 2>&1 >/dev/null; then +if command -v uname >/dev/null 2>&1 ; then uname -m fi From a0db375f91bad2e288a36ce298146e22672718d9 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 4 Oct 2018 21:30:28 +0200 Subject: [PATCH 0903/1332] Disable SC2059 (printf injection) for staged_file We're explicitly allowing for 'printf injection' here, so it's ok to just disable the corresponding shellcheck check. --- cdist/conf/type/__staged_file/gencode-local | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdist/conf/type/__staged_file/gencode-local b/cdist/conf/type/__staged_file/gencode-local index 18bf09f5..c0d94e92 100755 --- a/cdist/conf/type/__staged_file/gencode-local +++ b/cdist/conf/type/__staged_file/gencode-local @@ -57,6 +57,7 @@ get_file() { } fetch_file() { + # shellcheck disable=SC2059 printf "$fetch_command" "$source" printf ' > "%s"\n' "$stage_file" } @@ -64,8 +65,10 @@ fetch_file() { fetch_and_prepare_file() { printf 'tmpdir="$(mktemp -d --tmpdir="/tmp" "%s")"\n' "${__type##*/}.XXXXXXXXXX" printf 'cd "$tmpdir"\n' + # shellcheck disable=SC2059 printf "$fetch_command > \"%s\"\n" "$source" "$source_file_name" prepare_command="$(cat "$__object/parameter/prepare-command")" + # shellcheck disable=SC2059 printf "$prepare_command > \"%s\"\n" "$source_file_name" "$stage_file" printf 'cd - >/dev/null\n' printf 'rm -rf "$tmpdir"\n' From bcd7fbbcc48b72eb0f5ec378f0555428a0dac8d8 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 4 Oct 2018 22:01:25 +0200 Subject: [PATCH 0904/1332] Fix SC2155 (directly export computed variables) --- cdist/conf/type/__key_value/explorer/state | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__key_value/explorer/state b/cdist/conf/type/__key_value/explorer/state index b990733d..7b2de1df 100755 --- a/cdist/conf/type/__key_value/explorer/state +++ b/cdist/conf/type/__key_value/explorer/state @@ -19,9 +19,9 @@ # along with cdist. If not, see . # -export key="$(cat "$__object/parameter/key" 2>/dev/null \ +key="$(cat "$__object/parameter/key" 2>/dev/null \ || echo "$__object_id")" -export state="$(cat "$__object/parameter/state")" +state="$(cat "$__object/parameter/state")" file="$(cat "$__object/parameter/file")" @@ -30,14 +30,15 @@ if [ ! -f "$file" ]; then exit fi -export delimiter="$(cat "$__object/parameter/delimiter")" -export value="$(cat "$__object/parameter/value" 2>/dev/null \ +delimiter="$(cat "$__object/parameter/delimiter")" +value="$(cat "$__object/parameter/value" 2>/dev/null \ || echo "__CDIST_NOTSET__")" if [ -f "$__object/parameter/exact_delimiter" ]; then - export exact_delimiter=1 + exact_delimiter=1 else - export exact_delimiter=0 + exact_delimiter=0 fi +export key state delimiter value exact_delimiter awk -f - "$file" <<"AWK_EOF" BEGIN { From 34b571b7d9d98451910650339231c3c3c06cfb61 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 4 Oct 2018 22:22:22 +0200 Subject: [PATCH 0905/1332] Fix SC2091 (execute result of condition) For some reason, the echo|grep pattern was enclosed four times in a $() operation. Nothing happened, since grep is always invoked with -q (quiet, nothing printed to stdout). --- cdist/conf/type/__file/gencode-local | 2 +- cdist/conf/type/__jail_freebsd10/gencode-local | 2 +- cdist/conf/type/__jail_freebsd9/gencode-local | 2 +- cdist/conf/type/__user/gencode-remote | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 3f60b4b3..fb9f9a92 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -84,7 +84,7 @@ DONE if [ "$upload_file" ]; then echo upload >> "$__messages_out" # IPv6 fix - if $(echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$') + if echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' then my_target_host="[${__target_host}]" else diff --git a/cdist/conf/type/__jail_freebsd10/gencode-local b/cdist/conf/type/__jail_freebsd10/gencode-local index b2016f86..f163cad3 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-local +++ b/cdist/conf/type/__jail_freebsd10/gencode-local @@ -44,7 +44,7 @@ basepresent="$(cat "$__object/explorer/basepresent")" if [ "$state" = "present" ]; then if [ "$basepresent" = "NONE" ]; then # IPv6 fix - if $(echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$') + if echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' then my_target_host="[${__target_host}]" else diff --git a/cdist/conf/type/__jail_freebsd9/gencode-local b/cdist/conf/type/__jail_freebsd9/gencode-local index 1ab7ff1a..bbdc9fcc 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-local +++ b/cdist/conf/type/__jail_freebsd9/gencode-local @@ -40,7 +40,7 @@ basepresent="$(cat "$__object/explorer/basepresent")" if [ "$state" = "present" ]; then if [ "$basepresent" = "NONE" ]; then # IPv6 fix - if $(echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$') + if echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$' then my_target_host="[${__target_host}]" else diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index 332e93f1..a1347a6f 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -60,7 +60,7 @@ if [ "$state" = "present" ]; then case "$property" in gid) - if $(echo "$new_value" | grep -q '^[0-9][0-9]*$'); then + if echo "$new_value" | grep -q '^[0-9][0-9]*$'; then field=4 else # We were passed a group name. Compare the gid in From 738f0538775ae182e10ae90c56a38af094ba7063 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 4 Oct 2018 22:39:06 +0200 Subject: [PATCH 0906/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 1405ad3c..151b11e5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -11,6 +11,9 @@ next: * Explorers and types: Fix SC2039: In POSIX sh, something is undefined (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2045: Iterating over ls output is fragile. Use globs. (shellcheck) (Thomas Eckert) * Explorers and types: Fix SC2148: Tips depend on target shell and yours is unknown. Add a shebang. (shellcheck) (Thomas Eckert) + * Explorers and types: Fix SC2069: To redirect stdout+stderr, 2>&1 must be last (or use '{ cmd > file; } 2>&1' to clarify). (shellcheck) (Jonas Weber) + * Explorers and types: Fix SC2034: foo appears unused. Verify it or export it. (shellcheck) (Jonas Weber) + * Explorers and types: Fix SC2215, SC2059, SC2155, SC2091. (shellcheck) (Jonas Weber) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From c01cf386608cbef77c53d6b2bf3c2f6d2b2be91d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 4 Oct 2018 23:10:42 +0200 Subject: [PATCH 0907/1332] Fix SC2164 --- cdist/conf/explorer/disks | 2 +- cdist/conf/type/__link/explorer/state | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks index 7a5c0da0..7c60b17a 100755 --- a/cdist/conf/explorer/disks +++ b/cdist/conf/explorer/disks @@ -1,3 +1,3 @@ #!/bin/sh -cd /dev +cd /dev || exit 0 echo sd? hd? vd? diff --git a/cdist/conf/type/__link/explorer/state b/cdist/conf/type/__link/explorer/state index b8d8fc2b..587835a2 100755 --- a/cdist/conf/type/__link/explorer/state +++ b/cdist/conf/type/__link/explorer/state @@ -32,7 +32,7 @@ destination_dir="${destination%/*}" case "$type" in symbolic) - cd "$destination_dir" + cd "$destination_dir" || exit 1 source_is=$(ls -l "$destination" | sed 's/.*-> //g') if [ -h "$destination" ]; then # ignore trailing slashes for comparison @@ -46,7 +46,7 @@ case "$type" in fi ;; hard) - cd "$destination_dir" + cd "$destination_dir" || exit 1 # check source relative to destination_dir if [ ! -e "$source" ]; then echo sourcemissing From d2f1d6185d7c9e46ae60e99cefc31f0b113ec148 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 10:29:47 +0200 Subject: [PATCH 0908/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 151b11e5..d53edba2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -14,6 +14,8 @@ next: * Explorers and types: Fix SC2069: To redirect stdout+stderr, 2>&1 must be last (or use '{ cmd > file; } 2>&1' to clarify). (shellcheck) (Jonas Weber) * Explorers and types: Fix SC2034: foo appears unused. Verify it or export it. (shellcheck) (Jonas Weber) * Explorers and types: Fix SC2215, SC2059, SC2155, SC2091. (shellcheck) (Jonas Weber) + * Explorers and types: Fix SC2086: Double quote to prevent globbing and word splitting. (shellcheck) (Jonas Weber) + * Explorers and types: Fix SC2164: Use cd ... || exit in case cd fails. (shellcheck) (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 3b6d75966011a80a2d396933abe7d1816245c8e5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 4 Oct 2018 23:24:30 +0200 Subject: [PATCH 0909/1332] Disable SC2016 check. --- cdist/conf/type/__docker_compose/gencode-remote | 5 +++-- cdist/conf/type/__golang_from_vendor/manifest | 1 + cdist/conf/type/__package_emerge/explorer/pkg_version | 1 + cdist/conf/type/__rvm_gemset/explorer/state | 2 ++ cdist/conf/type/__staged_file/gencode-local | 3 +++ 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__docker_compose/gencode-remote b/cdist/conf/type/__docker_compose/gencode-remote index 396c93ac..77fc2fdf 100755 --- a/cdist/conf/type/__docker_compose/gencode-remote +++ b/cdist/conf/type/__docker_compose/gencode-remote @@ -24,8 +24,9 @@ state="$(cat "$__object/parameter/state")" if [ "${state}" = "present" ]; then # Download docker-compose file - echo 'curl -L "https://github.com/docker/compose/releases/download/'"${version}"'/docker-compose-$(uname -s)-$(uname -m)" -o /tmp/docker-compose' - echo 'mv /tmp/docker-compose /usr/local/bin/docker-compose' + #shellcheck disable=SC2016 + echo 'curl -L "https://github.com/docker/compose/releases/download/'"${version}"'/docker-compose-$(uname -s)-$(uname -m)" -o /tmp/docker-compose' + echo 'mv /tmp/docker-compose /usr/local/bin/docker-compose' # Change permissions echo 'chmod +x /usr/local/bin/docker-compose' fi diff --git a/cdist/conf/type/__golang_from_vendor/manifest b/cdist/conf/type/__golang_from_vendor/manifest index cf164524..ad39ddfb 100755 --- a/cdist/conf/type/__golang_from_vendor/manifest +++ b/cdist/conf/type/__golang_from_vendor/manifest @@ -1,3 +1,4 @@ #!/bin/sh -e +# shellcheck disable=SC2016 __line go_in_path --line 'export PATH=/usr/local/go/bin:$PATH' --file /etc/profile diff --git a/cdist/conf/type/__package_emerge/explorer/pkg_version b/cdist/conf/type/__package_emerge/explorer/pkg_version index 7053eaff..d02b9d6b 100644 --- a/cdist/conf/type/__package_emerge/explorer/pkg_version +++ b/cdist/conf/type/__package_emerge/explorer/pkg_version @@ -32,4 +32,5 @@ else name="$__object_id" fi +# shellcheck disable=SC2016 equery -q l -F '$cp $fullversion' "$name" || true diff --git a/cdist/conf/type/__rvm_gemset/explorer/state b/cdist/conf/type/__rvm_gemset/explorer/state index d1462134..e300453b 100755 --- a/cdist/conf/type/__rvm_gemset/explorer/state +++ b/cdist/conf/type/__rvm_gemset/explorer/state @@ -25,7 +25,9 @@ if [ ! -e "~$user/.rvm/scripts/rvm" ] ; then exit 0 fi +# shellcheck disable=SC2016 if su - "$user" -c 'source ~/.rvm/scripts/rvm; rvm list strings | grep -q "^$ruby\$"'; then + # shellcheck disable=SC2016 if su - "$user" -c 'source ~/.rvm/scripts/rvm; rvm use "$ruby" > /dev/null; rvm gemset list strings | cut -f 1 -d " " | grep -q "^$gemsetname\$"'; then echo "present" exit 0 diff --git a/cdist/conf/type/__staged_file/gencode-local b/cdist/conf/type/__staged_file/gencode-local index 617ca23a..4edaba7f 100755 --- a/cdist/conf/type/__staged_file/gencode-local +++ b/cdist/conf/type/__staged_file/gencode-local @@ -62,7 +62,9 @@ fetch_file() { } fetch_and_prepare_file() { + # shellcheck disable=SC2016 printf 'tmpdir="$(mktemp -d --tmpdir="/tmp" "%s")"\n' "${__type##*/}.XXXXXXXXXX" + # shellcheck disable=SC2016 printf 'cd "$tmpdir"\n' # shellcheck disable=SC2059 printf "$fetch_command > \"%s\"\n" "$source" "$source_file_name" @@ -70,6 +72,7 @@ fetch_and_prepare_file() { # shellcheck disable=SC2059 printf "$prepare_command > \"%s\"\n" "$source_file_name" "$stage_file" printf 'cd - >/dev/null\n' + # shellcheck disable=SC2016 printf 'rm -rf "$tmpdir"\n' } From 5f8c631e344ed8b54c670748a08615161aea2ada Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 11:26:47 +0200 Subject: [PATCH 0910/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index d53edba2..b5c218bc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -16,6 +16,7 @@ next: * Explorers and types: Fix SC2215, SC2059, SC2155, SC2091. (shellcheck) (Jonas Weber) * Explorers and types: Fix SC2086: Double quote to prevent globbing and word splitting. (shellcheck) (Jonas Weber) * Explorers and types: Fix SC2164: Use cd ... || exit in case cd fails. (shellcheck) (Darko Poljak) + * Explorers and types: Disable SC2016 where it is intended: Expressions don't expand in single quotes, use double quotes for that. (shellcheck) (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From a601fa91d9c2eecc75bb476f81ccfb46e7d6d2c5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 11:34:10 +0200 Subject: [PATCH 0911/1332] Fix SC2116. --- cdist/conf/type/__hostname/gencode-remote | 2 +- cdist/conf/type/__hostname/manifest | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 3f784188..b729b667 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -22,7 +22,7 @@ if [ -f "$__object/parameter/name" ]; then name_should="$(cat "$__object/parameter/name")" else - name_should="$(echo "${__target_host%%.*}")" + name_should="${__target_host%%.*}" fi os=$(cat "$__global/explorer/os") diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 74664aa7..c03b2eac 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -25,10 +25,10 @@ if [ -f "$__object/parameter/name" ]; then else case "$os" in openbsd) - name_should="$(echo "${__target_host}")" + name_should="${__target_host}" ;; *) - name_should="$(echo "${__target_host%%.*}")" + name_should="${__target_host%%.*}" ;; esac fi From b25aff17c6cbeaf26cec3ce17f250bdacdd38df2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 11:49:28 +0200 Subject: [PATCH 0912/1332] Disable SC2039 where appropriate. --- cdist/conf/type/__package_pkg_freebsd/gencode-remote | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__package_pkg_freebsd/gencode-remote b/cdist/conf/type/__package_pkg_freebsd/gencode-remote index 6c6e15b1..fd02d939 100755 --- a/cdist/conf/type/__package_pkg_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_freebsd/gencode-remote @@ -36,6 +36,7 @@ assert () # If condition false, if [ ! "$1" ] then echo "Assertion failed: \"$1\"" + # shellcheck disable=SC2039 echo "File \"$0\", line $lineno, called by $(caller 0)" exit $E_ASSERT_FAILED fi @@ -95,6 +96,7 @@ if [ -n "$curr_version" ]; then # PKG *is* installed exit 0 else # Current version is wrong, fix #updatepkg "$name" "$version" + # shellcheck disable=SC2039 assert "! ${version} = ${curr_version}" $LINENO cmd="${rm_cmd} ${name}-${curr_version}" execcmd "remove" "${cmd}" From ed542cc7cb3f8e02a2dea1388e8434d0987eeac4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 11:57:31 +0200 Subject: [PATCH 0913/1332] Fix SC2046. --- cdist/conf/type/__jail_freebsd10/gencode-remote | 2 +- cdist/conf/type/__jail_freebsd9/gencode-remote | 2 +- cdist/conf/type/__package_emerge/gencode-remote | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index 5be04bc6..84b2bae8 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -83,7 +83,7 @@ present="$(cat "$__object/explorer/present")" status="$(cat "$__object/explorer/status")" # Handle ip="addr, addr" format -if [ $(expr "${ip}" : ".*, .*") -gt "0" ]; then +if [ "$(expr "${ip}" : ".*, .*")" -gt "0" ]; then SAVE_IFS="$IFS" IFS=", " for cur_ip in ${ip}; do diff --git a/cdist/conf/type/__jail_freebsd9/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote index 177bdf74..5b103ebc 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -86,7 +86,7 @@ present="$(cat "$__object/explorer/present")" status="$(cat "$__object/explorer/status")" # Handle ip="iface|addr, iface|addr" format -if [ $(expr "${ip}" : ".*|.*") -gt "0" ]; then +if [ "$(expr "${ip}" : ".*|.*")" -gt "0" ]; then # If we have multiple IPs defined, $interface doesn't make sense because ip="iface|addr, iface|addr" implies it interface="" SAVE_IFS="$IFS" diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote index 8abcb5b1..c8a79c1f 100755 --- a/cdist/conf/type/__package_emerge/gencode-remote +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -38,11 +38,11 @@ fi pkg_version="$(cat "$__object/explorer/pkg_version")" if [ -z "$pkg_version" ]; then state_is="absent" -elif [ -z "$version" ] && [ $(echo "$pkg_version" | wc -l) -gt 1 ]; then +elif [ -z "$version" ] && [ "$(echo "$pkg_version" | wc -l)" -gt 1 ]; then echo "Package name is not unique! The following packages are installed:" echo "$pkg_version" exit 1 -elif [ -n "$version" ] && [ $(echo "$pkg_version" | cut -d " " -f 1 | sort | uniq | wc -l) -gt 1 ]; then +elif [ -n "$version" ] && [ "$(echo "$pkg_version" | cut -d " " -f 1 | sort | uniq | wc -l)" -gt 1 ]; then echo "Package name is not unique! The following packages are installed:" echo "$pkg_version" exit 1 From 28889ef38a08f53b193a7cc561372e8c03175853 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:02:10 +0200 Subject: [PATCH 0914/1332] Disable SC2028 where intended. --- cdist/conf/type/__hostname/gencode-remote | 2 ++ cdist/conf/type/__jail_freebsd10/gencode-remote | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index b729b667..fd9e7c98 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -59,6 +59,7 @@ echo changed >> "$__messages_out" # Use the good old way to set the hostname even on machines running systemd. case "$os" in archlinux|debian|ubuntu|devuan|centos|coreos) + # shellcheck disable=SC2028 echo "printf '%s\n' '$name_should' > /etc/hostname" echo "hostname -F /etc/hostname" ;; @@ -67,6 +68,7 @@ case "$os" in ;; suse) echo "hostname '$name_should'" + # shellcheck disable=SC2028 echo "printf '%s\n' '$name_should' > /etc/HOSTNAME" ;; esac diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index 84b2bae8..81912050 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -298,7 +298,7 @@ END fi EOF - + # shellcheck disable=SC2028 echo "printf \"%s\\n%s\n%s\n\" \"\$jailheader\" \"\$jaildata\" \"\$jailtrailer\" >>\"\$jailfile\"" # Add $name to jail_list if $onboot=yes From 73acb35a8acf1f7f235e6cda40dc43563b261b00 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:04:45 +0200 Subject: [PATCH 0915/1332] Fix SC2196. --- cdist/conf/type/__package_luarocks/explorer/pkg_status | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_luarocks/explorer/pkg_status b/cdist/conf/type/__package_luarocks/explorer/pkg_status index 3eb73298..e83e8ce6 100755 --- a/cdist/conf/type/__package_luarocks/explorer/pkg_status +++ b/cdist/conf/type/__package_luarocks/explorer/pkg_status @@ -28,4 +28,4 @@ else fi # Accept luarocks failing if package is not known/installed -luarocks list "$name" | egrep -A1 "^$name$" || exit 0 +luarocks list "$name" | grep -E -A1 "^$name$" || exit 0 From 73d0a5bbbed2e777ea721e47b9e5dd6a2bc7859c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:14:51 +0200 Subject: [PATCH 0916/1332] Fix SC2235. --- cdist/conf/type/__package_emerge/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote index c8a79c1f..48462bde 100755 --- a/cdist/conf/type/__package_emerge/gencode-remote +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -57,7 +57,7 @@ fi # Exit if nothing is needed to be done -[ "$state_is" = "$state_should" ] && ( [ -z "$version" ] || [ "$installed_version" = "$version" ] ) && exit 0 +[ "$state_is" = "$state_should" ] && { [ -z "$version" ] || [ "$installed_version" = "$version" ]; } && exit 0 [ "$state_should" = "absent" ] && [ ! -z "$version" ] && [ "$installed_version" != "$version" ] && exit 0 From 2f7b8e6db9ed4900c3fdc9f3dac26654e706b8ae Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:16:27 +0200 Subject: [PATCH 0917/1332] Fix SC2153. --- cdist/conf/type/__pf_ruleset/gencode-local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__pf_ruleset/gencode-local b/cdist/conf/type/__pf_ruleset/gencode-local index b4bded98..b9de1bce 100755 --- a/cdist/conf/type/__pf_ruleset/gencode-local +++ b/cdist/conf/type/__pf_ruleset/gencode-local @@ -54,7 +54,7 @@ case $uname in currentSum=\$(cksum -o 1 ${source} | cut -d= -f2 | sed 's/ //g') ;; *) - echo "Sorry, I do not know how to find a cksum on ${UNAME}." >&2 + echo "Sorry, I do not know how to find a cksum on ${uname}." >&2 exit 1 ;; esac From e46420e7f57560a5b833d42dfcf10c40549f83d9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:19:16 +0200 Subject: [PATCH 0918/1332] Fix SC1090. --- cdist/conf/type/__docker/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index 35760cef..8f26feec 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -24,6 +24,7 @@ state=$(cat "$__object/parameter/state") case "$os" in centos) + # shellcheck source=/dev/null if (. "$__global/explorer/os_release" && [ "${VERSION_ID}" = "7" ]); then __yum_repo docker-ce-stable \ --name 'Docker CE Stable' \ From 7b17ad473303a48a70b1d959141bdf22b8747607 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:21:59 +0200 Subject: [PATCH 0919/1332] Fix SC2143. --- cdist/conf/type/__jail/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index 222cb859..6fb4a306 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -44,7 +44,7 @@ for property in *; do done ver="$(cat "$__global/explorer/os_version")" -if [ -n "$(echo "$ver" | grep '^10\.' )" ]; then # Version is 10.x +if echo "$ver" | grep -q '^10\.'; then # Version is 10.x __jail_freebsd10 "$@" else __jail_freebsd9 "$@" From b120a813a2e2db27e29c8442fba9d0091f67a45c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:24:03 +0200 Subject: [PATCH 0920/1332] Disable SC2030 where appropriate. --- cdist/conf/type/__consul_template_template/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__consul_template_template/manifest b/cdist/conf/type/__consul_template_template/manifest index 7834ae9c..4ba0329f 100755 --- a/cdist/conf/type/__consul_template_template/manifest +++ b/cdist/conf/type/__consul_template_template/manifest @@ -52,6 +52,7 @@ for param in *; do --owner root --group root --mode 640 \ --source "$source" \ --state "$state" + # shellcheck disable=SC2030 export require="__file${destination}" printf ' source = "%s"\n' "$destination" From 8cea8e67aaa71d911b70326efd7c8e61103b1502 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:25:40 +0200 Subject: [PATCH 0921/1332] Disable SC2031 where appropriate. --- cdist/conf/type/__consul_template_template/manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__consul_template_template/manifest b/cdist/conf/type/__consul_template_template/manifest index 4ba0329f..2fd0a46c 100755 --- a/cdist/conf/type/__consul_template_template/manifest +++ b/cdist/conf/type/__consul_template_template/manifest @@ -17,6 +17,7 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # +# shellcheck disable=SC2031 name="$(cat "$__object/parameter/name" 2>/dev/null || echo "$__object_id")" state="$(cat "$__object/parameter/state")" From 9b567ed8f7030de20066f65f0d78e7bc323e6af1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:27:43 +0200 Subject: [PATCH 0922/1332] Fix SC2230. --- cdist/conf/type/__dot_file/explorer/home | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__dot_file/explorer/home b/cdist/conf/type/__dot_file/explorer/home index 132cfc71..08d941bf 100755 --- a/cdist/conf/type/__dot_file/explorer/home +++ b/cdist/conf/type/__dot_file/explorer/home @@ -19,7 +19,7 @@ set -eu user="$(cat "${__object}/parameter/user")" -if which getent >/dev/null 2>&1; then +if command -v getent >/dev/null 2>&1; then line=$(getent passwd "${user}") else line=$(grep "^${user}:" /etc/passwd) From 596f3cf227c3e0ee219caf00a1973baf0d68db87 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:30:52 +0200 Subject: [PATCH 0923/1332] Disable SC2119,SC2120 where appropriate. --- cdist/conf/type/__jail_freebsd10/gencode-remote | 2 ++ cdist/conf/type/__jail_freebsd9/gencode-remote | 2 ++ 2 files changed, 4 insertions(+) diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index 81912050..d01b30c6 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -111,6 +111,7 @@ startJail() { fi } +# shellcheck disable=SC2120 deleteJail() { # Unmount the jail's mountpoints if necessary cat < Date: Fri, 5 Oct 2018 12:32:56 +0200 Subject: [PATCH 0924/1332] Fix SC2145. --- .../conf/type/__install_partition_msdos_apply/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index 644de33c..d699d8ad 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -21,11 +21,11 @@ #set -x die() { - echo "[__install_partition_msdos_apply] $@" >&2 + echo "[__install_partition_msdos_apply] $*" >&2 exit 1 } debug() { - #echo "[__install_partition_msdos_apply] $@" >&2 + #echo "[__install_partition_msdos_apply] $*" >&2 : } From 644ec85d801e17f38b8917b2822e611db97a1979 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:50:01 +0200 Subject: [PATCH 0925/1332] Fix SC2162. --- cdist/conf/type/__rsync/gencode-local | 2 +- cdist/conf/type/__ssh_authorized_key/gencode-remote | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__rsync/gencode-local b/cdist/conf/type/__rsync/gencode-local index c7196175..e36ded2f 100755 --- a/cdist/conf/type/__rsync/gencode-local +++ b/cdist/conf/type/__rsync/gencode-local @@ -29,7 +29,7 @@ fi set -- if [ -f "$__object/parameter/rsync-opts" ]; then - while read opts; do + while read -r opts; do set -- "$@" "--$opts" done < "$__object/parameter/rsync-opts" fi diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index 325854c2..82c90d61 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -78,7 +78,7 @@ if [ -s "$__object/explorer/entry" ]; then # Note that the files have to be sorted for comparison with `comm`. sort "$__object/explorer/entry" > "$__object/files/is" comm -13 "$__object/files/should" "$__object/files/is" | { - while read entry; do + while read -r entry; do remove_line "$file" "$entry" done } From a369acea72d173aa7f8bb2793ece4b8a91839caa Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 12:52:44 +0200 Subject: [PATCH 0926/1332] Fix SC2021. --- cdist/conf/type/__postgres_role/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index 14240992..f977e73e 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -34,7 +34,7 @@ case "$state_should" in if [ ! -f "$__object/parameter/$boolean" ]; then boolean="no${boolean}" fi - upper=$(echo $boolean | tr '[a-z]' '[A-Z]') + upper=$(echo $boolean | tr '[:lower:]' '[:upper:]') booleans="$booleans $upper" done From bf270b6f9c32ab345ed3ee30dc70aeb7a1ca8d81 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 13:05:01 +0200 Subject: [PATCH 0927/1332] Fix SC2044. --- cdist/conf/type/__install_generate_fstab/gencode-local | 4 +++- cdist/conf/type/__install_mount/gencode-remote | 4 +++- .../conf/type/__install_partition_msdos_apply/gencode-remote | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__install_generate_fstab/gencode-local b/cdist/conf/type/__install_generate_fstab/gencode-local index aca42761..80455aaa 100755 --- a/cdist/conf/type/__install_generate_fstab/gencode-local +++ b/cdist/conf/type/__install_generate_fstab/gencode-local @@ -25,7 +25,9 @@ mkdir "$__object/files" # get current UUID's from target_host $__remote_exec "$__target_host" blkid > "$__object/files/blkid" -for object in $(find "$__global/object/__install_mount" -type d -name "$__cdist_object_marker"); do +find "$__global/object/__install_mount" -type d -name "$__cdist_object_marker" | +while IFS= read -r object +do device="$(cat "$object/parameter/device")" dir="$(cat "$object/parameter/dir")" type="$(cat "$object/parameter/type")" diff --git a/cdist/conf/type/__install_mount/gencode-remote b/cdist/conf/type/__install_mount/gencode-remote index ce96279a..4415f0ff 100755 --- a/cdist/conf/type/__install_mount/gencode-remote +++ b/cdist/conf/type/__install_mount/gencode-remote @@ -20,7 +20,9 @@ get_type_from_mkfs() { _device="$1" - for mkfs_object in $(find "$__global/object/__install_mkfs" -type d -name "$__cdist_object_marker"); do + find "$__global/object/__install_mkfs" -type d -name "$__cdist_object_marker" | + while IFS= read -r mkfs_object + do mkfs_device="$(cat "$mkfs_object/parameter/device")" if [ "$_device" = "$mkfs_device" ]; then cat "$mkfs_object/parameter/type" diff --git a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote index 644de33c..69be8daf 100755 --- a/cdist/conf/type/__install_partition_msdos_apply/gencode-remote +++ b/cdist/conf/type/__install_partition_msdos_apply/gencode-remote @@ -59,7 +59,9 @@ size_to_mb() { get_objects() { objects_file=$(mktemp) - for object in $(find "$__global/object/__install_partition_msdos" -type d -name "$__cdist_object_marker"); do + find "$__global/object/__install_partition_msdos" -type d -name "$__cdist_object_marker" | + while IFS= read -r object + do object_device="$(cat "$object/parameter/device")" object_minor="$(cat "$object/parameter/minor")" echo "$object_device $object_minor $object" >> "$objects_file" From 9a61aab631a9a0a8425d20affe603f1ab2d194ae Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 14:59:35 +0200 Subject: [PATCH 0928/1332] ++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index b5c218bc..419a3003 100644 --- a/docs/changelog +++ b/docs/changelog @@ -17,6 +17,7 @@ next: * Explorers and types: Fix SC2086: Double quote to prevent globbing and word splitting. (shellcheck) (Jonas Weber) * Explorers and types: Fix SC2164: Use cd ... || exit in case cd fails. (shellcheck) (Darko Poljak) * Explorers and types: Disable SC2016 where it is intended: Expressions don't expand in single quotes, use double quotes for that. (shellcheck) (Darko Poljak) + * Explorers and types: Fix SC2044: For loops over find output are fragile. Use find -exec or a while read loop. (shellcheck) (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 0d80b4473b58623eaea63e115310e03201dd11fc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 15:04:22 +0200 Subject: [PATCH 0929/1332] Disable SC2031 for the single incident. --- cdist/conf/type/__consul_template_template/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul_template_template/manifest b/cdist/conf/type/__consul_template_template/manifest index 2fd0a46c..506bc528 100755 --- a/cdist/conf/type/__consul_template_template/manifest +++ b/cdist/conf/type/__consul_template_template/manifest @@ -17,7 +17,6 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# shellcheck disable=SC2031 name="$(cat "$__object/parameter/name" 2>/dev/null || echo "$__object_id")" state="$(cat "$__object/parameter/state")" @@ -37,6 +36,7 @@ if [ ! -f "$__object/parameter/source" ] && [ ! -f "$__object/parameter/source-f fi # Generate hcl config file +# shellcheck disable=SC2031 ( printf 'template {\n' cd "$__object/parameter/" From 02f39bcf6f32647e7ee2c4cbd7781439c3567f16 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 15:08:25 +0200 Subject: [PATCH 0930/1332] Fix SC2028. --- cdist/conf/type/__hostname/gencode-remote | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index fd9e7c98..fc50b651 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -59,8 +59,7 @@ echo changed >> "$__messages_out" # Use the good old way to set the hostname even on machines running systemd. case "$os" in archlinux|debian|ubuntu|devuan|centos|coreos) - # shellcheck disable=SC2028 - echo "printf '%s\n' '$name_should' > /etc/hostname" + printf "printf '%s\\n' '$name_should' > /etc/hostname\\n" echo "hostname -F /etc/hostname" ;; freebsd|openbsd) @@ -68,8 +67,7 @@ case "$os" in ;; suse) echo "hostname '$name_should'" - # shellcheck disable=SC2028 - echo "printf '%s\n' '$name_should' > /etc/HOSTNAME" + printf "printf '%s\\n' '$name_should' > /etc/HOSTNAME\\n" ;; esac From b284bafbee38be49b57b2b6caf8af8d6df4be2c9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 15:14:03 +0200 Subject: [PATCH 0931/1332] grep directly on the explorer file --- cdist/conf/type/__jail/manifest | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index 6fb4a306..adf9bd99 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -43,8 +43,7 @@ for property in *; do set -- "$@" "--$property" "$(cat "$property")" done -ver="$(cat "$__global/explorer/os_version")" -if echo "$ver" | grep -q '^10\.'; then # Version is 10.x +if grep -q '^10\.' "$(cat "$__global/explorer/os_version")" ; then # Version is 10.x __jail_freebsd10 "$@" else __jail_freebsd9 "$@" From 68fad03a6b98c48abf6cca05488998d7df872c7b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Oct 2018 15:18:59 +0200 Subject: [PATCH 0932/1332] Fix SC2120, SC2119. --- cdist/conf/type/__jail_freebsd10/gencode-remote | 6 ++---- cdist/conf/type/__jail_freebsd9/gencode-remote | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index d01b30c6..230370c2 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -111,7 +111,6 @@ startJail() { fi } -# shellcheck disable=SC2120 deleteJail() { # Unmount the jail's mountpoints if necessary cat <=1 rw mount is mounted still for DIR in "${output}"; do - umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print $3}')" + umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print \$3}')" done fi output="\$(mount | grep "\/${name} (")" || true if [ -n "\${output}" ]; then # ro mount is mounted still - umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print $3}')" + umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print \$3}')" fi EOF # Remove the jail's rw mountpoints @@ -348,7 +347,6 @@ if [ "$present" = "EXISTS" ]; then # The jail currently exists exit 0 else # The jail is not supposed to exist stopJail - # shellcheck disable=SC2119 deleteJail exit 0 fi diff --git a/cdist/conf/type/__jail_freebsd9/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote index e89672c2..13c237a9 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -116,7 +116,6 @@ startJail() { fi } -# shellcheck disable=SC2120 deleteJail() { # Unmount the jail's mountpoints if necessary cat <=1 rw mount is mounted still for DIR in "${output}"; do - umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print $3}')" + umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print \$3}')" done fi output="\$(mount | grep "\/${name} (")" || true if [ -n "\${output}" ]; then # ro mount is mounted still - umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print $3}')" + umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print \$3}')" fi EOF # Remove the jail's rw mountpoints @@ -343,7 +342,6 @@ if [ "$present" = "EXISTS" ]; then # The jail currently exists exit 0 else # The jail is not supposed to exist stopJail - # shellcheck disable=SC2119 deleteJail exit 0 fi From f039b0e6e5e4d90793061cc2a6dc73883367d767 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Oct 2018 08:36:06 +0200 Subject: [PATCH 0933/1332] Fix SC2030,SC2031. --- cdist/conf/type/__consul_template_template/manifest | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__consul_template_template/manifest b/cdist/conf/type/__consul_template_template/manifest index 506bc528..1eae1fad 100755 --- a/cdist/conf/type/__consul_template_template/manifest +++ b/cdist/conf/type/__consul_template_template/manifest @@ -35,9 +35,13 @@ if [ ! -f "$__object/parameter/source" ] && [ ! -f "$__object/parameter/source-f exit 1 fi +if [ -f "$__object/parameter/source-file" ]; then + destination="${template_dir}/${name}" + require="__file${destination}" +fi + # Generate hcl config file -# shellcheck disable=SC2031 -( +{ printf 'template {\n' cd "$__object/parameter/" for param in *; do @@ -47,14 +51,11 @@ for param in *; do if [ "$source" = "-" ]; then source="$__object/stdin" fi - destination="${template_dir}/${name}" require="__directory${template_dir}" \ __file "$destination" \ --owner root --group root --mode 640 \ --source "$source" \ --state "$state" - # shellcheck disable=SC2030 - export require="__file${destination}" printf ' source = "%s"\n' "$destination" ;; @@ -68,7 +69,7 @@ for param in *; do esac done printf '}\n' -) | \ +} | \ require="$require __directory${conf_dir}" \ __config_file "${conf_dir}/${conf_file}" \ --owner root --group root --mode 640 \ From 877b4d2748018096fded1c9e81ee73a2257c53b5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Oct 2018 15:15:53 +0200 Subject: [PATCH 0934/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 419a3003..bc51c81b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -18,6 +18,7 @@ next: * Explorers and types: Fix SC2164: Use cd ... || exit in case cd fails. (shellcheck) (Darko Poljak) * Explorers and types: Disable SC2016 where it is intended: Expressions don't expand in single quotes, use double quotes for that. (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2044: For loops over find output are fragile. Use find -exec or a while read loop. (shellcheck) (Darko Poljak) + * Explorers and types: Fix SC1090,SC2021,SC2028,SC2030,SC2031,SC2039,SC2046,SC2116,SC2119,SC2120,SC2143,SC2145,SC2153,SC2162,SC2196,SC2230,SC2235. (shellcheck) (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 8436f872a9cc32162e8991751558ecfcbcc7e967 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Oct 2018 14:57:55 +0200 Subject: [PATCH 0935/1332] Add shellcheck makefile target. shellcheck when doing release. --- Makefile | 20 ++++++++++++++++++++ bin/build-helper | 25 ++++++++++++++++++++++++- bin/build-helper.freebsd | 25 ++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3a1819be..4a756808 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,9 @@ PYTHON_VERSION=cdist/version.py SPHINXM=make -C $(DOCS_SRC_DIR) man SPHINXH=make -C $(DOCS_SRC_DIR) html SPHINXC=make -C $(DOCS_SRC_DIR) clean + +SHELLCHECKCMD=shellcheck -s sh -f gcc -x +SHELLCHECK_SKIP=grep -v ': __.*is referenced but not assigned.*\[SC2154\]' ################################################################################ # Manpages # @@ -253,3 +256,20 @@ test-remote: pep8: $(helper) $@ + +shellcheck-global-explorers: + @find cdist/conf/explorer -type f -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) +shellcheck-manifests: + @find cdist/conf/type -type f -name manifest -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) + +shellcheck-local-gencodes: + @find cdist/conf/type -type f -name gencode-local -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) + +shellcheck-remote-gencodes: + @find cdist/conf/type -type f -name gencode-remote -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) + +shellcheck-gencodes: shellcheck-local-gencodes shellcheck-remote-gencodes + +shellcheck-types: shellcheck-manifests shellcheck-gencodes + +shellcheck: shellcheck-global-explorers shellcheck-types diff --git a/bin/build-helper b/bin/build-helper index ef15b6c2..02fa67d6 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -250,6 +250,7 @@ eof "$0" check-date "$0" check-unittest "$0" check-pep8 + "$0" shellcheck # Generate version file to be included in packaging "$0" target-version @@ -370,7 +371,29 @@ eof check-pep8) "$0" pep8 - echo "Please review pep8 report." + printf "\\nPlease review pep8 report.\\n" + while true + do + echo "Continue (yes/no)?" + any= + read any + case "$any" in + yes) + break + ;; + no) + exit 1 + ;; + *) + echo "Please answer with 'yes' or 'no' explicitly." + ;; + esac + done + ;; + + shellcheck) + make helper=${helper} WEBDIR=${WEBDIR} shellcheck + printf "\\nPlease review shellcheck report.\\n" while true do echo "Continue (yes/no)?" diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index e49b2f7a..081feb54 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -285,6 +285,7 @@ eof "$0" check-date "$0" check-unittest "$0" check-pep8 + "$0" shellcheck # Generate version file to be included in packaging "$0" target-version @@ -432,7 +433,29 @@ eof check-pep8) "$0" pep8 - echo "Please review pep8 report." + printf "\\nPlease review pep8 report.\\n" + while true + do + echo "Continue (yes/no)?" + any= + read any + case "$any" in + yes) + break + ;; + no) + exit 1 + ;; + *) + echo "Please answer with 'yes' or 'no' explicitly." + ;; + esac + done + ;; + + shellcheck) + make helper=${helper} WEBDIR=${WEBDIR} shellcheck + printf "\\nPlease review shellcheck report.\\n" while true do echo "Continue (yes/no)?" From 140518f1b0dddb1778d4e4c9ce3903f893a5a53e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Oct 2018 15:00:31 +0200 Subject: [PATCH 0936/1332] Add comment for SHELLCHECK_SKIP. --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 4a756808..56229496 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,8 @@ SPHINXH=make -C $(DOCS_SRC_DIR) html SPHINXC=make -C $(DOCS_SRC_DIR) clean SHELLCHECKCMD=shellcheck -s sh -f gcc -x +# Skip SC2154 for variables starting with __ since such variables are cdist +# environment variables. SHELLCHECK_SKIP=grep -v ': __.*is referenced but not assigned.*\[SC2154\]' ################################################################################ # Manpages From edaf4b46a521e2073de829ce5989127451b216ee Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Oct 2018 22:53:07 +0200 Subject: [PATCH 0937/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index bc51c81b..d7d31f52 100644 --- a/docs/changelog +++ b/docs/changelog @@ -19,6 +19,7 @@ next: * Explorers and types: Disable SC2016 where it is intended: Expressions don't expand in single quotes, use double quotes for that. (shellcheck) (Darko Poljak) * Explorers and types: Fix SC2044: For loops over find output are fragile. Use find -exec or a while read loop. (shellcheck) (Darko Poljak) * Explorers and types: Fix SC1090,SC2021,SC2028,SC2030,SC2031,SC2039,SC2046,SC2116,SC2119,SC2120,SC2143,SC2145,SC2153,SC2162,SC2196,SC2230,SC2235. (shellcheck) (Darko Poljak) + * Build: Add shellcheck makefile target and check when doing release (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 3be1c4ad6f4a5f97d346f0a2a54b5526d8deb0ca Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 7 Oct 2018 10:21:08 +0200 Subject: [PATCH 0938/1332] If nothing found shellcheck targets should succeed. --- Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 56229496..e9cacced 100644 --- a/Makefile +++ b/Makefile @@ -260,15 +260,16 @@ pep8: $(helper) $@ shellcheck-global-explorers: - @find cdist/conf/explorer -type f -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) + @find cdist/conf/explorer -type f -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 + shellcheck-manifests: - @find cdist/conf/type -type f -name manifest -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) + @find cdist/conf/type -type f -name manifest -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 shellcheck-local-gencodes: - @find cdist/conf/type -type f -name gencode-local -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) + @find cdist/conf/type -type f -name gencode-local -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 shellcheck-remote-gencodes: - @find cdist/conf/type -type f -name gencode-remote -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) + @find cdist/conf/type -type f -name gencode-remote -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 shellcheck-gencodes: shellcheck-local-gencodes shellcheck-remote-gencodes From 83806e767a834ce80cc35f756090356fe276a205 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Oct 2018 13:25:16 +0200 Subject: [PATCH 0939/1332] Disable SC1091 where appropriate. --- cdist/conf/explorer/lsb_codename | 1 + cdist/conf/explorer/lsb_description | 1 + cdist/conf/explorer/lsb_id | 1 + cdist/conf/explorer/lsb_release | 1 + 4 files changed, 4 insertions(+) diff --git a/cdist/conf/explorer/lsb_codename b/cdist/conf/explorer/lsb_codename index bfabd444..26bb8e3d 100755 --- a/cdist/conf/explorer/lsb_codename +++ b/cdist/conf/explorer/lsb_codename @@ -22,6 +22,7 @@ set +e case "$("$__explorer/os")" in 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 441fdbf3..b1009627 100755 --- a/cdist/conf/explorer/lsb_description +++ b/cdist/conf/explorer/lsb_description @@ -22,6 +22,7 @@ set +e case "$("$__explorer/os")" in 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 1a12b610..82ff9977 100755 --- a/cdist/conf/explorer/lsb_id +++ b/cdist/conf/explorer/lsb_id @@ -22,6 +22,7 @@ set +e case "$("$__explorer/os")" in 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 25eb95b1..5ebfff1a 100755 --- a/cdist/conf/explorer/lsb_release +++ b/cdist/conf/explorer/lsb_release @@ -22,6 +22,7 @@ set +e case "$("$__explorer/os")" in openwrt) + # shellcheck disable=SC1091 (. /etc/openwrt_release && echo "$DISTRIB_RELEASE") ;; *) From a9f27beb983b2f29e0af7b4b62434088556d292b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Oct 2018 13:41:09 +0200 Subject: [PATCH 0940/1332] Fix SC1117. --- cdist/conf/type/__cron/gencode-remote | 2 +- cdist/conf/type/__install_coreos/gencode-remote | 2 +- .../type/__install_reset_disk/gencode-remote | 2 +- cdist/conf/type/__jail_freebsd10/gencode-remote | 16 ++++++++-------- cdist/conf/type/__jail_freebsd9/gencode-remote | 12 ++++++------ cdist/conf/type/__mount/gencode-remote | 2 +- .../type/__package_pkgng_freebsd/gencode-remote | 2 +- cdist/conf/type/__rvm/gencode-remote | 2 +- .../type/__ssh_authorized_key/gencode-remote | 2 +- cdist/conf/type/__staged_file/gencode-local | 4 ++-- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index f58896af..ee626485 100755 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -58,7 +58,7 @@ state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" # These are the old markers prefix="#cdist:__cron/$__object_id" suffix="#/cdist:__cron/$__object_id" -filter="^# DO NOT EDIT THIS FILE|^# \(.* installed on |^# \(Cron version V|^# \(Cronie version .\..\)$" +filter="^# DO NOT EDIT THIS FILE|^# \\(.* installed on |^# \\(Cron version V|^# \\(Cronie version .\\..\\)$" cat << DONE crontab -u $user -l 2>/dev/null | grep -v -E "$filter" | awk -v prefix="$prefix" -v suffix="$suffix" ' { diff --git a/cdist/conf/type/__install_coreos/gencode-remote b/cdist/conf/type/__install_coreos/gencode-remote index fbe86479..f550b5a5 100755 --- a/cdist/conf/type/__install_coreos/gencode-remote +++ b/cdist/conf/type/__install_coreos/gencode-remote @@ -12,7 +12,7 @@ eof coreos-install -d "${device}" \ \$(if [ -s "\${ignition_file}" ]; then - printf -- "-i \${ignition_file}\n" + printf -- "-i \${ignition_file}\\n" fi) rm "\${ignition_file}" diff --git a/cdist/conf/type/__install_reset_disk/gencode-remote b/cdist/conf/type/__install_reset_disk/gencode-remote index 947dd472..ac9ae6cf 100755 --- a/cdist/conf/type/__install_reset_disk/gencode-remote +++ b/cdist/conf/type/__install_reset_disk/gencode-remote @@ -67,5 +67,5 @@ fi # erase partition table dd if=/dev/zero of=$disk bs=512 count=1 -printf 'w\n' | fdisk -u -c $disk || true +printf 'w\\n' | fdisk -u -c $disk || true DONE diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index 230370c2..a5e097f9 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -45,7 +45,7 @@ else # when $state=present, it's required. Enforce this. if [ "$state" = "present" ]; then exec >&2 - echo "If --state is 'present,' --ip must be given\!" + echo "If --state is 'present,' --ip must be given\\!" exit 1 fi fi @@ -114,17 +114,17 @@ startJail() { deleteJail() { # Unmount the jail's mountpoints if necessary cat <=1 rw mount is mounted still for DIR in "${output}"; do umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print \$3}')" done fi - output="\$(mount | grep "\/${name} (")" || true + output="\$(mount | grep "\\/${name} (")" || true if [ -n "\${output}" ]; then # ro mount is mounted still umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print \$3}')" fi @@ -275,9 +275,9 @@ cat <&1 >/dev/null # Close the FD==fail... @@ -290,7 +290,7 @@ add include \\\$devfsrules_unhide_basic add include \\\$devfsrules_unhide_login END fi - devfsruleset_num=\$(grep "\[${devfsruleset}=" /etc/devfs.rules | sed -n 's/\[.*=\([0-9]*\)\]/\1/pg') + devfsruleset_num=\$(grep "\\[${devfsruleset}=" /etc/devfs.rules | sed -n 's/\\[.*=\\([0-9]*\\)\\]/\\1/pg') if [ -n "\$devfsruleset_num" ]; then jaildata="\$jaildata devfs_ruleset=\"\${devfsruleset_num}\";" @@ -299,7 +299,7 @@ END EOF # shellcheck disable=SC2028 - echo "printf \"%s\\n%s\n%s\n\" \"\$jailheader\" \"\$jaildata\" \"\$jailtrailer\" >>\"\$jailfile\"" + echo "printf \"%s\\n%s\\n%s\\n\" \"\$jailheader\" \"\$jaildata\" \"\$jailtrailer\" >>\"\$jailfile\"" # Add $name to jail_list if $onboot=yes if [ "$onboot" = "yes" ]; then diff --git a/cdist/conf/type/__jail_freebsd9/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote index 13c237a9..7f3828b2 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -45,7 +45,7 @@ else # when $state=present, it's required. Enforce this. if [ "$state" = "present" ]; then exec >&2 - echo "If --state is 'present,' --ip must be given\!" + echo "If --state is 'present,' --ip must be given\\!" exit 1 fi fi @@ -119,17 +119,17 @@ startJail() { deleteJail() { # Unmount the jail's mountpoints if necessary cat <=1 rw mount is mounted still for DIR in "${output}"; do umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print \$3}')" done fi - output="\$(mount | grep "\/${name} (")" || true + output="\$(mount | grep "\\/${name} (")" || true if [ -n "\${output}" ]; then # ro mount is mounted still umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print \$3}')" fi @@ -279,9 +279,9 @@ END if [ ! -f /etc/devfs.rules ]; then touch /etc/devfs.rules fi - if [ -z "\$(grep '\[jailrules=' /etc/devfs.rules)" ]; then # The default ruleset doesn't exist + if [ -z "\$(grep '\\[jailrules=' /etc/devfs.rules)" ]; then # The default ruleset doesn't exist # Get the highest-numbered ruleset - highest="\$(sed -n 's/\[.*=\([0-9]*\)\]/\1/pg' /etc/devfs.rules | sort -u | tail -n 1)" || true + highest="\$(sed -n 's/\\[.*=\\([0-9]*\\)\\]/\\1/pg' /etc/devfs.rules | sort -u | tail -n 1)" || true # increment by 1 let num="\${highest}+1" 2>&- >&- # add default ruleset diff --git a/cdist/conf/type/__mount/gencode-remote b/cdist/conf/type/__mount/gencode-remote index 66d85f88..e8266a0b 100755 --- a/cdist/conf/type/__mount/gencode-remote +++ b/cdist/conf/type/__mount/gencode-remote @@ -39,7 +39,7 @@ case "$state_should" in printf ' -o %s' "$(cat "$__object/parameter/options")" fi printf ' %s' "$(cat "$__object/parameter/device")" - printf " %s\n" "$path" + printf " %s\\n" "$path" else # mount using existing fstab entry printf 'mount "%s"\n' "$path" diff --git a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote index b59e3648..592d4d0f 100755 --- a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote @@ -95,7 +95,7 @@ if [ -n "$curr_version" ]; then # PKG *is* installed if [ "$upgrade" = "true" ]; then execcmd "upg" "${cmd}" else - printf "Version %s is already installed and pkg-ng can't upgrade directly to version %s.\nTo upgrade to the latest version, use the --upgrade flag.\n" "$curr_version" "$version" >&2 + printf "Version %s is already installed and pkg-ng can't upgrade directly to version %s.\\nTo upgrade to the latest version, use the --upgrade flag.\\n" "$curr_version" "$version" >&2 exit 1 fi # PKG is supposed to be installed to the latest version diff --git a/cdist/conf/type/__rvm/gencode-remote b/cdist/conf/type/__rvm/gencode-remote index 494c8fd8..993191c1 100755 --- a/cdist/conf/type/__rvm/gencode-remote +++ b/cdist/conf/type/__rvm/gencode-remote @@ -34,7 +34,7 @@ DONE absent) cat << DONE su - $user -c "rm -Rf \"\\\$HOME/.rvm\"; -sed '/rvm\/scripts\/rvm/d' \"\\\$HOME/.bashrc\" > \"\\\$HOME/.bashrc.cdist-tmp\" +sed '/rvm\\/scripts\\/rvm/d' \"\\\$HOME/.bashrc\" > \"\\\$HOME/.bashrc.cdist-tmp\" mv \"\\\$HOME/.bashrc.cdist-tmp\" \"\\\$HOME/.bashrc\"" DONE ;; diff --git a/cdist/conf/type/__ssh_authorized_key/gencode-remote b/cdist/conf/type/__ssh_authorized_key/gencode-remote index 82c90d61..f37aa565 100755 --- a/cdist/conf/type/__ssh_authorized_key/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_key/gencode-remote @@ -48,7 +48,7 @@ add_line() { line="$2" # escape single quotes line_sanitised=$(echo "$line" | sed -e "s/'/'\"'\"'/g") - printf '%s' "printf '%s\n' '$line_sanitised' >> $file" + printf '%s' "printf '%s\\n' '$line_sanitised' >> $file" } diff --git a/cdist/conf/type/__staged_file/gencode-local b/cdist/conf/type/__staged_file/gencode-local index 4edaba7f..e78b50bd 100755 --- a/cdist/conf/type/__staged_file/gencode-local +++ b/cdist/conf/type/__staged_file/gencode-local @@ -67,10 +67,10 @@ fetch_and_prepare_file() { # shellcheck disable=SC2016 printf 'cd "$tmpdir"\n' # shellcheck disable=SC2059 - printf "$fetch_command > \"%s\"\n" "$source" "$source_file_name" + printf "$fetch_command > \"%s\"\\n" "$source" "$source_file_name" prepare_command="$(cat "$__object/parameter/prepare-command")" # shellcheck disable=SC2059 - printf "$prepare_command > \"%s\"\n" "$source_file_name" "$stage_file" + printf "$prepare_command > \"%s\"\\n" "$source_file_name" "$stage_file" printf 'cd - >/dev/null\n' # shellcheck disable=SC2016 printf 'rm -rf "$tmpdir"\n' From a78baccc827ece35501888cf83dab62144dac1ea Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Oct 2018 13:59:47 +0200 Subject: [PATCH 0941/1332] Fix SC2154. Note: ignoring __ vars. --- cdist/conf/type/__jail_freebsd10/gencode-remote | 4 ++-- cdist/conf/type/__jail_freebsd9/gencode-remote | 4 ++-- cdist/conf/type/__package_opkg/gencode-remote | 2 +- cdist/conf/type/__pf_ruleset/gencode-local | 4 ++-- cdist/conf/type/__postgres_extension/gencode-remote | 2 +- cdist/conf/type/__process/gencode-remote | 1 + cdist/conf/type/__zypper_service/gencode-remote | 2 +- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index a5e097f9..73518326 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -120,13 +120,13 @@ deleteJail() { fi output="\$(mount | grep "\\/rw\\/${name}\\/")" || true if [ -n "\${output}" ]; then # >=1 rw mount is mounted still - for DIR in "${output}"; do + for DIR in "\${output}"; do umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print \$3}')" done fi output="\$(mount | grep "\\/${name} (")" || true if [ -n "\${output}" ]; then # ro mount is mounted still - umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print \$3}')" + umount -F "/etc/fstab.${name}" "\$(echo "\${output}" | awk '{print \$3}')" fi EOF # Remove the jail's rw mountpoints diff --git a/cdist/conf/type/__jail_freebsd9/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote index 7f3828b2..be583e5d 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -125,13 +125,13 @@ deleteJail() { fi output="\$(mount | grep "\\/rw\\/${name}\\/")" || true if [ -n "\${output}" ]; then # >=1 rw mount is mounted still - for DIR in "${output}"; do + for DIR in "\${output}"; do umount -F "/etc/fstab.${name}" "\$(echo "${DIR}" | awk '{print \$3}')" done fi output="\$(mount | grep "\\/${name} (")" || true if [ -n "\${output}" ]; then # ro mount is mounted still - umount -F "/etc/fstab.${name}" "\$(echo "${output}" | awk '{print \$3}')" + umount -F "/etc/fstab.${name}" "\$(echo "\${output}" | awk '{print \$3}')" fi EOF # Remove the jail's rw mountpoints diff --git a/cdist/conf/type/__package_opkg/gencode-remote b/cdist/conf/type/__package_opkg/gencode-remote index 7013ec9f..e94ff388 100755 --- a/cdist/conf/type/__package_opkg/gencode-remote +++ b/cdist/conf/type/__package_opkg/gencode-remote @@ -51,7 +51,7 @@ case "$state_should" in echo "opkg --verbosity=0 remove '$name'" ;; *) - echo "Unknown state: $state" >&2 + echo "Unknown state: ${state_should}" >&2 exit 1 ;; esac diff --git a/cdist/conf/type/__pf_ruleset/gencode-local b/cdist/conf/type/__pf_ruleset/gencode-local index b9de1bce..11bfb0b1 100755 --- a/cdist/conf/type/__pf_ruleset/gencode-local +++ b/cdist/conf/type/__pf_ruleset/gencode-local @@ -69,10 +69,10 @@ fi if [ -n "${cksum}" ]; then if [ ! "\${currentSum}" = "${cksum}" ]; then - $__remote_copy "${source}" "${my_target_host}:${rcvar}.new" + $__remote_copy "${source}" "\${my_target_host}:${rcvar}.new" fi else # File just doesn't exist yet - $__remote_copy "${source}" "${my_target_host}:${rcvar}.new" + $__remote_copy "${source}" "\${my_target_host}:${rcvar}.new" fi EOF diff --git a/cdist/conf/type/__postgres_extension/gencode-remote b/cdist/conf/type/__postgres_extension/gencode-remote index f7895103..627067c7 100755 --- a/cdist/conf/type/__postgres_extension/gencode-remote +++ b/cdist/conf/type/__postgres_extension/gencode-remote @@ -33,7 +33,7 @@ case "$state_should" in echo "su - postgres -c 'psql -c \"$cmd\" \"$dbname\"'" ;; absent) - cmd="DROP EXTENSION IF EXISTS $extenstion" + cmd="DROP EXTENSION IF EXISTS $extension" echo "su - postgres -c 'psql -c \"$cmd\" \"$dbname\"'" ;; esac diff --git a/cdist/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote index fc491321..d14cf506 100755 --- a/cdist/conf/type/__process/gencode-remote +++ b/cdist/conf/type/__process/gencode-remote @@ -52,6 +52,7 @@ case "$state_should" in if [ -f "$__object/parameter/stop" ]; then cat "$__object/parameter/stop" else + # TODO: what should be runs variable? echo kill "${runs}" fi echo "stopped" >> "$__messages_out" diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote index 59ffc942..4ccfe301 100755 --- a/cdist/conf/type/__zypper_service/gencode-remote +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -76,7 +76,7 @@ case "$state_should" in echo "zypper $zypper_def_opts ref" ;; absent) - echo "zypper $zypper_def_opts removeservice $service_id" + echo "zypper $zypper_def_opts removeservice $exp_id" echo "zypper $zypper_def_opts refs" echo "zypper $zypper_def_opts ref" ;; From e9b823bc390c30cb9294591c628c5353d194d0ef Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 7 Oct 2018 09:59:01 +0200 Subject: [PATCH 0942/1332] Better fixes. --- cdist/conf/type/__cron/gencode-remote | 2 +- cdist/conf/type/__jail_freebsd10/gencode-remote | 2 +- cdist/conf/type/__jail_freebsd9/gencode-remote | 2 +- cdist/conf/type/__mount/gencode-remote | 2 +- cdist/conf/type/__package_pkgng_freebsd/gencode-remote | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index ee626485..59398058 100755 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -58,7 +58,7 @@ state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" # These are the old markers prefix="#cdist:__cron/$__object_id" suffix="#/cdist:__cron/$__object_id" -filter="^# DO NOT EDIT THIS FILE|^# \\(.* installed on |^# \\(Cron version V|^# \\(Cronie version .\\..\\)$" +filter='^# DO NOT EDIT THIS FILE|^# \(.* installed on |^# \(Cron version V|^# \(Cronie version .\..\)$' cat << DONE crontab -u $user -l 2>/dev/null | grep -v -E "$filter" | awk -v prefix="$prefix" -v suffix="$suffix" ' { diff --git a/cdist/conf/type/__jail_freebsd10/gencode-remote b/cdist/conf/type/__jail_freebsd10/gencode-remote index 73518326..4f376c25 100755 --- a/cdist/conf/type/__jail_freebsd10/gencode-remote +++ b/cdist/conf/type/__jail_freebsd10/gencode-remote @@ -45,7 +45,7 @@ else # when $state=present, it's required. Enforce this. if [ "$state" = "present" ]; then exec >&2 - echo "If --state is 'present,' --ip must be given\\!" + printf 'If --state is "present", --ip must be given\!\n' exit 1 fi fi diff --git a/cdist/conf/type/__jail_freebsd9/gencode-remote b/cdist/conf/type/__jail_freebsd9/gencode-remote index be583e5d..68229d3e 100755 --- a/cdist/conf/type/__jail_freebsd9/gencode-remote +++ b/cdist/conf/type/__jail_freebsd9/gencode-remote @@ -45,7 +45,7 @@ else # when $state=present, it's required. Enforce this. if [ "$state" = "present" ]; then exec >&2 - echo "If --state is 'present,' --ip must be given\\!" + printf 'If --state is "present", --ip must be given\!\n' exit 1 fi fi diff --git a/cdist/conf/type/__mount/gencode-remote b/cdist/conf/type/__mount/gencode-remote index e8266a0b..b2096764 100755 --- a/cdist/conf/type/__mount/gencode-remote +++ b/cdist/conf/type/__mount/gencode-remote @@ -39,7 +39,7 @@ case "$state_should" in printf ' -o %s' "$(cat "$__object/parameter/options")" fi printf ' %s' "$(cat "$__object/parameter/device")" - printf " %s\\n" "$path" + printf ' %s\n' "$path" else # mount using existing fstab entry printf 'mount "%s"\n' "$path" diff --git a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote index 592d4d0f..b72544c1 100755 --- a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote @@ -95,7 +95,7 @@ if [ -n "$curr_version" ]; then # PKG *is* installed if [ "$upgrade" = "true" ]; then execcmd "upg" "${cmd}" else - printf "Version %s is already installed and pkg-ng can't upgrade directly to version %s.\\nTo upgrade to the latest version, use the --upgrade flag.\\n" "$curr_version" "$version" >&2 + printf 'Version %s is already installed and pkg-ng cannot upgrade directly to version %s.\nTo upgrade to the latest version, use the --upgrade flag.\n' "$curr_version" "$version" >&2 exit 1 fi # PKG is supposed to be installed to the latest version From 334201b9452ef8bc6207e7cc8b118dc1ba0607e5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 7 Oct 2018 10:20:08 +0200 Subject: [PATCH 0943/1332] Fix remaining shellcheck problems. --- cdist/conf/type/__daemontools/manifest | 1 + cdist/conf/type/__grafana_dashboard/manifest | 1 + cdist/conf/type/__jail/manifest | 2 +- cdist/conf/type/__letsencrypt_cert/manifest | 2 +- cdist/conf/type/__mount/manifest | 2 +- cdist/conf/type/__postfix_master/manifest | 1 - cdist/conf/type/__process/gencode-remote | 3 +-- cdist/conf/type/__prometheus_alertmanager/manifest | 1 + cdist/conf/type/__prometheus_exporter/manifest | 1 + cdist/conf/type/__prometheus_server/manifest | 1 + cdist/conf/type/__ssh_authorized_keys/manifest | 2 +- 11 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__daemontools/manifest b/cdist/conf/type/__daemontools/manifest index 656f4984..b04c7e07 100755 --- a/cdist/conf/type/__daemontools/manifest +++ b/cdist/conf/type/__daemontools/manifest @@ -9,6 +9,7 @@ __directory "$servicedir" --mode 700 os=$(cat "$__global/explorer/os") init=$(cat "$__global/explorer/init") +require="" case $os in freebsd) # TODO change to __start_on_boot once it supports freebsd diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest index 2e9bd115..9cd1465d 100755 --- a/cdist/conf/type/__grafana_dashboard/manifest +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -3,6 +3,7 @@ os=$(cat "$__global/explorer/os") os_version=$(cat "$__global/explorer/os_version") +require="" case $os in debian|devuan) case $os_version in diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index adf9bd99..fad6a3a1 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -37,7 +37,7 @@ jaildir="$(cat "$__object/parameter/jaildir")" __directory "${jaildir}" --parents -set -- "$@" "$__object_id" "--state" "$state" +set -- "$@" "$__object_id" cd "$__object/parameter" for property in *; do set -- "$@" "--$property" "$(cat "$property")" diff --git a/cdist/conf/type/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest index 56e3532c..d6892c9b 100755 --- a/cdist/conf/type/__letsencrypt_cert/manifest +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -91,7 +91,7 @@ if [ -f "${__object}/parameter/automatic-renewal" ]; then renew_hook_param="${__object}/parameter/renew-hook" renew_hook="" if [ -f "${renew_hook_param}" ]; then - while read hook; do + while read -r hook; do renew_hook="${renew_hook} --renew-hook \"${hook}\"" done < "${renew_hook_param}" fi diff --git a/cdist/conf/type/__mount/manifest b/cdist/conf/type/__mount/manifest index 73937899..999d806c 100755 --- a/cdist/conf/type/__mount/manifest +++ b/cdist/conf/type/__mount/manifest @@ -31,7 +31,7 @@ printf " %s" "$type" options="$(cat "$__object/parameter/options")" printf " %s" "$options" printf " %s" "$(cat "$__object/parameter/dump")" -printf " %s\n" "$(cat "$__object/parameter/pass")" +printf ' %s\n' "$(cat "$__object/parameter/pass")" ) | \ __block "$__object_name" \ --file "/etc/fstab" \ diff --git a/cdist/conf/type/__postfix_master/manifest b/cdist/conf/type/__postfix_master/manifest index 94b5044f..0960ea41 100755 --- a/cdist/conf/type/__postfix_master/manifest +++ b/cdist/conf/type/__postfix_master/manifest @@ -50,7 +50,6 @@ entry="$__object/files/entry" echo "# $(cat "$__object/parameter/comment")" fi printf "%s " "$service" - printf "%s " "$type" for parameter in type private unpriv chroot wakeup maxproc; do printf "%s " "$(cat "$__object/parameter/$parameter")" done diff --git a/cdist/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote index d14cf506..ec9691b9 100755 --- a/cdist/conf/type/__process/gencode-remote +++ b/cdist/conf/type/__process/gencode-remote @@ -52,8 +52,7 @@ case "$state_should" in if [ -f "$__object/parameter/stop" ]; then cat "$__object/parameter/stop" else - # TODO: what should be runs variable? - echo kill "${runs}" + echo kill "$(cat "$__object/parameter/runs")" fi echo "stopped" >> "$__messages_out" ;; diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index 3f417526..64ef76af 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -15,6 +15,7 @@ storage_path="$(cat "$__object/parameter/storage-path")" ##### INSTALL THE PACKAGE ################################################### require_pkg="" # what to require if I want to require "the package" +require="" if [ -f "$__object/parameter/install-from-backports" ]; then os=$(cat "$__global/explorer/os") os_version=$(cat "$__global/explorer/os_version") diff --git a/cdist/conf/type/__prometheus_exporter/manifest b/cdist/conf/type/__prometheus_exporter/manifest index 35e654e2..b9e14531 100644 --- a/cdist/conf/type/__prometheus_exporter/manifest +++ b/cdist/conf/type/__prometheus_exporter/manifest @@ -7,6 +7,7 @@ exporter="$(cat "$__object/parameter/exporter")" __user prometheus --system +require="" case $exporter in node) TEXTFILES=/service/node-exporter/textfiles # path for the textfiles collector diff --git a/cdist/conf/type/__prometheus_server/manifest b/cdist/conf/type/__prometheus_server/manifest index 63b7b438..8685130f 100755 --- a/cdist/conf/type/__prometheus_server/manifest +++ b/cdist/conf/type/__prometheus_server/manifest @@ -18,6 +18,7 @@ rule_files="$(cat "$__object/parameter/rule-files")" ##### INSTALL THE PACKAGE ################################################### require_pkg="" # what to require if I want to require "the package" +require="" if [ -f "$__object/parameter/install-from-backports" ]; then os=$(cat "$__global/explorer/os") os_version=$(cat "$__global/explorer/os_version") diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 8cac3449..f6ff74c3 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -61,7 +61,7 @@ _cksum() { echo "$1" | cksum | cut -d' ' -f 1 } -while read key; do +while read -r key; do type_and_key="$(echo "$key" | tr ' ' '\n' | awk '/^(ssh|ecdsa)-[^ ]+/ { printf $1" "; getline; printf $1 }')" object_id="$(_cksum "$file")-$(_cksum "$type_and_key")" set -- "$object_id" From cb826ad5708a3ceaadd6616098fbb9cd793ee652 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 7 Oct 2018 18:47:38 +0200 Subject: [PATCH 0944/1332] ++changelog --- docs/changelog | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/docs/changelog b/docs/changelog index d7d31f52..1a3a7e2a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,21 +4,7 @@ Changelog next: * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) * Core: Add timestamp (optional) to log messages (Darko Poljak) - * Explorers, manifests, gencodes: Fix SC2166: and/or operators in test (shellcheck) (Jonas Weber, Thomas Eckert) - * Explorers and types: Fix SC2004: $/${} is unnecessary on arithmetic variables (shellcheck) (Darko Poljak) - * Explorers and types: Fix SC2005: Useless echo? Instead of echo $(cmd), just use cmd (shellcheck) (Darko Poljak) - * Explorers and types: Fix SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead (shellcheck) (Darko Poljak) - * Explorers and types: Fix SC2039: In POSIX sh, something is undefined (shellcheck) (Darko Poljak) - * Explorers and types: Fix SC2045: Iterating over ls output is fragile. Use globs. (shellcheck) (Thomas Eckert) - * Explorers and types: Fix SC2148: Tips depend on target shell and yours is unknown. Add a shebang. (shellcheck) (Thomas Eckert) - * Explorers and types: Fix SC2069: To redirect stdout+stderr, 2>&1 must be last (or use '{ cmd > file; } 2>&1' to clarify). (shellcheck) (Jonas Weber) - * Explorers and types: Fix SC2034: foo appears unused. Verify it or export it. (shellcheck) (Jonas Weber) - * Explorers and types: Fix SC2215, SC2059, SC2155, SC2091. (shellcheck) (Jonas Weber) - * Explorers and types: Fix SC2086: Double quote to prevent globbing and word splitting. (shellcheck) (Jonas Weber) - * Explorers and types: Fix SC2164: Use cd ... || exit in case cd fails. (shellcheck) (Darko Poljak) - * Explorers and types: Disable SC2016 where it is intended: Expressions don't expand in single quotes, use double quotes for that. (shellcheck) (Darko Poljak) - * Explorers and types: Fix SC2044: For loops over find output are fragile. Use find -exec or a while read loop. (shellcheck) (Darko Poljak) - * Explorers and types: Fix SC1090,SC2021,SC2028,SC2030,SC2031,SC2039,SC2046,SC2116,SC2119,SC2120,SC2143,SC2145,SC2153,SC2162,SC2196,SC2230,SC2235. (shellcheck) (Darko Poljak) + * Explorers and types: Fix shellcheck found problems and encountered bugs (Jonas Weber, Thomas Eckert, Darko Poljak) * Build: Add shellcheck makefile target and check when doing release (Darko Poljak) 4.10.3: 2018-09-23 From ab8f87864e2be88a9529eb68f346f6139f7443c1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 7 Oct 2018 19:09:14 +0200 Subject: [PATCH 0945/1332] Add shellcheck-ing for type explorers and auxiliary files. --- Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e9cacced..9f81cf06 100644 --- a/Makefile +++ b/Makefile @@ -262,6 +262,9 @@ pep8: shellcheck-global-explorers: @find cdist/conf/explorer -type f -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 +shellcheck-type-explorers: + @find cdist/conf/type -type f -path "*/explorer/*" -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 + shellcheck-manifests: @find cdist/conf/type -type f -name manifest -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 @@ -273,6 +276,11 @@ shellcheck-remote-gencodes: shellcheck-gencodes: shellcheck-local-gencodes shellcheck-remote-gencodes -shellcheck-types: shellcheck-manifests shellcheck-gencodes +shellcheck-types: shellcheck-type-explorers shellcheck-manifests shellcheck-gencodes shellcheck: shellcheck-global-explorers shellcheck-types + +shellcheck-type-files: + @find cdist/conf/type -type f -path "*/files/*" -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 + +shellcheck-with-files: shellcheck shellcheck-type-files From 638ddd95d6b7f07c88baa44a8c6aa1022bf405e0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 7 Oct 2018 19:41:44 +0200 Subject: [PATCH 0946/1332] Fix problems found by sellcheck in type explorers. --- cdist/conf/type/__apt_ppa/explorer/state | 3 ++- .../conf/type/__go_get/explorer/go-executable | 2 ++ .../type/__jail_freebsd10/explorer/status | 2 +- .../conf/type/__jail_freebsd9/explorer/status | 2 +- .../type/__postgres_database/explorer/state | 2 +- .../conf/type/__postgres_role/explorer/state | 2 +- .../type/__ssh_authorized_key/explorer/entry | 2 +- .../conf/type/__start_on_boot/explorer/state | 21 ++++++++++++++++--- .../type/__zypper_service/explorer/service_id | 2 +- 9 files changed, 28 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__apt_ppa/explorer/state b/cdist/conf/type/__apt_ppa/explorer/state index 2bb4f65a..d47e7d20 100755 --- a/cdist/conf/type/__apt_ppa/explorer/state +++ b/cdist/conf/type/__apt_ppa/explorer/state @@ -23,10 +23,11 @@ name="$__object_id" +# shellcheck disable=SC1091 . /etc/lsb-release repo_name="${name#ppa:}" -repo_file_name="$(echo "$repo_name" | sed -e "s|[/:]|-|" -e "s|\.|_|")-${DISTRIB_CODENAME}.list" +repo_file_name="$(echo "$repo_name" | sed -e 's|[/:]|-|' -e 's|\.|_|')-${DISTRIB_CODENAME}.list" [ -s "/etc/apt/sources.list.d/${repo_file_name}" ] \ && echo present || echo absent diff --git a/cdist/conf/type/__go_get/explorer/go-executable b/cdist/conf/type/__go_get/explorer/go-executable index bdce7559..87182282 100755 --- a/cdist/conf/type/__go_get/explorer/go-executable +++ b/cdist/conf/type/__go_get/explorer/go-executable @@ -1,4 +1,6 @@ #!/bin/sh +# shellcheck disable=SC1091 [ -f /etc/environment ] && . /etc/environment +# shellcheck disable=SC1091 [ -f /etc/profile ] && . /etc/profile go version 2>/dev/null || true diff --git a/cdist/conf/type/__jail_freebsd10/explorer/status b/cdist/conf/type/__jail_freebsd10/explorer/status index 1ceba212..c8039f21 100755 --- a/cdist/conf/type/__jail_freebsd10/explorer/status +++ b/cdist/conf/type/__jail_freebsd10/explorer/status @@ -39,7 +39,7 @@ fi # backslash-escaped $jaildir sjaildir="$(echo ${jaildir} | sed 's#/#\\/#g')" -jls_output="$(jls | grep "[ ]${sjaildir}\/${name}\$")" || true +jls_output="$(jls | grep "[ ]${sjaildir}\\/${name}\$")" || true if [ -n "${jls_output}" ]; then echo "STARTED" diff --git a/cdist/conf/type/__jail_freebsd9/explorer/status b/cdist/conf/type/__jail_freebsd9/explorer/status index 1ceba212..c8039f21 100755 --- a/cdist/conf/type/__jail_freebsd9/explorer/status +++ b/cdist/conf/type/__jail_freebsd9/explorer/status @@ -39,7 +39,7 @@ fi # backslash-escaped $jaildir sjaildir="$(echo ${jaildir} | sed 's#/#\\/#g')" -jls_output="$(jls | grep "[ ]${sjaildir}\/${name}\$")" || true +jls_output="$(jls | grep "[ ]${sjaildir}\\/${name}\$")" || true if [ -n "${jls_output}" ]; then echo "STARTED" diff --git a/cdist/conf/type/__postgres_database/explorer/state b/cdist/conf/type/__postgres_database/explorer/state index dc9659e2..54eb768d 100755 --- a/cdist/conf/type/__postgres_database/explorer/state +++ b/cdist/conf/type/__postgres_database/explorer/state @@ -20,7 +20,7 @@ name="$__object_id" -if su - postgres -c "echo '\q' | psql '$name'" 2>/dev/null; then +if su - postgres -c "echo '\\q' | psql '$name'" 2>/dev/null; then echo "present" else echo "absent" diff --git a/cdist/conf/type/__postgres_role/explorer/state b/cdist/conf/type/__postgres_role/explorer/state index 8c102df9..40f64cef 100755 --- a/cdist/conf/type/__postgres_role/explorer/state +++ b/cdist/conf/type/__postgres_role/explorer/state @@ -20,7 +20,7 @@ name="$__object_id" -if su - postgres -c "psql -c '\du' | grep -q '^ *$name *|'"; then +if su - postgres -c "psql -c '\\du' | grep -q '^ *$name *|'"; then echo "present" else echo "absent" diff --git a/cdist/conf/type/__ssh_authorized_key/explorer/entry b/cdist/conf/type/__ssh_authorized_key/explorer/entry index b528b26e..78efbb48 100755 --- a/cdist/conf/type/__ssh_authorized_key/explorer/entry +++ b/cdist/conf/type/__ssh_authorized_key/explorer/entry @@ -27,5 +27,5 @@ then file="$(cat "$__object/parameter/file")" # get any entries that match the type and key - grep ".*$type_and_key\([ \n]\|$\)" "$file" || true + grep ".*$type_and_key\\([ \\n]\\|$\\)" "$file" || true fi diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index d8f9b7ba..cef9013e 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -38,12 +38,27 @@ if [ "$init" = 'systemd' ]; then else case "$os" in debian|openwrt|devuan) - state="present" - [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" + state="absent" + for file in "/etc/rc$runlevel.d/S"??"$name" + do + if [ -f "$file" ] + then + state="present" + break + fi + done ;; ubuntu) state="absent" - [ -f "/etc/rc$runlevel.d/S"??"$name" ] && state="present" + for file in "/etc/rc$runlevel.d/S"??"$name" + do + if [ -f "$file" ] + then + state="present" + break + fi + done + [ -f "/etc/init/${name}.conf" ] && state="present" ;; diff --git a/cdist/conf/type/__zypper_service/explorer/service_id b/cdist/conf/type/__zypper_service/explorer/service_id index 91858d84..7161f804 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_id +++ b/cdist/conf/type/__zypper_service/explorer/service_id @@ -27,4 +27,4 @@ else fi # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 1 ) -zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\<$uri\>" | cut -d'|' -f 1 +zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\\<$uri\\>" | cut -d'|' -f 1 From ec186673bf4021d67221d011921ce7165e9473f0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 7 Oct 2018 19:46:34 +0200 Subject: [PATCH 0947/1332] Add TODO markers for SC2012. --- cdist/conf/type/__link/explorer/state | 3 +++ cdist/conf/type/__link/explorer/type | 1 + 2 files changed, 4 insertions(+) diff --git a/cdist/conf/type/__link/explorer/state b/cdist/conf/type/__link/explorer/state index 587835a2..edccf08d 100755 --- a/cdist/conf/type/__link/explorer/state +++ b/cdist/conf/type/__link/explorer/state @@ -33,6 +33,7 @@ destination_dir="${destination%/*}" case "$type" in symbolic) cd "$destination_dir" || exit 1 + # TODO SC2012: use readlink or something? source_is=$(ls -l "$destination" | sed 's/.*-> //g') if [ -h "$destination" ]; then # ignore trailing slashes for comparison @@ -52,7 +53,9 @@ case "$type" in echo sourcemissing exit 0 fi + # TODO SC2012: use stat? destination_inode=$(ls -i "$destination" | awk '{print $1}') + # TODO SC2012: use stat? source_inode=$(ls -i "$source" | awk '{print $1}') if [ "$destination_inode" -eq "$source_inode" ]; then echo present diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type index 48a79bf0..aa1aff2c 100755 --- a/cdist/conf/type/__link/explorer/type +++ b/cdist/conf/type/__link/explorer/type @@ -31,6 +31,7 @@ elif [ -f "$destination" ]; then type="$(cat "$__object/parameter/type")" case "$type" in hard) + # TODO SC2012: use stat? link_count=$(ls -l "$destination" | awk '{ print $2 }') if [ "$link_count" -gt 1 ]; then echo hardlink From 0458f66c96b1061b81f759cfa47f8fe20f2d66ae Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 8 Oct 2018 15:35:29 +0200 Subject: [PATCH 0948/1332] Resolve SC2012. --- cdist/conf/type/__link/explorer/state | 11 +++++---- cdist/conf/type/__link/explorer/type | 34 ++++++++++++++------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/cdist/conf/type/__link/explorer/state b/cdist/conf/type/__link/explorer/state index edccf08d..a601d53b 100755 --- a/cdist/conf/type/__link/explorer/state +++ b/cdist/conf/type/__link/explorer/state @@ -33,8 +33,7 @@ destination_dir="${destination%/*}" case "$type" in symbolic) cd "$destination_dir" || exit 1 - # TODO SC2012: use readlink or something? - source_is=$(ls -l "$destination" | sed 's/.*-> //g') + source_is=$(readlink "$destination") if [ -h "$destination" ]; then # ignore trailing slashes for comparison if [ "${source_is%/}" = "${source%/}" ]; then @@ -53,9 +52,13 @@ case "$type" in echo sourcemissing exit 0 fi - # TODO SC2012: use stat? + # Currently not worth the effor to change it, stat is not defined by POSIX + # and different OSes has different implementations for it. + # shellcheck disable=SC2012 destination_inode=$(ls -i "$destination" | awk '{print $1}') - # TODO SC2012: use stat? + # Currently not worth the effor to change it, stat is not defined by POSIX + # and different OSes has different implementations for it. + # shellcheck disable=SC2012 source_inode=$(ls -i "$source" | awk '{print $1}') if [ "$destination_inode" -eq "$source_inode" ]; then echo present diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type index aa1aff2c..796f1ac6 100755 --- a/cdist/conf/type/__link/explorer/type +++ b/cdist/conf/type/__link/explorer/type @@ -24,24 +24,26 @@ destination="/$__object_id" if [ ! -e "$destination" ]; then - echo none + echo none elif [ -h "$destination" ]; then - echo symlink + echo symlink elif [ -f "$destination" ]; then - type="$(cat "$__object/parameter/type")" - case "$type" in - hard) - # TODO SC2012: use stat? - link_count=$(ls -l "$destination" | awk '{ print $2 }') - if [ "$link_count" -gt 1 ]; then - echo hardlink - exit 0 - fi - ;; - esac - echo file + type="$(cat "$__object/parameter/type")" + case "$type" in + hard) + # Currently not worth the effor to change it, stat is not defined by POSIX + # and different OSes has different implementations for it. + # shellcheck disable=SC2012 + ink_count=$(ls -l "$destination" | awk '{ print $2 }') + if [ "$link_count" -gt 1 ]; then + echo hardlink + exit 0 + fi + ;; + esac + echo file elif [ -d "$destination" ]; then - echo directory + echo directory else - echo unknown + echo unknown fi From 69790ec138a9ef63c179b5d2ca3777c758ed7347 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 8 Oct 2018 15:43:42 +0200 Subject: [PATCH 0949/1332] Fix typing error. --- cdist/conf/type/__link/explorer/type | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type index 796f1ac6..b322bf42 100755 --- a/cdist/conf/type/__link/explorer/type +++ b/cdist/conf/type/__link/explorer/type @@ -34,7 +34,7 @@ elif [ -f "$destination" ]; then # Currently not worth the effor to change it, stat is not defined by POSIX # and different OSes has different implementations for it. # shellcheck disable=SC2012 - ink_count=$(ls -l "$destination" | awk '{ print $2 }') + link_count=$(ls -l "$destination" | awk '{ print $2 }') if [ "$link_count" -gt 1 ]; then echo hardlink exit 0 From 9afc17f3f8fee41285fa915264aac4ae52046efc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Oct 2018 10:37:29 +0200 Subject: [PATCH 0950/1332] Make cdist.test return exit code. --- cdist/test/__main__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/test/__main__.py b/cdist/test/__main__.py index 08e839d1..c8c7df3b 100644 --- a/cdist/test/__main__.py +++ b/cdist/test/__main__.py @@ -45,4 +45,5 @@ for test_module in test_modules: suites.append(suite) all_suites = unittest.TestSuite(suites) -unittest.TextTestRunner(verbosity=2).run(all_suites) +rv = unittest.TextTestRunner(verbosity=2).run(all_suites).wasSuccessful() +sys.exit(not rv) From 0b58ab8c83d86d72eb33d220e9a2e76ac95a04d6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Oct 2018 12:34:31 +0200 Subject: [PATCH 0951/1332] Bypass Configuration singleton from other tests if any. --- cdist/test/exec/local.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdist/test/exec/local.py b/cdist/test/exec/local.py index 0e0cc755..0865b7dc 100644 --- a/cdist/test/exec/local.py +++ b/cdist/test/exec/local.py @@ -170,6 +170,9 @@ class LocalTestCase(test.CdistTestCase): os.environ['CDIST_PATH'] = conf_dir + # bypass singleton from other tests if any + cc.Configuration.instance = None + configuration = cc.Configuration(argparse.Namespace(), env=os.environ) From c58e12a4b9b321346159d54f0aea63a7430add43 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 7 Oct 2018 20:27:57 +0200 Subject: [PATCH 0952/1332] shellcheck on /files/ scripts. --- .../__consul_agent/files/consul.sysv-debian | 2 ++ .../__consul_agent/files/consul.sysv-redhat | 18 +++++----- .../files/consul-template.sysv | 18 +++++----- .../type/__daemontools/files/init.d-svscan | 34 +++++++++---------- .../type/__install_config/files/remote/copy | 4 +-- .../type/__install_config/files/remote/exec | 4 +-- .../files/lib.sh | 34 ++++++++++--------- .../type/__iptables_apply/files/init-script | 4 +-- .../type/__key_value/files/remote_script.sh | 14 ++++---- .../conf/type/__yum_repo/files/repo.template | 2 +- 10 files changed, 72 insertions(+), 62 deletions(-) diff --git a/cdist/conf/type/__consul_agent/files/consul.sysv-debian b/cdist/conf/type/__consul_agent/files/consul.sysv-debian index d364d6c4..4f43c000 100644 --- a/cdist/conf/type/__consul_agent/files/consul.sysv-debian +++ b/cdist/conf/type/__consul_agent/files/consul.sysv-debian @@ -31,9 +31,11 @@ ### END INIT INFO if [ -f "/etc/default/consul" ]; then + # shellcheck disable=SC1091 . /etc/default/consul fi +# shellcheck disable=SC1091 . /lib/lsb/init-functions NAME=consul diff --git a/cdist/conf/type/__consul_agent/files/consul.sysv-redhat b/cdist/conf/type/__consul_agent/files/consul.sysv-redhat index 13dafd2e..e9c869e5 100644 --- a/cdist/conf/type/__consul_agent/files/consul.sysv-redhat +++ b/cdist/conf/type/__consul_agent/files/consul.sysv-redhat @@ -11,6 +11,7 @@ # pidfile: /var/run/consul/pidfile # Source function library. +# shellcheck disable=SC1091 . /etc/init.d/functions NAME=consul CONSUL=/usr/local/bin/consul @@ -18,6 +19,7 @@ CONFIG=/etc/$NAME/conf.d PID_FILE=/var/run/$NAME/pidfile LOG_FILE=/var/log/$NAME +# shellcheck disable=SC1090 [ -e /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME export GOMAXPROCS=${GOMAXPROCS:-2} @@ -27,7 +29,7 @@ chmod 2770 /var/run/$NAME start() { - echo -n "Starting $NAME: " + printf "Starting %s" "$NAME: " daemon --user=consul \ --pidfile="$PID_FILE" \ "$CONSUL" agent -pid-file="$PID_FILE" -config-dir "$CONFIG" >> "$LOG_FILE" & @@ -37,7 +39,7 @@ start() { } stop() { - echo -n "Shutting down $NAME: " + printf "Shutting down %s" "$NAME: " killproc -p "$PID_FILE" $NAME retcode=$? rm -f /var/lock/subsys/$NAME @@ -46,14 +48,14 @@ stop() { case "$1" in start) - if $(status -p "$PID_FILE" $NAME >/dev/null); then + if status -p "$PID_FILE" $NAME >/dev/null; then echo "$NAME already running" else start fi ;; stop) - if $(status -p "$PID_FILE" $NAME >/dev/null); then + if status -p "$PID_FILE" $NAME >/dev/null; then stop else echo "$NAME not running" @@ -67,21 +69,21 @@ case "$1" in exit $? ;; restart) - if $(status -p "$PID_FILE" $NAME >/dev/null); then + if status -p "$PID_FILE" $NAME >/dev/null; then stop fi start ;; reload) - if $(status -p "$PID_FILE" $NAME >/dev/null); then - kill -HUP `cat $PID_FILE` + if status -p "$PID_FILE" $NAME >/dev/null; then + kill -HUP "$(cat "$PID_FILE")" else echo "$NAME not running" fi ;; condrestart) if [ -f /var/lock/subsys/$NAME ]; then - if $(status -p "$PID_FILE" $NAME >/dev/null); then + if status -p "$PID_FILE" $NAME >/dev/null; then stop fi start diff --git a/cdist/conf/type/__consul_template/files/consul-template.sysv b/cdist/conf/type/__consul_template/files/consul-template.sysv index 0a463020..2375f8cf 100644 --- a/cdist/conf/type/__consul_template/files/consul-template.sysv +++ b/cdist/conf/type/__consul_template/files/consul-template.sysv @@ -10,6 +10,7 @@ # pidfile: /var/run/consul-template/pidfile # Source function library. +# shellcheck disable=SC1091 . /etc/init.d/functions NAME=consul-template CONSUL_TEMPLATE=/usr/local/bin/consul-template @@ -17,6 +18,7 @@ CONFIG=/etc/$NAME/conf.d PID_FILE=/var/run/$NAME/pidfile LOG_FILE=/var/log/$NAME +# shellcheck disable=SC1090 [ -e /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME export CONSUL_TEMPLATE_LOG=${CONSUL_TEMPLATE_LOG:-info} export GOMAXPROCS=${GOMAXPROCS:-2} @@ -24,7 +26,7 @@ export GOMAXPROCS=${GOMAXPROCS:-2} mkdir -p /var/run/$NAME start() { - echo -n "Starting $NAME: " + printf "Starting %s" "$NAME: " daemon --pidfile="$PID_FILE" \ "$CONSUL_TEMPLATE" -config "$CONFIG" >> "$LOG_FILE" 2>&1 & echo $! > "$PID_FILE" @@ -34,7 +36,7 @@ start() { } stop() { - echo -n "Shutting down $NAME: " + printf "Shutting down %s" "$NAME: " killproc -p $PID_FILE $CONSUL_TEMPLATE retcode=$? rm -f /var/lock/subsys/$NAME @@ -43,14 +45,14 @@ stop() { case "$1" in start) - if $(status -p "$PID_FILE" $NAME >/dev/null); then + if status -p "$PID_FILE" $NAME >/dev/null; then echo "$NAME already running" else start fi ;; stop) - if $(status -p "$PID_FILE" $NAME >/dev/null); then + if status -p "$PID_FILE" $NAME >/dev/null; then stop else echo "$NAME not running" @@ -61,21 +63,21 @@ case "$1" in exit $? ;; restart) - if $(status -p "$PID_FILE" $NAME >/dev/null); then + if status -p "$PID_FILE" $NAME >/dev/null; then stop fi start ;; reload) - if $(status -p "$PID_FILE" $NAME >/dev/null); then - kill -HUP `cat $PID_FILE` + if status -p "$PID_FILE" $NAME >/dev/null; then + kill -HUP "$(cat "$PID_FILE")" else echo "$NAME not running" fi ;; condrestart) if [ -f /var/lock/subsys/$NAME ]; then - if $(status -p "$PID_FILE" $NAME >/dev/null); then + if status -p "$PID_FILE" $NAME >/dev/null; then stop fi start diff --git a/cdist/conf/type/__daemontools/files/init.d-svscan b/cdist/conf/type/__daemontools/files/init.d-svscan index 127dfdb3..6b4dba1d 100644 --- a/cdist/conf/type/__daemontools/files/init.d-svscan +++ b/cdist/conf/type/__daemontools/files/init.d-svscan @@ -23,9 +23,9 @@ fi case "$1" in start) - echo -n "Starting daemontools: " - if [ ! `pidof svscan` ]; then - echo -n "svscan " + printf "Starting daemontools: " + if [ ! "$(pidof svscan)" ]; then + printf "svscan " env - PATH="$PATH" svscan /service 2>&1 | setuidgid daemon multilog t /var/log/svscan & echo "." else @@ -33,23 +33,23 @@ case "$1" in fi ;; stop) - echo -n "Stopping daemontools: " - if [ `pidof svscan` ]; then - echo -n "svscan" - while [ `pidof svscan` ]; do - kill `pidof svscan` - echo -n "." + printf "Stopping daemontools: " + if [ "$(pidof svscan)" ]; then + printf "svscan" + while [ "$(pidof svscan)" ]; do + kill "$(pidof svscan)" + printf "." done fi - echo -n " services" - for i in `ls -d /service/*`; do - svc -dx $i - echo -n "." + printf " services" + for i in /service/*; do + svc -dx "$i" + printf "." done - echo -n " logging " - for i in `ls -d /service/*/log`; do - svc -dx $i - echo -n "." + printf " logging " + for i in /service/*/log; do + svc -dx "$i" + printf "." done echo "" ;; diff --git a/cdist/conf/type/__install_config/files/remote/copy b/cdist/conf/type/__install_config/files/remote/copy index 15c901f9..78af31b9 100755 --- a/cdist/conf/type/__install_config/files/remote/copy +++ b/cdist/conf/type/__install_config/files/remote/copy @@ -37,10 +37,10 @@ code="$(echo "$@" | sed "s|$target_host:|$target_host:$chroot|g")" log "target_host: $target_host" log "chroot: $chroot" -log "@: $@" +log "@: $*" log "code: $code" # copy files into chroot -$__default_remote_copy $code +"$__default_remote_copy" "$code" log "-----" diff --git a/cdist/conf/type/__install_config/files/remote/exec b/cdist/conf/type/__install_config/files/remote/exec index 5b25e41e..ea7396e0 100755 --- a/cdist/conf/type/__install_config/files/remote/exec +++ b/cdist/conf/type/__install_config/files/remote/exec @@ -40,10 +40,10 @@ code="chroot $chroot sh -e -c '$code'" log "target_host: $target_host" log "chroot: $chroot" -log "@: $@" +log "@: $*" log "code: $code" # Run the code -$__default_remote_exec $target_host $code +"$__default_remote_exec" "$target_host" "$code" log "-----" diff --git a/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh b/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh index 13ead401..2db9a441 100644 --- a/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh +++ b/cdist/conf/type/__install_partition_msdos_apply/files/lib.sh @@ -1,9 +1,11 @@ +#!/bin/sh + die() { - echo "[__install_partition_msdos_apply] $@" >&2 + echo "[__install_partition_msdos_apply] $*" >&2 exit 1 } debug() { - #echo "[__install_partition_msdos_apply] $@" >&2 + #echo "[__install_partition_msdos_apply] $*" >&2 : } @@ -12,7 +14,7 @@ fdisk_command() { cmd="$2" debug fdisk_command "running fdisk command '${cmd}' on device ${device}" - printf "${cmd}\nw\n" | fdisk -c -u "$device" + printf '%s\nw\n' "${cmd}" | fdisk -c -u "$device" ret=$? # give disk some time sleep 1 @@ -23,14 +25,14 @@ create_disklabel() { device=$1 debug create_disklabel "creating new msdos disklabel" - fdisk_command ${device} "o" + fdisk_command "${device}" "o" return $? } toggle_bootable() { device="$1" minor="$2" - fdisk_command ${device} "a\n${minor}\n" + fdisk_command "${device}" "a\\n${minor}\\n" return $? } @@ -41,28 +43,28 @@ create_partition() { type="$4" primary_count="$5" - if [ "$type" = "extended" -o "$type" = "5" ]; then + if [ "$type" = "extended" ] || [ "$type" = "5" ]; then # Extended partition - primary_extended="e\n" - first_minor="${minor}\n" + primary_extended='e\n' + first_minor="${minor}\\n" [ "${minor}" = "4" ] && first_minor="" - type_minor="${minor}\n" + type_minor="${minor}\\n" [ "${minor}" = "1" ] && type_minor="" type="5" elif [ "${minor}" -lt "5" ]; then - primary_extended="p\n" - first_minor="${minor}\n" + primary_extended='p\n' + first_minor="${minor}\\n" [ "${minor}" = "4" ] && first_minor="" - type_minor="${minor}\n" + type_minor="${minor}\\n" [ "${minor}" = "1" ] && type_minor="" else # Logical partitions - first_minor="${minor}\n" - type_minor="${minor}\n" - primary_extended="l\n" + first_minor="${minor}\\n" + type_minor="${minor}\\n" + primary_extended='l\n' [ "$primary_count" -gt "3" ] && primary_extended="" fi [ -n "${size}" ] && size="+${size}M" - fdisk_command ${device} "n\n${primary_extended}${first_minor}\n${size}\nt\n${type_minor}${type}\n" + fdisk_command "${device}" "n\\n${primary_extended}${first_minor}\\n${size}\\nt\\n${type_minor}${type}\\n" return $? } diff --git a/cdist/conf/type/__iptables_apply/files/init-script b/cdist/conf/type/__iptables_apply/files/init-script index 2247dcf5..7c08ce08 100644 --- a/cdist/conf/type/__iptables_apply/files/init-script +++ b/cdist/conf/type/__iptables_apply/files/init-script @@ -24,14 +24,14 @@ case $1 in iptables-save > "$status" # Apply our ruleset - cd "$basedir" + cd "$basedir" || exit count="$(ls -1 | wc -l)" # Only do something if there are rules if [ "$count" -ge 1 ]; then for rule in *; do echo "Applying iptables rule $rule ..." - iptables $(cat "$rule") + iptables "$(cat "$rule")" done fi ;; diff --git a/cdist/conf/type/__key_value/files/remote_script.sh b/cdist/conf/type/__key_value/files/remote_script.sh index 52b3f2de..f7a1add5 100644 --- a/cdist/conf/type/__key_value/files/remote_script.sh +++ b/cdist/conf/type/__key_value/files/remote_script.sh @@ -1,19 +1,21 @@ #!/bin/sh -export key="$(cat "$__object/parameter/key" 2>/dev/null \ +key="$(cat "$__object/parameter/key" 2>/dev/null \ || echo "$__object_id")" -export state="$(cat "$__object/parameter/state")" +state="$(cat "$__object/parameter/state")" file="$(cat "$__object/parameter/file")" -export delimiter="$(cat "$__object/parameter/delimiter")" -export value="$(cat "$__object/parameter/value" 2>/dev/null \ +delimiter="$(cat "$__object/parameter/delimiter")" +value="$(cat "$__object/parameter/value" 2>/dev/null \ || echo "__CDIST_NOTSET__")" +export key state delimiter value if [ -f "$__object/parameter/exact_delimiter" ]; then - export exact_delimiter=1 + exact_delimiter=1 else - export exact_delimiter=0 + exact_delimiter=0 fi +export exact_delimiter tmpfile=$(mktemp "${file}.cdist.XXXXXXXXXX") # preserve ownership and permissions by copying existing file over tmpfile diff --git a/cdist/conf/type/__yum_repo/files/repo.template b/cdist/conf/type/__yum_repo/files/repo.template index 3e14c8b6..18ea9d2b 100755 --- a/cdist/conf/type/__yum_repo/files/repo.template +++ b/cdist/conf/type/__yum_repo/files/repo.template @@ -43,7 +43,7 @@ for key in baseurl gpgkey; do if [ -f "$__object/parameter/$key" ]; then printf '%s=' "$key" prefix='' - while read line; do + while read -r line; do printf '%s%s\n' "$prefix" "$line" prefix=' ' done < "$__object/parameter/$key" From 0f31a550cc2a6a4e5468c40b854d3f5bd08e83e2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 7 Oct 2018 22:26:18 +0200 Subject: [PATCH 0953/1332] Fix SC2012. --- cdist/conf/type/__iptables_apply/files/init-script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__iptables_apply/files/init-script b/cdist/conf/type/__iptables_apply/files/init-script index 7c08ce08..aee40cbb 100644 --- a/cdist/conf/type/__iptables_apply/files/init-script +++ b/cdist/conf/type/__iptables_apply/files/init-script @@ -25,7 +25,7 @@ case $1 in # Apply our ruleset cd "$basedir" || exit - count="$(ls -1 | wc -l)" + count="$(find . ! -name . -prune | wc -l)" # Only do something if there are rules if [ "$count" -ge 1 ]; then From dcb4395909124e5680686cb314df6bda6b30fdcf Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 8 Oct 2018 17:13:13 +0200 Subject: [PATCH 0954/1332] Resolve custom remote copy/exec shellcheck (non-)issues. --- cdist/conf/type/__install_config/files/remote/copy | 4 +++- cdist/conf/type/__install_config/files/remote/exec | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__install_config/files/remote/copy b/cdist/conf/type/__install_config/files/remote/copy index 78af31b9..0f68b1ea 100755 --- a/cdist/conf/type/__install_config/files/remote/copy +++ b/cdist/conf/type/__install_config/files/remote/copy @@ -41,6 +41,8 @@ log "@: $*" log "code: $code" # copy files into chroot -"$__default_remote_copy" "$code" +# code should be split on spaces +# shellcheck disable=SC2086 +"$__default_remote_copy" $code log "-----" diff --git a/cdist/conf/type/__install_config/files/remote/exec b/cdist/conf/type/__install_config/files/remote/exec index ea7396e0..3a48c58f 100755 --- a/cdist/conf/type/__install_config/files/remote/exec +++ b/cdist/conf/type/__install_config/files/remote/exec @@ -36,6 +36,7 @@ shift # escape ' with '"'"' code="$(echo "$@" | sed -e "s/'/'\"'\"'/g")" +# shellcheck disable=SC2089 code="chroot $chroot sh -e -c '$code'" log "target_host: $target_host" @@ -44,6 +45,8 @@ log "@: $*" log "code: $code" # Run the code -"$__default_remote_exec" "$target_host" "$code" +# code should be split on spaces +# shellcheck disable=SC2086,SC2090 +"$__default_remote_exec" "$target_host" $code log "-----" From 53300b1004adf33405e6637117ae97e279716772 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 9 Oct 2018 18:25:03 +0200 Subject: [PATCH 0955/1332] Fix after shellcheck. --- cdist/conf/type/__install_config/files/remote/copy | 4 ++-- cdist/conf/type/__install_config/files/remote/exec | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__install_config/files/remote/copy b/cdist/conf/type/__install_config/files/remote/copy index 0f68b1ea..fa7fa9b7 100755 --- a/cdist/conf/type/__install_config/files/remote/copy +++ b/cdist/conf/type/__install_config/files/remote/copy @@ -41,8 +41,8 @@ log "@: $*" log "code: $code" # copy files into chroot -# code should be split on spaces +# __default_remote_copy and code should be split # shellcheck disable=SC2086 -"$__default_remote_copy" $code +$__default_remote_copy $code log "-----" diff --git a/cdist/conf/type/__install_config/files/remote/exec b/cdist/conf/type/__install_config/files/remote/exec index 3a48c58f..c2057ebf 100755 --- a/cdist/conf/type/__install_config/files/remote/exec +++ b/cdist/conf/type/__install_config/files/remote/exec @@ -45,8 +45,8 @@ log "@: $*" log "code: $code" # Run the code -# code should be split on spaces +# __default_remote_exec and code should be split # shellcheck disable=SC2086,SC2090 -"$__default_remote_exec" "$target_host" $code +$__default_remote_exec "$target_host" $code log "-----" From 8669ccb9c17616a20c4fe7f7074e2aaade5aeca0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 9 Oct 2018 18:25:35 +0200 Subject: [PATCH 0956/1332] Improve shell code. --- cdist/conf/type/__daemontools/files/init.d-svscan | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__daemontools/files/init.d-svscan b/cdist/conf/type/__daemontools/files/init.d-svscan index 6b4dba1d..996eb4e8 100644 --- a/cdist/conf/type/__daemontools/files/init.d-svscan +++ b/cdist/conf/type/__daemontools/files/init.d-svscan @@ -24,7 +24,7 @@ fi case "$1" in start) printf "Starting daemontools: " - if [ ! "$(pidof svscan)" ]; then + if ! pidof svscan > /dev/null 2>&1; then printf "svscan " env - PATH="$PATH" svscan /service 2>&1 | setuidgid daemon multilog t /var/log/svscan & echo "." @@ -34,11 +34,16 @@ case "$1" in ;; stop) printf "Stopping daemontools: " - if [ "$(pidof svscan)" ]; then + pids="$(pidof svscan)" + if [ -n "${pids}" ] + then printf "svscan" - while [ "$(pidof svscan)" ]; do - kill "$(pidof svscan)" - printf "." + while [ -n "${pids}" ] + do + # shellcheck disable=SC2086 + kill ${pids} + printf "." + pids="$(pidof svscan)" done fi printf " services" From 610deba4543ed1f52a4831fcd61f1a375a4135bf Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Oct 2018 12:52:50 +0200 Subject: [PATCH 0957/1332] Improve quoting. --- .../files/consul-template.sysv | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/cdist/conf/type/__consul_template/files/consul-template.sysv b/cdist/conf/type/__consul_template/files/consul-template.sysv index 2375f8cf..b263915a 100644 --- a/cdist/conf/type/__consul_template/files/consul-template.sysv +++ b/cdist/conf/type/__consul_template/files/consul-template.sysv @@ -10,74 +10,75 @@ # pidfile: /var/run/consul-template/pidfile # Source function library. + # shellcheck disable=SC1091 . /etc/init.d/functions NAME=consul-template CONSUL_TEMPLATE=/usr/local/bin/consul-template -CONFIG=/etc/$NAME/conf.d -PID_FILE=/var/run/$NAME/pidfile -LOG_FILE=/var/log/$NAME +CONFIG="/etc/$NAME/conf.d" +PID_FILE="/var/run/$NAME/pidfile" +LOG_FILE="/var/log/$NAME" # shellcheck disable=SC1090 -[ -e /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME -export CONSUL_TEMPLATE_LOG=${CONSUL_TEMPLATE_LOG:-info} -export GOMAXPROCS=${GOMAXPROCS:-2} +[ -e "/etc/sysconfig/$NAME" ] && . "/etc/sysconfig/$NAME" +export CONSUL_TEMPLATE_LOG="${CONSUL_TEMPLATE_LOG:-info}" +export GOMAXPROCS="${GOMAXPROCS:-2}" -mkdir -p /var/run/$NAME +mkdir -p "/var/run/$NAME" start() { - printf "Starting %s" "$NAME: " + printf "Starting %s: " "$NAME" daemon --pidfile="$PID_FILE" \ "$CONSUL_TEMPLATE" -config "$CONFIG" >> "$LOG_FILE" 2>&1 & - echo $! > "$PID_FILE" + echo "$!" > "$PID_FILE" retcode=$? - touch /var/lock/subsys/$NAME - return $retcode + touch "/var/lock/subsys/$NAME" + return "$retcode" } stop() { - printf "Shutting down %s" "$NAME: " - killproc -p $PID_FILE $CONSUL_TEMPLATE + printf "Shutting down %s: " "$NAME" + killproc -p "$PID_FILE" "$CONSUL_TEMPLATE" retcode=$? - rm -f /var/lock/subsys/$NAME - return $retcode + rm -f "/var/lock/subsys/$NAME" + return "$retcode" } case "$1" in start) - if status -p "$PID_FILE" $NAME >/dev/null; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then echo "$NAME already running" else start fi ;; stop) - if status -p "$PID_FILE" $NAME >/dev/null; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then stop else echo "$NAME not running" fi ;; status) - status -p "$PID_FILE" $NAME + status -p "$PID_FILE" "$NAME" exit $? ;; restart) - if status -p "$PID_FILE" $NAME >/dev/null; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then stop fi start ;; reload) - if status -p "$PID_FILE" $NAME >/dev/null; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then kill -HUP "$(cat "$PID_FILE")" else echo "$NAME not running" fi ;; condrestart) - if [ -f /var/lock/subsys/$NAME ]; then - if status -p "$PID_FILE" $NAME >/dev/null; then + if [ -f "/var/lock/subsys/$NAME" ]; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then stop fi start From 7a9dea975439fc4894107f9c124d5874cc416c84 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Oct 2018 12:56:48 +0200 Subject: [PATCH 0958/1332] Improve quoting. --- .../__consul_agent/files/consul.sysv-redhat | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/cdist/conf/type/__consul_agent/files/consul.sysv-redhat b/cdist/conf/type/__consul_agent/files/consul.sysv-redhat index e9c869e5..58fc9bd9 100644 --- a/cdist/conf/type/__consul_agent/files/consul.sysv-redhat +++ b/cdist/conf/type/__consul_agent/files/consul.sysv-redhat @@ -11,51 +11,52 @@ # pidfile: /var/run/consul/pidfile # Source function library. + # shellcheck disable=SC1091 . /etc/init.d/functions NAME=consul CONSUL=/usr/local/bin/consul -CONFIG=/etc/$NAME/conf.d -PID_FILE=/var/run/$NAME/pidfile -LOG_FILE=/var/log/$NAME +CONFIG="/etc/$NAME/conf.d" +PID_FILE="/var/run/$NAME/pidfile" +LOG_FILE="/var/log/$NAME" # shellcheck disable=SC1090 -[ -e /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME -export GOMAXPROCS=${GOMAXPROCS:-2} +[ -e "/etc/sysconfig/$NAME" ] && . "/etc/sysconfig/$NAME" +export GOMAXPROCS="${GOMAXPROCS:-2}" -mkdir -p /var/run/$NAME -chown consul:consul /var/run/$NAME -chmod 2770 /var/run/$NAME +mkdir -p "/var/run/$NAME" +chown consul:consul "/var/run/$NAME" +chmod 2770 "/var/run/$NAME" start() { - printf "Starting %s" "$NAME: " + printf "Starting %s: " "$NAME" daemon --user=consul \ --pidfile="$PID_FILE" \ "$CONSUL" agent -pid-file="$PID_FILE" -config-dir "$CONFIG" >> "$LOG_FILE" & retcode=$? - touch /var/lock/subsys/$NAME - return $retcode + touch "/var/lock/subsys/$NAME" + return "$retcode" } stop() { - printf "Shutting down %s" "$NAME: " - killproc -p "$PID_FILE" $NAME + printf "Shutting down %s: " "$NAME" + killproc -p "$PID_FILE" "$NAME" retcode=$? - rm -f /var/lock/subsys/$NAME - return $retcode + rm -f "/var/lock/subsys/$NAME" + return "$retcode" } case "$1" in start) - if status -p "$PID_FILE" $NAME >/dev/null; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then echo "$NAME already running" else start fi ;; stop) - if status -p "$PID_FILE" $NAME >/dev/null; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then stop else echo "$NAME not running" @@ -65,25 +66,25 @@ case "$1" in "$CONSUL" info ;; status) - status -p "$PID_FILE" $NAME + status -p "$PID_FILE" "$NAME" exit $? ;; restart) - if status -p "$PID_FILE" $NAME >/dev/null; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then stop fi start ;; reload) - if status -p "$PID_FILE" $NAME >/dev/null; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then kill -HUP "$(cat "$PID_FILE")" else echo "$NAME not running" fi ;; condrestart) - if [ -f /var/lock/subsys/$NAME ]; then - if status -p "$PID_FILE" $NAME >/dev/null; then + if [ -f "/var/lock/subsys/$NAME" ]; then + if status -p "$PID_FILE" "$NAME" >/dev/null; then stop fi start From faed292a4e667005e4c4f906d6268743d2917568 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 10 Oct 2018 15:01:03 +0200 Subject: [PATCH 0959/1332] Rule should be split. --- cdist/conf/type/__iptables_apply/files/init-script | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__iptables_apply/files/init-script b/cdist/conf/type/__iptables_apply/files/init-script index aee40cbb..d9c79ef7 100644 --- a/cdist/conf/type/__iptables_apply/files/init-script +++ b/cdist/conf/type/__iptables_apply/files/init-script @@ -31,7 +31,9 @@ case $1 in if [ "$count" -ge 1 ]; then for rule in *; do echo "Applying iptables rule $rule ..." - iptables "$(cat "$rule")" + # Rule should be split. + # shellcheck disable=SC2046 + iptables $(cat "$rule") done fi ;; From dd5a45a809f604a299b44bec8c04ce29bc45000c Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Fri, 12 Oct 2018 11:42:42 +0200 Subject: [PATCH 0960/1332] [CONSUL] add newest versions --- cdist/conf/type/__consul/files/versions/1.2.3/cksum | 1 + cdist/conf/type/__consul/files/versions/1.2.3/source | 1 + cdist/conf/type/__consul/files/versions/1.3.0/cksum | 1 + cdist/conf/type/__consul/files/versions/1.3.0/source | 1 + 4 files changed, 4 insertions(+) create mode 100644 cdist/conf/type/__consul/files/versions/1.2.3/cksum create mode 100644 cdist/conf/type/__consul/files/versions/1.2.3/source create mode 100644 cdist/conf/type/__consul/files/versions/1.3.0/cksum create mode 100644 cdist/conf/type/__consul/files/versions/1.3.0/source diff --git a/cdist/conf/type/__consul/files/versions/1.2.3/cksum b/cdist/conf/type/__consul/files/versions/1.2.3/cksum new file mode 100644 index 00000000..6352409e --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/1.2.3/cksum @@ -0,0 +1 @@ +191982 110369685 diff --git a/cdist/conf/type/__consul/files/versions/1.2.3/source b/cdist/conf/type/__consul/files/versions/1.2.3/source new file mode 100644 index 00000000..5e67bc37 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/1.2.3/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/1.2.3/consul_1.2.3_linux_amd64.zip diff --git a/cdist/conf/type/__consul/files/versions/1.3.0/cksum b/cdist/conf/type/__consul/files/versions/1.3.0/cksum new file mode 100644 index 00000000..7a885378 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/1.3.0/cksum @@ -0,0 +1 @@ +1714523667 98363467 consul diff --git a/cdist/conf/type/__consul/files/versions/1.3.0/source b/cdist/conf/type/__consul/files/versions/1.3.0/source new file mode 100644 index 00000000..18a1ba8e --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/1.3.0/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/1.3.0/consul_1.3.0_linux_amd64.zip From 09870ece59f5c341208be7b447fa7873463054f4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Oct 2018 13:57:02 +0200 Subject: [PATCH 0961/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 1a3a7e2a..0cbbf6bb 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Core: Add timestamp (optional) to log messages (Darko Poljak) * Explorers and types: Fix shellcheck found problems and encountered bugs (Jonas Weber, Thomas Eckert, Darko Poljak) * Build: Add shellcheck makefile target and check when doing release (Darko Poljak) + * Type __consul: Add newest versions (Dominique Roux) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 409d736339f9c2041b8733cad982beb129bf1a3c Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 11 Oct 2018 15:58:30 +0200 Subject: [PATCH 0962/1332] explicitly check for `absent` to handle state-typos gracefully --- cdist/conf/type/__user/gencode-remote | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index b908874b..ef04ed3a 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -3,6 +3,7 @@ # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2011 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Daniel Heule (hda at sfs.biz) +# 2018 Thomas Eckert (tom at it-eckert.de) # # This file is part of cdist. # @@ -130,7 +131,7 @@ if [ "$state" = "present" ]; then echo useradd "$@" "$name" fi fi -else +elif [ "$state" = "absent" ]; then if grep -q "^${name}:" "$__object/explorer/passwd"; then #user exists, but state != present, so delete it if [ -f "$__object/parameter/remove-home" ]; then @@ -139,4 +140,6 @@ else echo userdel "${name}" fi fi +else + echo "Invalid state $state" >&2 fi From a1bf3813705117f3ae7a513a4d893cc5094bc59c Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 11 Oct 2018 15:59:47 +0200 Subject: [PATCH 0963/1332] add messaging --- cdist/conf/type/__user/gencode-remote | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index ef04ed3a..a5b60ac6 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -136,8 +136,10 @@ elif [ "$state" = "absent" ]; then #user exists, but state != present, so delete it if [ -f "$__object/parameter/remove-home" ]; then echo userdel -r "${name}" + echo "userdel -r" >> "$__messages_out" else echo userdel "${name}" + echo "userdel" >> "$__messages_out" fi fi else From c995d08ce2305ec75bed9362d4a0ed845c7fcc92 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 11 Oct 2018 16:01:50 +0200 Subject: [PATCH 0964/1332] redirect stdout+stderr of `userdel` If no mail-spoolfile exists for the user the error reporting was visible in the cdist-run. --- cdist/conf/type/__user/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index a5b60ac6..8f2a422a 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -135,10 +135,10 @@ elif [ "$state" = "absent" ]; then if grep -q "^${name}:" "$__object/explorer/passwd"; then #user exists, but state != present, so delete it if [ -f "$__object/parameter/remove-home" ]; then - echo userdel -r "${name}" + printf "userdel -r %s >/dev/null 2>&1\n" "${name}" echo "userdel -r" >> "$__messages_out" else - echo userdel "${name}" + printf "userdel %s >/dev/null 2>&1\n" "${name}" echo "userdel" >> "$__messages_out" fi fi From 5761939fa93e921706e854675dd5e7acbe7619c1 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 11 Oct 2018 16:05:57 +0200 Subject: [PATCH 0965/1332] add new messages to man.rst --- cdist/conf/type/__user/man.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cdist/conf/type/__user/man.rst b/cdist/conf/type/__user/man.rst index 5001bfa4..ef6b77af 100644 --- a/cdist/conf/type/__user/man.rst +++ b/cdist/conf/type/__user/man.rst @@ -60,6 +60,11 @@ mod add New user added +userdel -r + If user was deleted with homedir + +userdel + If user was deleted (keeping homedir) EXAMPLES -------- From c950dd1e9022c2a8965d648d1ab7d3fe25aa3ad4 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 11 Oct 2018 19:00:44 +0200 Subject: [PATCH 0966/1332] quote "remote user", ensuring `user` is handled as one parameter --- cdist/conf/type/__user/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index 8f2a422a..90e3707d 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -135,10 +135,10 @@ elif [ "$state" = "absent" ]; then if grep -q "^${name}:" "$__object/explorer/passwd"; then #user exists, but state != present, so delete it if [ -f "$__object/parameter/remove-home" ]; then - printf "userdel -r %s >/dev/null 2>&1\n" "${name}" + printf "userdel -r '%s' >/dev/null 2>&1\n" "${name}" echo "userdel -r" >> "$__messages_out" else - printf "userdel %s >/dev/null 2>&1\n" "${name}" + printf "userdel '%s' >/dev/null 2>&1\n" "${name}" echo "userdel" >> "$__messages_out" fi fi From c5098dfcc50ab88ce524346ed369cfede4f387da Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Fri, 12 Oct 2018 14:02:11 +0200 Subject: [PATCH 0967/1332] fix [SC1117] (explicitly excaping `\n`) --- cdist/conf/type/__user/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index 90e3707d..ee18c18f 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -135,10 +135,10 @@ elif [ "$state" = "absent" ]; then if grep -q "^${name}:" "$__object/explorer/passwd"; then #user exists, but state != present, so delete it if [ -f "$__object/parameter/remove-home" ]; then - printf "userdel -r '%s' >/dev/null 2>&1\n" "${name}" + printf "userdel -r '%s' >/dev/null 2>&1\\n" "${name}" echo "userdel -r" >> "$__messages_out" else - printf "userdel '%s' >/dev/null 2>&1\n" "${name}" + printf "userdel '%s' >/dev/null 2>&1\\n" "${name}" echo "userdel" >> "$__messages_out" fi fi From 3b7f39cab7aeb3e682f38d2462885b4289beee6c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Oct 2018 15:14:30 +0200 Subject: [PATCH 0968/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 0cbbf6bb..b4425df0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: * Explorers and types: Fix shellcheck found problems and encountered bugs (Jonas Weber, Thomas Eckert, Darko Poljak) * Build: Add shellcheck makefile target and check when doing release (Darko Poljak) * Type __consul: Add newest versions (Dominique Roux) + * Type __user: Remove annoying output, handle state param gracefully, add messages for removal (Thomas Eckert) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 151edc63980e9f9f90df24b952e5b894dc30f15d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Oct 2018 19:08:36 +0200 Subject: [PATCH 0969/1332] Fix DirectoryDict getitem. --- cdist/util/fsproperty.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cdist/util/fsproperty.py b/cdist/util/fsproperty.py index e458fd9e..5a27c9d7 100644 --- a/cdist/util/fsproperty.py +++ b/cdist/util/fsproperty.py @@ -58,7 +58,7 @@ class FileList(collections.MutableSequence): with open(self.path) as fd: for line in fd: lines.append(line.rstrip('\n')) - except EnvironmentError as e: + except EnvironmentError: # error ignored pass return lines @@ -127,7 +127,16 @@ class DirectoryDict(collections.MutableMapping): def __getitem__(self, key): try: with open(os.path.join(self.path, key), "r") as fd: - return fd.read().rstrip('\n') + value = fd.read().splitlines() + # if there is no value/empty line then return '' + # if there is only one value then return that value + # if there are multiple lines in file then return list + if not value: + return '' + elif len(value) == 1: + return value[0] + else: + return value except EnvironmentError: raise KeyError(key) From 5480c22020ac8cd45c630672a07dff105c6289c7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 13 Oct 2018 16:11:51 +0200 Subject: [PATCH 0970/1332] Adapt object_parameters before checking conflicting parameters. --- cdist/emulator.py | 30 ++++++++- cdist/test/emulator/__init__.py | 63 +++++++++++++++++++ .../type/__arguments_all/parameter/boolean | 1 + .../type/__arguments_all/parameter/optional | 1 + .../parameter/optional_multiple | 2 + .../type/__arguments_all/parameter/required | 1 + .../parameter/required_multiple | 2 + .../parameter/optional_multiple | 1 + .../parameter/required_multiple | 1 + 9 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/boolean create mode 100644 cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/optional create mode 100644 cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/optional_multiple create mode 100644 cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/required create mode 100644 cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/required_multiple create mode 100644 cdist/test/emulator/fixtures/conf/type/__arguments_optional_multiple/parameter/optional_multiple create mode 100644 cdist/test/emulator/fixtures/conf/type/__arguments_required_multiple/parameter/required_multiple diff --git a/cdist/emulator.py b/cdist/emulator.py index 4123a353..65d044d7 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -182,6 +182,29 @@ class Emulator(object): lockfname = lockfname.replace(os.sep, '_') self.flock_path = os.path.join(self.object_base_path, lockfname) + def _object_params_in_context(self): + ''' Get cdist_object parameters dict adopted by context. + Context consists of cdist_type boolean, optional, required, + optional_multiple and required_multiple parameters. If parameter + is multiple parameter then its value is a list. + This adaptation works on cdist_object.parameters which are read from + directory based dict where it is unknown what kind of data is in + file. If there is only one line in the file it is unknown if this + is a value of required/optional parameter or if it is one value of + multiple values parameter. + ''' + params = {} + if self.cdist_object.exists: + for param in self.cdist_object.parameters: + value = ('' if param in self.cdist_type.boolean_parameters + else self.cdist_object.parameters[param]) + if ((param in self.cdist_type.required_multiple_parameters or + param in self.cdist_type.optional_multiple_parameters) and + not isinstance(value, list)): + value = [value] + params[param] = value + return params + def setup_object(self): # Create object with given parameters self.parameters = {} @@ -193,12 +216,13 @@ class Emulator(object): # Make existing requirements a set so that we can compare it # later with new requirements. self._existing_reqs = set(self.cdist_object.requirements) - if self.cdist_object.parameters != self.parameters: + obj_params = self._object_params_in_context() + if obj_params != self.parameters: errmsg = ("Object %s already exists with conflicting " "parameters:\n%s: %s\n%s: %s" % ( self.cdist_object.name, " ".join(self.cdist_object.source), - self.cdist_object.parameters, + obj_params, self.object_source, self.parameters)) raise cdist.Error(errmsg) @@ -252,7 +276,7 @@ class Emulator(object): self.cdist_object.name, requirement, e.name, self.object_source))) raise - except core.cdist_object.MissingObjectIdError as e: + except core.cdist_object.MissingObjectIdError: self.log.error(("%s requires object %s without object id." " Defined at %s" % (self.cdist_object.name, requirement, diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index f94ce96d..5691093c 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -420,6 +420,27 @@ class ArgumentsTestCase(test.CdistTestCase): self.assertEqual(cdist_object.parameters['required1'], value) self.assertEqual(cdist_object.parameters['required2'], value) + def test_required_multiple_arguments(self): + """check whether assigning required multiple parameter works""" + + type_name = '__arguments_required_multiple' + object_id = 'some-id' + value1 = 'value1' + value2 = 'value2' + argv = [type_name, object_id, '--required1', value1, + '--required1', value2] + os.environ.update(self.env) + emu = emulator.Emulator(argv) + emu.run() + + cdist_type = core.CdistType(self.local.type_path, type_name) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + object_id) + self.assertTrue('required1' in cdist_object.parameters) + self.assertTrue(value1 in cdist_object.parameters['required1']) + self.assertTrue(value2 in cdist_object.parameters['required1']) + # def test_required_missing(self): # type_name = '__arguments_required' # object_id = 'some-id' @@ -447,6 +468,25 @@ class ArgumentsTestCase(test.CdistTestCase): self.assertFalse('optional2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['optional1'], value) + def test_optional_multiple(self): + type_name = '__arguments_optional_multiple' + object_id = 'some-id' + value1 = 'value1' + value2 = 'value2' + argv = [type_name, object_id, '--optional1', value1, '--optional1', + value2] + os.environ.update(self.env) + emu = emulator.Emulator(argv) + emu.run() + + cdist_type = core.CdistType(self.local.type_path, type_name) + cdist_object = core.CdistObject(cdist_type, self.local.object_path, + self.local.object_marker_name, + object_id) + self.assertTrue('optional1' in cdist_object.parameters) + self.assertTrue(value1 in cdist_object.parameters['optional1']) + self.assertTrue(value2 in cdist_object.parameters['optional1']) + def test_argument_defaults(self): type_name = '__argument_defaults' object_id = 'some-id' @@ -464,6 +504,29 @@ class ArgumentsTestCase(test.CdistTestCase): self.assertFalse('optional2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['optional1'], value) + def test_object_params_in_context(self): + type_name = '__arguments_all' + object_id = 'some-id' + argv = [type_name, object_id, '--opt', 'opt', '--req', 'req', + '--bool', '--optmul', 'val1', '--optmul', 'val2', + '--reqmul', 'val3', '--reqmul', 'val4', + '--optmul1', 'val5', '--reqmul1', 'val6'] + os.environ.update(self.env) + emu = emulator.Emulator(argv) + emu.run() + + obj_params = emu._object_params_in_context() + obj_params_expected = { + 'bool': '', + 'opt': 'opt', + 'optmul1': ['val5', ], + 'optmul': ['val1', 'val2', ], + 'req': 'req', + 'reqmul1': ['val6', ], + 'reqmul': ['val3', 'val4', ], + } + self.assertEqual(obj_params, obj_params_expected) + class StdinTestCase(test.CdistTestCase): diff --git a/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/boolean b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/boolean new file mode 100644 index 00000000..46a27912 --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/boolean @@ -0,0 +1 @@ +bool diff --git a/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/optional b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/optional new file mode 100644 index 00000000..d6eba11a --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/optional @@ -0,0 +1 @@ +opt diff --git a/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/optional_multiple b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/optional_multiple new file mode 100644 index 00000000..04893522 --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/optional_multiple @@ -0,0 +1,2 @@ +optmul +optmul1 diff --git a/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/required b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/required new file mode 100644 index 00000000..da45f08d --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/required @@ -0,0 +1 @@ +req diff --git a/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/required_multiple b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/required_multiple new file mode 100644 index 00000000..28c1a19b --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__arguments_all/parameter/required_multiple @@ -0,0 +1,2 @@ +reqmul +reqmul1 diff --git a/cdist/test/emulator/fixtures/conf/type/__arguments_optional_multiple/parameter/optional_multiple b/cdist/test/emulator/fixtures/conf/type/__arguments_optional_multiple/parameter/optional_multiple new file mode 100644 index 00000000..31647628 --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__arguments_optional_multiple/parameter/optional_multiple @@ -0,0 +1 @@ +optional1 diff --git a/cdist/test/emulator/fixtures/conf/type/__arguments_required_multiple/parameter/required_multiple b/cdist/test/emulator/fixtures/conf/type/__arguments_required_multiple/parameter/required_multiple new file mode 100644 index 00000000..180d60c7 --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__arguments_required_multiple/parameter/required_multiple @@ -0,0 +1 @@ +required1 From 3d56aa83ac7a7fb0fac92c2e97a7a7324b6dc877 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 14 Oct 2018 10:32:30 +0200 Subject: [PATCH 0971/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index b4425df0..364e5ef2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Build: Add shellcheck makefile target and check when doing release (Darko Poljak) * Type __consul: Add newest versions (Dominique Roux) * Type __user: Remove annoying output, handle state param gracefully, add messages for removal (Thomas Eckert) + * Core: Fix checking for conflicting parameters for multiple values parameters (Darko Poljak) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From 8c035189629ebca424092fbf4a216d5b7222ba04 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 17 Oct 2018 07:09:59 +0200 Subject: [PATCH 0972/1332] Fix spelling. --- cdist/config.py | 6 +++--- cdist/core/explorer.py | 6 +++--- cdist/exec/remote.py | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index e8fd5384..11c433db 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -556,19 +556,19 @@ class Config(object): self.log.trace("Multiprocessing cargo_types: %s", cargo_types) nt = len(cargo_types) if nt == 1: - self.log.debug(("Only one type, transfering explorers " + self.log.debug(("Only one type, transferring explorers " "sequentially")) self.explorer.transfer_type_explorers(cargo_types.pop()) else: self.log.trace(("Starting multiprocessing Pool for {} " - "parallel transfering types' explorers".format( + "parallel types explorers transferring".format( nt))) args = [ (ct, ) for ct in cargo_types ] mp_pool_run(self.explorer.transfer_type_explorers, args, jobs=self.jobs) - self.log.trace(("Multiprocessing for parallel transfering " + self.log.trace(("Multiprocessing for parallel transferring " "types' explorers finished")) self.log.trace(("Starting multiprocessing Pool for {} parallel " diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index a42b0117..0b3d7b2e 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -176,14 +176,14 @@ class Explorer(object): self.log.verbose("Running type explorers for {}".format( cdist_object.cdist_type)) if transfer_type_explorers: - self.log.trace("Transfering type explorers for type: %s", + self.log.trace("Transferring type explorers for type: %s", cdist_object.cdist_type) self.transfer_type_explorers(cdist_object.cdist_type) else: - self.log.trace(("No need for transfering type explorers for " + self.log.trace(("No need for transferring type explorers for " "type: %s"), cdist_object.cdist_type) - self.log.trace("Transfering object parameters for object: %s", + self.log.trace("Transferring object parameters for object: %s", cdist_object.name) self.transfer_object_parameters(cdist_object) for explorer in self.list_type_explorer_names(cdist_object.cdist_type): diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index ffb3ee00..9e3e279e 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -190,7 +190,7 @@ class Remote(object): self.log.trace( "Archiving mode desttarpath: %s", desttarpath) # transfer archive to the remote side - self.log.trace("Archiving mode: transfering") + self.log.trace("Archiving mode: transferring") self._transfer_file(tarpath, desttarpath) # extract archive at the remote self.log.trace("Archiving mode: extracting") @@ -248,15 +248,15 @@ class Remote(object): # variable declarations # cdist command prepended with variable assignments expects - # posix shell (bourne, bash) at the remote as user default shell. - # If remote user shell isn't poxis shell, but for e.g. csh/tcsh + # POSIX shell (bourne, bash) at the remote as user default shell. + # If remote user shell isn't POSIX shell, but for e.g. csh/tcsh # then these var assignments are not var assignments for this # remote shell, it tries to execute it as a command and fails. # So really do this by default: # /bin/sh -c 'export ; command' # so that constructed remote command isn't dependent on remote # shell. Do this only if env is not None. env breaks this. - # Explicitly use /bin/sh, because var assignments assume poxis + # Explicitly use /bin/sh, because var assignments assume POSIX # shell already. # This leaves the posibility to write script that needs to be run # remotely in e.g. csh and setting up CDIST_REMOTE_SHELL to e.g. From 6895ad0207a58a5d22efd2943b872afbd1225204 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 24 Oct 2018 18:26:33 +0200 Subject: [PATCH 0973/1332] Fix post-shellcheck bug. --- cdist/conf/type/__hostname/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index fc50b651..33947f7f 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -59,7 +59,7 @@ echo changed >> "$__messages_out" # Use the good old way to set the hostname even on machines running systemd. case "$os" in archlinux|debian|ubuntu|devuan|centos|coreos) - printf "printf '%s\\n' '$name_should' > /etc/hostname\\n" + printf "printf '%%s\\\\n' '$name_should' > /etc/hostname\\n" echo "hostname -F /etc/hostname" ;; freebsd|openbsd) @@ -67,7 +67,7 @@ case "$os" in ;; suse) echo "hostname '$name_should'" - printf "printf '%s\\n' '$name_should' > /etc/HOSTNAME\\n" + printf "printf '%%s\\\\n' '$name_should' > /etc/HOSTNAME\\n" ;; esac From 1bae2be4068dfdd2eea99e7859622ec7dbdb488f Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 31 Oct 2018 20:22:41 +0100 Subject: [PATCH 0974/1332] Synchronize notes on ssh-connection multipexing with current state. --- docs/src/cdist-best-practice.rst | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/src/cdist-best-practice.rst b/docs/src/cdist-best-practice.rst index 45aba11b..a99ba88e 100644 --- a/docs/src/cdist-best-practice.rst +++ b/docs/src/cdist-best-practice.rst @@ -13,15 +13,18 @@ See sshd_config(5) and ssh-keygen(1). Speeding up ssh connections --------------------------- When connecting to a new host, the initial delay with ssh connections -is pretty big. You can work around this by -"sharing of multiple sessions over a single network connection" -(quote from ssh_config(5)). The following code is suitable for -inclusion into your ~/.ssh/config:: +is pretty big. As cdist makes many connections to each host successive +connections can be sped up by "sharing of multiple sessions over a single +network connection" (quote from ssh_config(5)). This is also called "connection +multiplexing". - Host * - ControlPath ~/.ssh/master-%l-%r@%h:%p - ControlMaster auto - ControlPersist 10 +Cdist implements this since v4.0.0 by executing ssh with the appropriate +options (`-o ControlMaster=auto -o ControlPath=/tmp//s -o +ControlPersist=2h`). + +Note that the sshd_config on the server can configure the maximum number of +parallel multiplexed connections this with `MaxSessions N` (N defaults to 10 +for OpenSSH v7.4). Speeding up shell execution From a3a0023b2a44db53fd4fa5c8243068e5cc3e154e Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 31 Oct 2018 20:24:07 +0100 Subject: [PATCH 0975/1332] man-pages are no longer in asciidoc but in ReSTructured text instead --- docs/src/cdist-hacker.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/src/cdist-hacker.rst b/docs/src/cdist-hacker.rst index ea5dceb3..d65c41a6 100644 --- a/docs/src/cdist-hacker.rst +++ b/docs/src/cdist-hacker.rst @@ -59,10 +59,9 @@ How to submit a new type For detailed information about types, see `cdist type `_. Submitting a type works as described above, with the additional requirement -that a corresponding manpage named man.text in asciidoc format with +that a corresponding manpage named man.rst in ReSTructured text format with the manpage-name "cdist-type__NAME" is included in the type directory -AND asciidoc is able to compile it (i.e. do NOT have to many "=" in the second -line). +AND the manpage builds (`make man`). Warning: Submitting "exec" or "run" types that simply echo their parameter in **gencode** will not be accepted, because they are of no use. Every type can output From e860f1c79273731382f0c788ef1b462c6cbb8adc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 2 Nov 2018 14:35:06 +0100 Subject: [PATCH 0976/1332] Determine source_is only if destination is symlink. --- cdist/conf/type/__link/explorer/state | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__link/explorer/state b/cdist/conf/type/__link/explorer/state index a601d53b..7150df25 100755 --- a/cdist/conf/type/__link/explorer/state +++ b/cdist/conf/type/__link/explorer/state @@ -33,8 +33,8 @@ destination_dir="${destination%/*}" case "$type" in symbolic) cd "$destination_dir" || exit 1 - source_is=$(readlink "$destination") if [ -h "$destination" ]; then + source_is=$(readlink "$destination") # ignore trailing slashes for comparison if [ "${source_is%/}" = "${source%/}" ]; then echo present From 6d702053199760703a51d31820210f4e80445755 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 2 Nov 2018 15:25:13 +0100 Subject: [PATCH 0977/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 364e5ef2..8f414e44 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Type __consul: Add newest versions (Dominique Roux) * Type __user: Remove annoying output, handle state param gracefully, add messages for removal (Thomas Eckert) * Core: Fix checking for conflicting parameters for multiple values parameters (Darko Poljak) + * Documentation: Various fixes (Thomas Eckert) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From a34060d7035e84ff8f70d1e8d5bded7a1bfd71b3 Mon Sep 17 00:00:00 2001 From: sideeffect42 Date: Sat, 3 Nov 2018 19:17:56 +0100 Subject: [PATCH 0978/1332] Improve OpenBSD support (#720) * [type/__timezone] Whitelist OpenBSD OpenBSD ships /etc/localtime and /usr/share/zoneinfo by default. * [type/__postgres_{database,role}] Add explorer support for OpenBSD On OpenBSD the "postgres" user is called "_postgresql". The "postgres" database must me specifically specified as it differs from the user name. * [type/__postgres_{database,role}] Add gencode support for OpenBSD On OpenBSD the "postgres" user is called "_postgresql". The "postgres" database must me specifically specified when using psql as it differs from the user name. * [type/__postgres_role] Query DB if role exists instead of screen scaping * [type/__postgres_database] Query DB if database exists instead * [type/__postgres_{database,role}] Add user for NetBSD * [type/__postgres_extension] Add support for OpenBSD and NetBSD * [__ssh_authorized_key] Add OpenBSD support to entry explorer Make sure to adhere to re_format(7) for OpenBSD compatibility. https://man.openbsd.org/re_format.7 * [type/__start_on_boot] Add support for OpenBSD --- .../type/__postgres_database/explorer/state | 21 +++++++++++++++--- .../type/__postgres_database/gencode-remote | 18 +++++++++++++-- .../type/__postgres_extension/gencode-remote | 20 ++++++++++++++--- .../conf/type/__postgres_role/explorer/state | 21 +++++++++++++++--- .../conf/type/__postgres_role/gencode-remote | 22 +++++++++++++++---- .../type/__ssh_authorized_key/explorer/entry | 5 ++++- .../conf/type/__start_on_boot/explorer/state | 4 ++++ .../conf/type/__start_on_boot/gencode-remote | 5 +++++ cdist/conf/type/__timezone/manifest | 6 ++++- 9 files changed, 105 insertions(+), 17 deletions(-) diff --git a/cdist/conf/type/__postgres_database/explorer/state b/cdist/conf/type/__postgres_database/explorer/state index 54eb768d..652d81e7 100755 --- a/cdist/conf/type/__postgres_database/explorer/state +++ b/cdist/conf/type/__postgres_database/explorer/state @@ -18,10 +18,25 @@ # along with cdist. If not, see . # +case "$("${__explorer}/os")" +in + netbsd) + postgres_user='pgsql' + ;; + openbsd) + postgres_user='_postgresql' + ;; + *) + postgres_user='postgres' + ;; +esac + + name="$__object_id" -if su - postgres -c "echo '\\q' | psql '$name'" 2>/dev/null; then - echo "present" +if test -n "$(su - "$postgres_user" -c "psql postgres -tAc \"SELECT 1 FROM pg_database WHERE datname='$name'\"")" +then + echo 'present' else - echo "absent" + echo 'absent' fi diff --git a/cdist/conf/type/__postgres_database/gencode-remote b/cdist/conf/type/__postgres_database/gencode-remote index 92301fb8..61cfa50d 100755 --- a/cdist/conf/type/__postgres_database/gencode-remote +++ b/cdist/conf/type/__postgres_database/gencode-remote @@ -18,6 +18,20 @@ # along with cdist. If not, see . # +case "$(cat "${__global}/explorer/os")" +in + netbsd) + postgres_user='pgsql' + ;; + openbsd) + postgres_user='_postgresql' + ;; + *) + postgres_user='postgres' + ;; +esac + + name="$__object_id" state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" @@ -29,10 +43,10 @@ if [ "$state_should" != "$state_is" ]; then if [ -f "$__object/parameter/owner" ]; then owner="-O '$(cat "$__object/parameter/owner")'" fi - echo "su - postgres -c \"createdb $owner '$name'\"" + echo "su - '$postgres_user' -c \"createdb $owner '$name'\"" ;; absent) - echo "su - postgres -c \"dropdb '$name'\"" + echo "su - '$postgres_user' -c \"dropdb '$name'\"" ;; esac fi diff --git a/cdist/conf/type/__postgres_extension/gencode-remote b/cdist/conf/type/__postgres_extension/gencode-remote index 627067c7..af9c97f1 100755 --- a/cdist/conf/type/__postgres_extension/gencode-remote +++ b/cdist/conf/type/__postgres_extension/gencode-remote @@ -22,6 +22,20 @@ # along with cdist. If not, see . # +case "$(cat "${__global}/explorer/os")" +in + netbsd) + postgres_user='pgsql' + ;; + openbsd) + postgres_user='_postgresql' + ;; + *) + postgres_user='postgres' + ;; +esac + + dbname=$( echo "$__object_id" | cut -d":" -f1 ) extension=$( echo "$__object_id" | cut -d":" -f2 ) @@ -30,10 +44,10 @@ state_should=$( cat "$__object/parameter/state" ) case "$state_should" in present) cmd="CREATE EXTENSION IF NOT EXISTS $extension" - echo "su - postgres -c 'psql -c \"$cmd\" \"$dbname\"'" + echo "su - '$postgres_user' -c 'psql -c \"$cmd\" \"$dbname\"'" ;; absent) - cmd="DROP EXTENSION IF EXISTS $extension" - echo "su - postgres -c 'psql -c \"$cmd\" \"$dbname\"'" + cmd="DROP EXTENSION IF EXISTS $extension" + echo "su - '$postgres_user' -c 'psql -c \"$cmd\" \"$dbname\"'" ;; esac diff --git a/cdist/conf/type/__postgres_role/explorer/state b/cdist/conf/type/__postgres_role/explorer/state index 40f64cef..5cc71477 100755 --- a/cdist/conf/type/__postgres_role/explorer/state +++ b/cdist/conf/type/__postgres_role/explorer/state @@ -18,10 +18,25 @@ # along with cdist. If not, see . # +case "$("${__explorer}/os")" +in + netbsd) + postgres_user='pgsql' + ;; + openbsd) + postgres_user='_postgresql' + ;; + *) + postgres_user='postgres' + ;; +esac + + name="$__object_id" -if su - postgres -c "psql -c '\\du' | grep -q '^ *$name *|'"; then - echo "present" +if test -n "$(su - "$postgres_user" -c "psql postgres -tAc \"SELECT 1 FROM pg_roles WHERE rolname='$name'\"")" +then + echo 'present' else - echo "absent" + echo 'absent' fi diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index f977e73e..f04b22e7 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -18,6 +18,20 @@ # along with cdist. If not, see . # +case "$(cat "${__global}/explorer/os")" +in + netbsd) + postgres_user='pgsql' + ;; + openbsd) + postgres_user='_postgresql' + ;; + *) + postgres_user='postgres' + ;; +esac + + name="$__object_id" state_is="$(cat "$__object/explorer/state")" state_should="$(cat "$__object/parameter/state")" @@ -38,12 +52,12 @@ case "$state_should" in booleans="$booleans $upper" done - [ -n "$password" ] && password="PASSWORD '$password'" + [ -n "$password" ] && password="PASSWORD '$password'" - cmd="CREATE ROLE $name WITH $password $booleans" - echo "su - postgres -c \"psql -c \\\"$cmd\\\"\"" + cmd="CREATE ROLE $name WITH $password $booleans" + echo "su - '$postgres_user' -c \"psql postgres -c '$cmd'\"" ;; absent) - echo "su - postgres -c \"dropuser \\\"$name\\\"\"" + echo "su - '$postgres_user' -c \"dropuser '$name'\"" ;; esac diff --git a/cdist/conf/type/__ssh_authorized_key/explorer/entry b/cdist/conf/type/__ssh_authorized_key/explorer/entry index 78efbb48..ccab0afc 100755 --- a/cdist/conf/type/__ssh_authorized_key/explorer/entry +++ b/cdist/conf/type/__ssh_authorized_key/explorer/entry @@ -27,5 +27,8 @@ then file="$(cat "$__object/parameter/file")" # get any entries that match the type and key - grep ".*$type_and_key\\([ \\n]\\|$\\)" "$file" || true + + # NOTE: Do not match from the beginning of the line as there may be options + # preceeding the key. + grep "${type_and_key}\\([ \\n].*\\)*$" "$file" || true fi diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index cef9013e..1f99db48 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -83,6 +83,10 @@ else state="absent" service -e | grep "/$name$" && state="present" ;; + openbsd) + state='absent' + # OpenBSD 5.7 and higher + rcctl ls on | grep "^${name}$" && state='present' *) echo "Unsupported os: $os" >&2 exit 1 diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 122692ec..b9346826 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -81,6 +81,11 @@ case "$state_should" in : # handled in manifest ;; + openbsd) + # OpenBSD 5.7 and phigher + echo "rcctl enable '$name'" + ;; + *) echo "Unsupported os: $os" >&2 exit 1 diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index a20f5d32..c908f087 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -34,7 +34,11 @@ case "$os" in __package timezone export require="__package/timezone" ;; - freebsd|netbsd|coreos) + freebsd|netbsd|openbsd) + # whitelist + : + ;; + coreos) # whitelist : ;; From 0882a0beecf31ba5753d1fc4342234a8aee9bf18 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Nov 2018 19:17:24 +0100 Subject: [PATCH 0979/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8f414e44..a794ddb3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Type __user: Remove annoying output, handle state param gracefully, add messages for removal (Thomas Eckert) * Core: Fix checking for conflicting parameters for multiple values parameters (Darko Poljak) * Documentation: Various fixes (Thomas Eckert) + * Various types: Improve OpenBSD support (sideeffect42) 4.10.3: 2018-09-23 * New global explorer: os_release (Ľubomír Kučera) From d11174f2b7e15fc1d9402226290c749378e21ca9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Nov 2018 19:21:20 +0100 Subject: [PATCH 0980/1332] Add missing ;; in case item. --- cdist/conf/type/__start_on_boot/explorer/state | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 1f99db48..19dfc74b 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -87,6 +87,7 @@ else state='absent' # OpenBSD 5.7 and higher rcctl ls on | grep "^${name}$" && state='present' + ;; *) echo "Unsupported os: $os" >&2 exit 1 From f8fbcdf2a7288d88db6f2afb9377cb53c69a195d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 3 Nov 2018 19:22:59 +0100 Subject: [PATCH 0981/1332] Release 4.10.4 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index a794ddb3..fd68bed6 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) * Core: Add timestamp (optional) to log messages (Darko Poljak) * Explorers and types: Fix shellcheck found problems and encountered bugs (Jonas Weber, Thomas Eckert, Darko Poljak) From 2cae33f6d64ad61f4d9679439605f13650d00bae Mon Sep 17 00:00:00 2001 From: Dimitrios Apostolou Date: Sun, 18 Nov 2018 01:30:40 +0100 Subject: [PATCH 0982/1332] Fix __group type failing with --gid The command `echo -- -g` prints `-- -g` so the generated `groupadd` command was syntactically incorrect and failing. Solution was to remove `--` since echo command does not understand it, and add instead an extra space before `-g` to avoid echo interpreting it as a flag. --- cdist/conf/type/__group/gencode-remote | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__group/gencode-remote b/cdist/conf/type/__group/gencode-remote index 822619d2..6091c548 100755 --- a/cdist/conf/type/__group/gencode-remote +++ b/cdist/conf/type/__group/gencode-remote @@ -30,9 +30,9 @@ state="$(cat "$__object/parameter/state")" # Use short option names for portability shorten_property() { case "$1" in - gid) echo -- "-g";; - password) echo -- "-p";; - system) echo -- "-r";; + gid) echo " -g";; + password) echo " -p";; + system) echo " -r";; esac } From 308be1b6fae2adba6b9c2fb2bd946027f066de29 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 18 Nov 2018 16:04:24 +0100 Subject: [PATCH 0983/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index fd68bed6..f1faf131 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __group: Fix/remove '--' from echo command (Dimitrios Apostolou) + 4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) * Core: Add timestamp (optional) to log messages (Darko Poljak) From 71ceba4ac588efcd995e2ffcdd9a5aea5f014371 Mon Sep 17 00:00:00 2001 From: Olliver Schinagl Date: Mon, 26 Nov 2018 15:49:23 +0100 Subject: [PATCH 0984/1332] type: Add new type __ping When starting with cdist, the documentation and examples can be overwheliming. Further more, sometimes one would only want to do a simple test to see if the basics are working. One such example currently is to create a simple remote file. While this is a nice and simple example, an even simpler example would be to just see if we can 'ping' the host. Other configuration management tools also seem to have this as a basic starting command. This thus allows to do: echo __ping | cdist config --initial-manifest - as the most basic, most simple command to 'test' things with, without having lingering files to boot. Signed-off-by: Olliver Schinagl --- cdist/conf/type/__ping/gencode-remote | 12 ++++++++ cdist/conf/type/__ping/man.rst | 43 +++++++++++++++++++++++++++ cdist/conf/type/__ping/singleton | 0 3 files changed, 55 insertions(+) create mode 100644 cdist/conf/type/__ping/gencode-remote create mode 100644 cdist/conf/type/__ping/man.rst create mode 100644 cdist/conf/type/__ping/singleton diff --git a/cdist/conf/type/__ping/gencode-remote b/cdist/conf/type/__ping/gencode-remote new file mode 100644 index 00000000..1341b954 --- /dev/null +++ b/cdist/conf/type/__ping/gencode-remote @@ -0,0 +1,12 @@ +#!/bin/sh -e +# +# Copyright (C) 2018 Olliver Schinagl +# +# SPDX-License-Identifier: GPL-3.0+ +# + +set -eu + +echo "echo 'pong'" + +exit 0 diff --git a/cdist/conf/type/__ping/man.rst b/cdist/conf/type/__ping/man.rst new file mode 100644 index 00000000..e08643dc --- /dev/null +++ b/cdist/conf/type/__ping/man.rst @@ -0,0 +1,43 @@ +cdist-type__ping(7) +================================== + +NAME +---- +cdist-type__ping - Try to connect to host and return 'pong' on success + + +DESCRIPTION +----------- +A simple type which tries to connect to a remote host and runs a simple command +to ensure everything is working. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + __ping + + +AUTHORS +------- +Olliver Schinagl + + +COPYING +------- +Copyright \(C) 2018 Schinagl. 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/__ping/singleton b/cdist/conf/type/__ping/singleton new file mode 100644 index 00000000..e69de29b From 6b95db8fc78a26cb0159be504bc05f3cd90afd00 Mon Sep 17 00:00:00 2001 From: Olliver Schinagl Date: Mon, 26 Nov 2018 20:39:20 +0100 Subject: [PATCH 0985/1332] Update .gitignore to more broadly ignore vim As per https://github.com/github/gitignore/blob/master/Global/Vim.gitignore Signed-off-by: Olliver Schinagl --- .gitignore | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0c664232..320d150d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,21 @@ # -vim -.*.swp +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ # Ignore generated manpages docs/src/.marker From a85f2ebdb6d398ea59524d577b69ca44882450b4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 27 Nov 2018 10:41:02 +0100 Subject: [PATCH 0986/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index f1faf131..20209bca 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Type __group: Fix/remove '--' from echo command (Dimitrios Apostolou) + * New type: __ping (Olliver Schinagl) 4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) From c85dfbdb10f11adce29dc9c9b5eaac252a825706 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Dec 2018 13:14:19 +0100 Subject: [PATCH 0987/1332] [__postgres_role] Revert parts of a34060d7035e84ff8f70d1e8d5bded7a1bfd71b3 Broken syntax fixed --- cdist/conf/type/__postgres_role/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index f04b22e7..11897306 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -55,9 +55,9 @@ case "$state_should" in [ -n "$password" ] && password="PASSWORD '$password'" cmd="CREATE ROLE $name WITH $password $booleans" - echo "su - '$postgres_user' -c \"psql postgres -c '$cmd'\"" + echo "su - '$postgres_user' -c \"psql -c \\\"$cmd\\\"\"" ;; absent) - echo "su - '$postgres_user' -c \"dropuser '$name'\"" + echo "su - '$postgres_user' -c \"dropuser \\\"$name\\\"\"" ;; esac From 0491b5b8db3a8d5f36c61e9a4e7ac5b625bcdb58 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 5 Dec 2018 16:41:22 +0100 Subject: [PATCH 0988/1332] Revert "[__postgres_role] Revert parts of a34060d7035e84ff8f70d1e8d5bded7a1bfd71b3" This reverts commit c85dfbdb10f11adce29dc9c9b5eaac252a825706. --- cdist/conf/type/__postgres_role/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index 11897306..f04b22e7 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -55,9 +55,9 @@ case "$state_should" in [ -n "$password" ] && password="PASSWORD '$password'" cmd="CREATE ROLE $name WITH $password $booleans" - echo "su - '$postgres_user' -c \"psql -c \\\"$cmd\\\"\"" + echo "su - '$postgres_user' -c \"psql postgres -c '$cmd'\"" ;; absent) - echo "su - '$postgres_user' -c \"dropuser \\\"$name\\\"\"" + echo "su - '$postgres_user' -c \"dropuser '$name'\"" ;; esac From 45d10374912ee215650efa622cc3af577a0c19ea Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 5 Dec 2018 16:51:37 +0100 Subject: [PATCH 0989/1332] [__postgres_role] Revert parts of a34060d7035e84ff8f70d1e8d5bded7a1bfd71b3 Broken syntax fixed --- cdist/conf/type/__postgres_role/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index f04b22e7..30d0689c 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -55,9 +55,9 @@ case "$state_should" in [ -n "$password" ] && password="PASSWORD '$password'" cmd="CREATE ROLE $name WITH $password $booleans" - echo "su - '$postgres_user' -c \"psql postgres -c '$cmd'\"" + echo "su - '$postgres_user' -c \"psql postgres -c \\\"$cmd\\\"\"" ;; absent) - echo "su - '$postgres_user' -c \"dropuser '$name'\"" + echo "su - '$postgres_user' -c \"dropuser \\\"$name\\\"\"" ;; esac From 5014fd23882f883cb154696c7f0fc2b7e90e39b1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 5 Dec 2018 16:54:39 +0100 Subject: [PATCH 0990/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 20209bca..cc4bc838 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __group: Fix/remove '--' from echo command (Dimitrios Apostolou) * New type: __ping (Olliver Schinagl) + * Type __postgres_role: Fix broken syntax (Nico Schottelius, Darko Poljak) 4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) From 7e9dce0ceb5500fe451170bc39705fe4a67c3095 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 7 Dec 2018 16:53:21 +0100 Subject: [PATCH 0991/1332] [type/__package_*] Print installed/removed messages Up-/downgraded packages will send an "installed" message. --- cdist/conf/type/__package_emerge/gencode-remote | 2 ++ cdist/conf/type/__package_luarocks/gencode-remote | 2 ++ cdist/conf/type/__package_opkg/gencode-remote | 4 +++- cdist/conf/type/__package_pacman/gencode-remote | 2 ++ cdist/conf/type/__package_pip/gencode-remote | 2 ++ cdist/conf/type/__package_pkg_freebsd/gencode-remote | 5 ++++- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 10 ++++++---- cdist/conf/type/__package_pkgng_freebsd/gencode-remote | 3 +++ cdist/conf/type/__package_rubygem/gencode-remote | 2 ++ cdist/conf/type/__package_yum/gencode-remote | 2 ++ cdist/conf/type/__package_zypper/gencode-remote | 3 +++ 11 files changed, 31 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote index 48462bde..c25f2be7 100755 --- a/cdist/conf/type/__package_emerge/gencode-remote +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -64,9 +64,11 @@ fi case "$state_should" in present) echo "emerge '$name' &>/dev/null || exit 1" + echo "installed" >> "$__messages_out" ;; absent) echo "emerge -C '$name' &>/dev/null || exit 1" + echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_luarocks/gencode-remote b/cdist/conf/type/__package_luarocks/gencode-remote index 60b9bfea..d83b3c3a 100755 --- a/cdist/conf/type/__package_luarocks/gencode-remote +++ b/cdist/conf/type/__package_luarocks/gencode-remote @@ -43,9 +43,11 @@ fi case "$state_should" in present) echo "luarocks install '$name'" + echo "installed" >> "$__messages_out" ;; absent) echo "luarocks remove '$name'" + echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_opkg/gencode-remote b/cdist/conf/type/__package_opkg/gencode-remote index e94ff388..269d5f49 100755 --- a/cdist/conf/type/__package_opkg/gencode-remote +++ b/cdist/conf/type/__package_opkg/gencode-remote @@ -43,12 +43,14 @@ esac case "$state_should" in present) if [ "$present" = "notpresent" ]; then - echo opkg --verbosity=0 update + echo "opkg --verbosity=0 update" fi echo "opkg --verbosity=0 install '$name'" + echo "installed" >> "$__messages_out" ;; absent) echo "opkg --verbosity=0 remove '$name'" + echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: ${state_should}" >&2 diff --git a/cdist/conf/type/__package_pacman/gencode-remote b/cdist/conf/type/__package_pacman/gencode-remote index 7ba85479..2e076ec3 100755 --- a/cdist/conf/type/__package_pacman/gencode-remote +++ b/cdist/conf/type/__package_pacman/gencode-remote @@ -46,9 +46,11 @@ fi case "$state_should" in present) echo "pacman --needed --noconfirm --noprogressbar -S '$name'" + echo "installed" >> "$__messages_out" ;; absent) echo "pacman --noconfirm --noprogressbar -R '$name'" + echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_pip/gencode-remote b/cdist/conf/type/__package_pip/gencode-remote index 33556bec..dcc4fdf9 100755 --- a/cdist/conf/type/__package_pip/gencode-remote +++ b/cdist/conf/type/__package_pip/gencode-remote @@ -57,6 +57,7 @@ case "$state_should" in else echo $pip install -q "$name" fi + echo "installed" >> "$__messages_out" ;; absent) if [ "$runas" ] @@ -65,6 +66,7 @@ case "$state_should" in else echo $pip uninstall -q -y "$name" fi + echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_pkg_freebsd/gencode-remote b/cdist/conf/type/__package_pkg_freebsd/gencode-remote index fd02d939..3f88f6bc 100755 --- a/cdist/conf/type/__package_pkg_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_freebsd/gencode-remote @@ -39,7 +39,7 @@ assert () # If condition false, # shellcheck disable=SC2039 echo "File \"$0\", line $lineno, called by $(caller 0)" exit $E_ASSERT_FAILED - fi + fi } # Debug @@ -89,6 +89,7 @@ if [ -n "$curr_version" ]; then # PKG *is* installed cmd="${rm_cmd} ${name}-${curr_version}" fi execcmd "remove" "${cmd}" + echo "removed" >> "$__messages_out" exit 0 else # Should be installed if [ -n "$version" ]; then # Want a specific version @@ -102,6 +103,7 @@ if [ -n "$curr_version" ]; then # PKG *is* installed execcmd "remove" "${cmd}" cmd="${add_cmd} -r ${name}-${version}" execcmd "add" "${cmd}" + echo "installed" >> "$__messages_out" fi else # Don't care what version to use exit 0 @@ -120,6 +122,7 @@ else # PKG *isn't* installed cmd="${cmd}-${version}" fi execcmd "add" "${cmd}" + echo "installed" >> "$__messages_out" exit 0 fi fi diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 61383edb..da63626b 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -62,15 +62,15 @@ state_should="$(cat "$__object/parameter/state")" pkg_version="$(cat "$__object/explorer/pkg_version")" -if [ -f "$__object/parameter/pkg_path" ]; then - pkg_path="$(cat "$__object/parameter/pkg_path")" +if [ -f "$__object/parameter/pkg_path" ]; then + pkg_path="$(cat "$__object/parameter/pkg_path")" else has_installurl=$(cat "${__object}/explorer/has_installurl") if [ Xyes != X"${has_installurl}" ]; then # there is no default PKG_PATH, try to provide one pkg_path="ftp://ftp.openbsd.org/pub/OpenBSD/$os_version/packages/$machine/" fi -fi +fi if [ "$pkg_version" ]; then state_is="present" @@ -99,11 +99,12 @@ if [ \$? -ne 0 ]; then echo "Error: \$status" exit 1 fi +echo "installed" >> "$__messages_out" eof ;; absent) - # use this because pkg_add doesn't properly handle errors + # use this because pkg_delete doesn't properly handle errors cat << eof status=\$(pkg_delete "$pkgopts" "$pkgid") pkg_info | grep "^${name}.*${version}.*${flavor}" > /dev/null 2>&1 @@ -117,6 +118,7 @@ if [ \$? -eq 0 ]; then echo "Error: \$status" exit 1 fi +echo "removed" >> "$__messages_out" eof ;; *) diff --git a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote index b72544c1..dd36efda 100755 --- a/cdist/conf/type/__package_pkgng_freebsd/gencode-remote +++ b/cdist/conf/type/__package_pkgng_freebsd/gencode-remote @@ -57,12 +57,15 @@ execcmd(){ case "$1" in add) _cmd="${add_cmd} $2" + echo "installed" >> "$__messages_out" ;; rm) _cmd="${rm_cmd} $2" + echo "removed" >> "$__messages_out" ;; upg) _cmd="${upg_cmd} $2" + echo "installed" >> "$__messages_out" ;; *) printf "Error. Don't understand command: %s" "$1" >&2 diff --git a/cdist/conf/type/__package_rubygem/gencode-remote b/cdist/conf/type/__package_rubygem/gencode-remote index ee563ef8..abb40653 100755 --- a/cdist/conf/type/__package_rubygem/gencode-remote +++ b/cdist/conf/type/__package_rubygem/gencode-remote @@ -40,9 +40,11 @@ fi case "$state_should" in present) echo "gem install '$name' --no-ri --no-rdoc" + echo "installed" >> "$__messages_out" ;; absent) echo "gem uninstall '$name'" + echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote index 97265827..b52953f6 100755 --- a/cdist/conf/type/__package_yum/gencode-remote +++ b/cdist/conf/type/__package_yum/gencode-remote @@ -61,9 +61,11 @@ fi case "$state_should" in present) echo "yum $opts install '$install_name'" + echo "installed" >> "$__messages_out" ;; absent) echo "yum $opts remove '$name'" + echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote index 1f15c531..e45dd9ff 100755 --- a/cdist/conf/type/__package_zypper/gencode-remote +++ b/cdist/conf/type/__package_zypper/gencode-remote @@ -62,14 +62,17 @@ case "$state_should" in if [ -z "$version_should" ]; then [ "$state_is" = "present" ] && exit 0 # if state is present, we dont need to do anything echo "zypper $globalopts install --type '$ptype' --auto-agree-with-licenses '$name' >/dev/null" + echo "removed" >> "$__messages_out" else [ "$state_is" = "present" ] && [ "$version_should" = "$version_is" ] && exit 0 # if state is present and version is correct, we dont need to do anything echo "zypper $globalopts install --oldpackage --type '$ptype' --auto-agree-with-licenses '$name' = '$version_should' >/dev/null" + echo "installed" >> "$__messages_out" fi ;; absent) [ "$state_is" = "absent" ] && exit 0 # if state is absent, we dont need to do anything echo "zypper $globalopts remove --type '$ptype' '$name' >/dev/null" + echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 From ccdbf1a31c92681e2f34d7a48acc67f243548520 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 7 Dec 2018 16:55:49 +0100 Subject: [PATCH 0992/1332] [type/__package_emerge_dependendencies] Send messages when a dependency is installed --- cdist/conf/type/__package_emerge_dependencies/gencode-remote | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_emerge_dependencies/gencode-remote b/cdist/conf/type/__package_emerge_dependencies/gencode-remote index face898a..f3e6f76e 100755 --- a/cdist/conf/type/__package_emerge_dependencies/gencode-remote +++ b/cdist/conf/type/__package_emerge_dependencies/gencode-remote @@ -6,10 +6,11 @@ flaggie_installed="$(cat "$__object/explorer/flaggie_installed")" if [ "${gentoolkit_installed}" != "true" ]; then # emerge app-portage/gentoolkit echo "emerge app-portage/gentoolkit &> /dev/null || exit 1" + echo "installed app-portage/gentoolkit" >> "$__messages_out" fi if [ "${flaggie_installed}" != "true" ]; then # emerge app-portage/flaggie echo "emerge app-portage/flaggie &> /dev/null || exit 1" + echo "installed app-portage/flaggie" >> "$__messages_out" fi - From 8ad93a29c964b623604846ca92ae3a24d45e7e64 Mon Sep 17 00:00:00 2001 From: "jinguk.kwon" Date: Wed, 12 Dec 2018 01:40:39 +0900 Subject: [PATCH 0993/1332] update for debian version 9 --- cdist/conf/type/__consul_agent/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index 3951f728..c48bfe85 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -206,7 +206,7 @@ case "$os" in [567]) init_sysvinit debian ;; - 8) + [89]) init_systemd ;; *) From 49f2d3bf9191f9a8ea06ec5ae566ce744781908e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Dec 2018 18:48:23 +0100 Subject: [PATCH 0994/1332] ++ changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index cc4bc838..536ff674 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __group: Fix/remove '--' from echo command (Dimitrios Apostolou) * New type: __ping (Olliver Schinagl) * Type __postgres_role: Fix broken syntax (Nico Schottelius, Darko Poljak) + * Type __consul_agent: Add Debian 9 support (Jin-Guk Kwon) 4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) From 96a0eaabf1caf912de5b430a655c634981b7122a Mon Sep 17 00:00:00 2001 From: Rage OxR463 <43783393+oxr463@users.noreply.github.com> Date: Wed, 12 Dec 2018 12:12:36 -0500 Subject: [PATCH 0995/1332] Fix broken links. --- docs/web/cdist.mdwn | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn index 74457fc8..90af20cb 100644 --- a/docs/web/cdist.mdwn +++ b/docs/web/cdist.mdwn @@ -6,10 +6,10 @@ cdist is a usable configuration management system. It adheres to the KISS principle and is being used in small up to enterprise grade environments. cdist is an alternative to other configuration management systems like -[bcfg2](http://trac.mcs.anl.gov/projects/bcfg2), -[chef](http://wiki.opscode.com/display/chef/), -[cfengine](http://www.cfengine.org/) -and [puppet](http://www.puppetlabs.com/). +[bcfg2](http://bcfg2.org/), +[chef](https://www.chef.sh/), +[cfengine](https://cfengine.com/) +and [puppet](https://puppet.com/). * [[Why should I use cdist?|why]] * [[Documentation|documentation]] From f2ef1ef0d688ed24e619fddd2d42a9967f862370 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 13 Dec 2018 12:32:57 +0100 Subject: [PATCH 0996/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 536ff674..c2bc2001 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * New type: __ping (Olliver Schinagl) * Type __postgres_role: Fix broken syntax (Nico Schottelius, Darko Poljak) * Type __consul_agent: Add Debian 9 support (Jin-Guk Kwon) + * Documentation: Fix broken links (Rage ) 4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) From a7f4c8d7736f961a654f93340439da92ccb1bd7f Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 13 Dec 2018 13:23:49 +0100 Subject: [PATCH 0997/1332] Allow installing specific Docker-CE version --- cdist/conf/type/__docker/man.rst | 5 +++++ cdist/conf/type/__docker/manifest | 13 +++++++++++-- cdist/conf/type/__docker/parameter/default/version | 1 + cdist/conf/type/__docker/parameter/optional | 1 + 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 cdist/conf/type/__docker/parameter/default/version diff --git a/cdist/conf/type/__docker/man.rst b/cdist/conf/type/__docker/man.rst index 5cb28ee1..718543a8 100644 --- a/cdist/conf/type/__docker/man.rst +++ b/cdist/conf/type/__docker/man.rst @@ -20,6 +20,9 @@ OPTIONAL PARAMETERS ------------------- state 'present' or 'absent', defaults to 'present' +version + The specific version to install. Defaults to the special value 'latest', + meaning the version the package manager will install by default. BOOLEAN PARAMETERS @@ -38,6 +41,8 @@ EXAMPLES # Remove docker __docker --state absent + # Install specific version + __docker --state present --version 18.03.0.ce AUTHORS ------- diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index 8f26feec..a893ea15 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -21,6 +21,7 @@ os=$(cat "$__global/explorer/os") state=$(cat "$__object/parameter/state") +version=$(cat "$__object/parameter/version") case "$os" in centos) @@ -33,7 +34,11 @@ case "$os" in --gpgcheck 1 \ --gpgkey 'https://download.docker.com/linux/centos/gpg' \ --state "${state}" - require="__yum_repo/docker-ce-stable" __package docker-ce --state "${state}" + if [ "$version" != "latest" ]; then + require="__yum_repo/docker-ce-stable" __package docker-ce --version "${version}" --state "${state}" + else + require="__yum_repo/docker-ce-stable" __package docker-ce --state "${state}" + fi else echo "CentOS version 7 is required!" >&2 exit 1 @@ -53,7 +58,11 @@ case "$os" in --distribution "$(cat "$__global/explorer/lsb_codename")" \ --state "${state}" \ --component "stable" - __package docker-ce --state "${state}" + if [ "$version" != "latest" ]; then + __package docker-ce --version "${version}" --state "${state}" + else + __package docker-ce --state "${state}" + fi unset CDIST_ORDER_DEPENDENCY ;; *) diff --git a/cdist/conf/type/__docker/parameter/default/version b/cdist/conf/type/__docker/parameter/default/version new file mode 100644 index 00000000..a0f9a4b4 --- /dev/null +++ b/cdist/conf/type/__docker/parameter/default/version @@ -0,0 +1 @@ +latest diff --git a/cdist/conf/type/__docker/parameter/optional b/cdist/conf/type/__docker/parameter/optional index ff72b5c7..4d595ed7 100644 --- a/cdist/conf/type/__docker/parameter/optional +++ b/cdist/conf/type/__docker/parameter/optional @@ -1 +1,2 @@ state +version From d4bb114468dcd8ea1483edfe20609d2179037f93 Mon Sep 17 00:00:00 2001 From: Jonas Weber Date: Thu, 13 Dec 2018 13:26:40 +0100 Subject: [PATCH 0998/1332] Remove usage of CDIST_ORDER_DEPENDENCY --- cdist/conf/type/__docker/manifest | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index a893ea15..04a9ff27 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -52,18 +52,17 @@ case "$os" in fi __apt_key_uri docker --name "Docker Release (CE deb) " \ --uri "https://download.docker.com/linux/${os}/gpg" --state "${state}" - export CDIST_ORDER_DEPENDENCY=on - __apt_source docker \ + + require="__apt_key_uri/docker" __apt_source docker \ --uri "https://download.docker.com/linux/${os}" \ --distribution "$(cat "$__global/explorer/lsb_codename")" \ --state "${state}" \ --component "stable" if [ "$version" != "latest" ]; then - __package docker-ce --version "${version}" --state "${state}" + require="__apt_source/docker" __package docker-ce --version "${version}" --state "${state}" else - __package docker-ce --state "${state}" + require="__apt_source/docker" __package docker-ce --state "${state}" fi - unset CDIST_ORDER_DEPENDENCY ;; *) echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 From 75afdd4d695e63fa95fb507a2dfb1cedc08f5e56 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 13 Dec 2018 20:14:54 +0100 Subject: [PATCH 0999/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index c2bc2001..a662eb38 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: * Type __postgres_role: Fix broken syntax (Nico Schottelius, Darko Poljak) * Type __consul_agent: Add Debian 9 support (Jin-Guk Kwon) * Documentation: Fix broken links (Rage ) + * Type __docker: Add version parameter (Jonas Weber) 4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) From 183d57d6d2aeb05d37bef3896badd9a20a6c541f Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 14 Dec 2018 12:43:57 +0100 Subject: [PATCH 1000/1332] [type/__sysctl] Fix spelling of FreeBSD --- cdist/conf/type/__sysctl/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__sysctl/gencode-remote b/cdist/conf/type/__sysctl/gencode-remote index a7aedb84..888ca117 100755 --- a/cdist/conf/type/__sysctl/gencode-remote +++ b/cdist/conf/type/__sysctl/gencode-remote @@ -31,7 +31,7 @@ case "$os" in redhat|centos|ubuntu|debian|devuan|archlinux|coreos) flag='-w' ;; - frebsd) + freebsd) flag='' ;; esac From b36716ef3619ff9881be98b0fa896ade7456a8e0 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 14 Dec 2018 12:44:41 +0100 Subject: [PATCH 1001/1332] [type/__sysctl] Add OpenBSD support --- cdist/conf/type/__sysctl/gencode-remote | 3 ++- cdist/conf/type/__sysctl/manifest | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__sysctl/gencode-remote b/cdist/conf/type/__sysctl/gencode-remote index 888ca117..76e5f528 100755 --- a/cdist/conf/type/__sysctl/gencode-remote +++ b/cdist/conf/type/__sysctl/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2018 Takashi Yoshi (takashi at yoshi.email) # # This file is part of cdist. # @@ -31,7 +32,7 @@ case "$os" in redhat|centos|ubuntu|debian|devuan|archlinux|coreos) flag='-w' ;; - freebsd) + freebsd|openbsd) flag='' ;; esac diff --git a/cdist/conf/type/__sysctl/manifest b/cdist/conf/type/__sysctl/manifest index 6e337ccb..43feec04 100755 --- a/cdist/conf/type/__sysctl/manifest +++ b/cdist/conf/type/__sysctl/manifest @@ -1,6 +1,7 @@ #!/bin/sh -e # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2018 Takashi Yoshi (takashi at yoshi.email) # # This file is part of cdist. # @@ -22,7 +23,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - redhat|centos|ubuntu|debian|devuan|archlinux|coreos|freebsd) + redhat|centos|ubuntu|debian|devuan|archlinux|coreos|freebsd|openbsd) : ;; *) From 566feba5b16b6eb56371fe0fa669d83c1d929bfc Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 14 Dec 2018 12:55:03 +0100 Subject: [PATCH 1002/1332] [type/__sysctl] Add NetBSD support --- cdist/conf/type/__sysctl/gencode-remote | 2 +- cdist/conf/type/__sysctl/manifest | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__sysctl/gencode-remote b/cdist/conf/type/__sysctl/gencode-remote index 76e5f528..873932ba 100755 --- a/cdist/conf/type/__sysctl/gencode-remote +++ b/cdist/conf/type/__sysctl/gencode-remote @@ -29,7 +29,7 @@ fi os=$(cat "$__global/explorer/os") case "$os" in - redhat|centos|ubuntu|debian|devuan|archlinux|coreos) + redhat|centos|ubuntu|debian|devuan|archlinux|coreos|netbsd) flag='-w' ;; freebsd|openbsd) diff --git a/cdist/conf/type/__sysctl/manifest b/cdist/conf/type/__sysctl/manifest index 43feec04..df3ff13c 100755 --- a/cdist/conf/type/__sysctl/manifest +++ b/cdist/conf/type/__sysctl/manifest @@ -23,7 +23,12 @@ os=$(cat "$__global/explorer/os") case "$os" in - redhat|centos|ubuntu|debian|devuan|archlinux|coreos|freebsd|openbsd) + # Linux + redhat|centos|ubuntu|debian|devuan|archlinux|coreos) + : + ;; + # BSD + freebsd|netbsd|openbsd) : ;; *) From 45ff67c0f55ece10c4265e8ab187b78ec432f1de Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 14 Dec 2018 13:06:31 +0100 Subject: [PATCH 1003/1332] [type/__sysctl] Add Mac OS X support --- cdist/conf/type/__sysctl/gencode-remote | 8 +++++++- cdist/conf/type/__sysctl/manifest | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__sysctl/gencode-remote b/cdist/conf/type/__sysctl/gencode-remote index 873932ba..e17e0659 100755 --- a/cdist/conf/type/__sysctl/gencode-remote +++ b/cdist/conf/type/__sysctl/gencode-remote @@ -31,7 +31,13 @@ os=$(cat "$__global/explorer/os") case "$os" in redhat|centos|ubuntu|debian|devuan|archlinux|coreos|netbsd) flag='-w' - ;; + ;; + macosx) + # NOTE: Older versions of Mac OS X require the -w option. + # Even though the flag is not mentioned in new man pages anymore, + # it still works. + flag='-w' + ;; freebsd|openbsd) flag='' ;; diff --git a/cdist/conf/type/__sysctl/manifest b/cdist/conf/type/__sysctl/manifest index df3ff13c..b4e2e902 100755 --- a/cdist/conf/type/__sysctl/manifest +++ b/cdist/conf/type/__sysctl/manifest @@ -28,7 +28,7 @@ case "$os" in : ;; # BSD - freebsd|netbsd|openbsd) + freebsd|macosx|netbsd|openbsd) : ;; *) From 92610fe76c6875ee4aa6b31bf5b2be23e5149305 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 14 Dec 2018 13:45:03 +0100 Subject: [PATCH 1004/1332] [type/__sysctl] Add support for Alpine Linux, Gentoo and OpenWrt --- cdist/conf/type/__sysctl/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__sysctl/gencode-remote b/cdist/conf/type/__sysctl/gencode-remote index e17e0659..d1da6058 100755 --- a/cdist/conf/type/__sysctl/gencode-remote +++ b/cdist/conf/type/__sysctl/gencode-remote @@ -29,7 +29,7 @@ fi os=$(cat "$__global/explorer/os") case "$os" in - redhat|centos|ubuntu|debian|devuan|archlinux|coreos|netbsd) + redhat|centos|ubuntu|debian|devuan|alpine|archlinux|gentoo|openwrt|coreos|netbsd) flag='-w' ;; macosx) From 9acb9d1f3aa7ffa9c10f4be1d8eb8c3ed6b3e251 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 14 Dec 2018 14:12:33 +0100 Subject: [PATCH 1005/1332] [type/__sysctl] Group entries --- cdist/conf/type/__sysctl/gencode-remote | 32 +++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/cdist/conf/type/__sysctl/gencode-remote b/cdist/conf/type/__sysctl/gencode-remote index d1da6058..711d54e5 100755 --- a/cdist/conf/type/__sysctl/gencode-remote +++ b/cdist/conf/type/__sysctl/gencode-remote @@ -29,18 +29,26 @@ fi os=$(cat "$__global/explorer/os") case "$os" in - redhat|centos|ubuntu|debian|devuan|alpine|archlinux|gentoo|openwrt|coreos|netbsd) - flag='-w' - ;; - macosx) - # NOTE: Older versions of Mac OS X require the -w option. - # Even though the flag is not mentioned in new man pages anymore, - # it still works. - flag='-w' - ;; - freebsd|openbsd) - flag='' - ;; + # Linux + redhat|centos|ubuntu|debian|devuan|archlinux|gentoo|coreos) + flag='-w' + ;; + # BusyBox + alpine|openwrt) + flag='-w' + ;; + macosx) + # NOTE: Older versions of Mac OS X require the -w option. + # Even though the flag is not mentioned in new man pages anymore, + # it still works. + flag='-w' + ;; + netbsd) + flag='-w' + ;; + freebsd|openbsd) + flag='' + ;; esac # set the current runtime value From e3b0cbe8ac4b75e5268d9c6ff1538ca4e809d8fd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 14 Dec 2018 15:20:17 +0100 Subject: [PATCH 1006/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index a662eb38..e1e3fdb6 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Type __consul_agent: Add Debian 9 support (Jin-Guk Kwon) * Documentation: Fix broken links (Rage ) * Type __docker: Add version parameter (Jonas Weber) + * Type __sysctl: Refactor for better OS support (Takashi Yoshi) 4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) From c492c53a9867e1218c5a5aba6ac987257e128495 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 7 Dec 2018 16:56:36 +0100 Subject: [PATCH 1007/1332] [type/__package_pkg_openbsd] Send error messages to stderr --- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 61383edb..a189eeac 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -96,7 +96,7 @@ if [ \$? -ne 0 ]; then if [ -z "\${status}" ]; then status="Failed to add package, uncaught exception." fi - echo "Error: \$status" + echo "Error: \$status" >&2 exit 1 fi eof @@ -114,7 +114,7 @@ if [ \$? -eq 0 ]; then if [ -z "\${status}" ]; then status="Failed to remove package, uncaught exception." fi - echo "Error: \$status" + echo "Error: \$status" >&2 exit 1 fi eof From 827081f8a280742ff7309515f476002717c18c1b Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 7 Dec 2018 17:32:43 +0100 Subject: [PATCH 1008/1332] [type/__package_pkg_openbsd/explorer/pkg_version] Fix version extraction The earlier code stripped away all non-numeric parts of the version number. E.g. "5.6.38p0" would be trimmed to "5.6.38" --- .../type/__package_pkg_openbsd/explorer/pkg_version | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version index 212f0d96..71fccb42 100755 --- a/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version +++ b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version @@ -19,7 +19,7 @@ # along with cdist. If not, see . # # -# Retrieve the status of a package - parsed dpkg output +# Retrieve the status of a package - parsed pkg_info output # if [ -f "$__object/parameter/name" ]; then @@ -28,5 +28,10 @@ else name="$__object_id" fi -#TODO: Is there a better way? -pkg_info | grep "^$name-[0-9]" | sed 's|.*\(-[0-9][0-9.]*\).*|\1|' | sed 's/-//' +# Extract version number from pkg_info. +# Refer to packages-specs(7) for more information regarding the format. + +# ATTENTION: If $name is just a stem (e.g. "php" or "python"), there may be +# multiple results. pkg_info prints a line for each version. + +pkg_info -q -I "inst:$name" | sed -e 's/^\([^-]*-\)*\([0-9][^-]*\).*$/\2/' From 498628d16a769132fe68c95f259c3bb557aab7e9 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 7 Dec 2018 19:02:43 +0100 Subject: [PATCH 1009/1332] [type/__package_pkg_openbsd] Misc. fixes and improvements --- .../__package_pkg_openbsd/explorer/pkg_state | 49 +++++++++++++++++++ .../explorer/pkg_version | 3 +- .../type/__package_pkg_openbsd/gencode-remote | 12 ++--- 3 files changed, 55 insertions(+), 9 deletions(-) create mode 100755 cdist/conf/type/__package_pkg_openbsd/explorer/pkg_state diff --git a/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_state b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_state new file mode 100755 index 00000000..9cd17787 --- /dev/null +++ b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_state @@ -0,0 +1,49 @@ +#!/bin/sh +# +# Copyright 2018, Takashi Yoshi +# +# 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 . +# +# +# Retrieve the status of a package - parsed pkg_info output +# + +if [ -f "${__object}/parameter/name" ] +then + pkgid="$(cat "${__object}/parameter/name")" +else + pkgid="${__object_id}" +fi + +if [ -f "${__object}/parameter/version" ] +then + pkgid="${pkgid}-$(cat "${__object}/parameter/version")" +fi + +if [ -f "${__object}/parameter/flavor" ] +then + # If a flavor but no version is given we need to add another -, + # otherwise pkg_info confuses the flavor with the version. + [ -f "${__object}/parameter/version" ] || pkgid="${pkgid}-" + + pkgid="${pkgid}-$(cat "${__object}/parameter/flavor")" +fi + + +pkg_info -q -I "inst:${pkgid}" >/dev/null 2>&1 \ + && echo 'present' || echo 'absent' + +exit 0 diff --git a/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version index 71fccb42..9b51a588 100755 --- a/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version +++ b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version @@ -2,6 +2,7 @@ # # 2011 Andi Brönnimann (andi-cdist at v-net.ch) # Copyright 2017, Philippe Gregoire +# Copyright 2018, Takashi Yoshi # # This file is part of cdist. # @@ -19,7 +20,7 @@ # along with cdist. If not, see . # # -# Retrieve the status of a package - parsed pkg_info output +# Retrieve the version of a package - parsed pkg_info output # if [ -f "$__object/parameter/name" ]; then diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index a189eeac..0a79fca3 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -2,6 +2,7 @@ # # 2011 Andi Brönnimann (andi-cdist at v-net.ch) # 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2018 Takashi Yoshi # # This file is part of cdist. # @@ -72,12 +73,7 @@ else fi fi -if [ "$pkg_version" ]; then - state_is="present" -else - state_is="absent" -fi - +state_is="$(cat "$__object/explorer/pkg_state")" [ "$state_is" = "$state_should" ] && exit 0 case "$state_should" in @@ -88,7 +84,7 @@ if [ X != X"${pkg_path}" ]; then PKG_PATH="${pkg_path}"; export PKG_PATH fi status=\$(pkg_add "$pkgopts" "$pkgid" 2>&1) -pkg_info | grep "^${name}.*${version}.*${flavor}" > /dev/null 2>&1 +pkg_info -q -I "inst:$pkgid" | grep -q "^${name}-${version}.*${flavor}$" 2>/dev/null # We didn't find the package in the list of 'installed packages', so it failed # This is necessary because pkg_add doesn't return properly @@ -106,7 +102,7 @@ eof # use this because pkg_add doesn't properly handle errors cat << eof status=\$(pkg_delete "$pkgopts" "$pkgid") -pkg_info | grep "^${name}.*${version}.*${flavor}" > /dev/null 2>&1 +pkg_info -q -I "inst:$pkgid" | grep -q "^${name}-${version}.*${flavor}" 2>/dev/null # We found the package in the list of 'installed packages' # This would indicate that pkg_delete failed, send the output of pkg_delete From aa456ab6c18754fda8b1cb6c07efb9511acbe236 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 14 Dec 2018 12:35:04 +0100 Subject: [PATCH 1010/1332] [type/__package_pkg_openbsd] Clean up code --- .../type/__package_pkg_openbsd/gencode-remote | 150 +++++++++--------- 1 file changed, 74 insertions(+), 76 deletions(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 0a79fca3..97f9ca46 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -23,100 +23,98 @@ # Manage packages with pkg on OpenBSD # -# Debug -# exec >&2 -# set -x +os_version=$(cat "${__global}/explorer/os_version") +machine=$(cat "${__global}/explorer/machine") -os_version="$(cat "$__global/explorer/os_version")" -machine="$(cat "$__global/explorer/machine")" - -if [ -f "$__object/parameter/version" ]; then - version="$(cat "$__object/parameter/version")" +if [ -f "${__object}/parameter/version" ]; then + version=$(cat "${__object}/parameter/version") fi -if [ -f "$__object/parameter/flavor" ]; then - flavor="$(cat "$__object/parameter/flavor")" +if [ -f "${__object}/parameter/flavor" ]; then + flavor=$(cat "${__object}/parameter/flavor") fi -# do not show progress bar -pkgopts="-x" +# Do not show progress bar +pkgopts='-x' -if [ -f "$__object/parameter/name" ]; then - name=$(cat "$__object/parameter/name") +name="${__object_id}" +if [ -f "${__object}/parameter/name" ]; then + name=$(cat "${__object}/parameter/name") +fi + +if [ -n "${version}" ] && [ -n "${flavor}" ]; then + pkgid="${name}-${version}-${flavor}" +elif [ -n "${version}" ]; then + pkgid="${name}-${version}" +elif [ -f "${__object}/parameter/flavor" ]; then + pkgid="${name}--${flavor}" else - name="$__object_id" + pkgid="${name}" fi -if [ -n "$version" ] && [ -n "$flavor" ]; then - pkgid="$name-$version-$flavor" -elif [ -n "$version" ]; then - pkgid="$name-$version" -elif [ -n "$flavor" ]; then - pkgid="$name--$flavor" -elif [ -f "$__object/parameter/flavor" ]; then - pkgid="$name--" +state_should=$(cat "${__object}/parameter/state") + +pkg_version=$(cat "${__object}/explorer/pkg_version") + +if [ -f "${__object}/parameter/pkg_path" ]; then + pkg_path=$(cat "${__object}/parameter/pkg_path") else - pkgid="$name" + has_installurl=$(cat "${__object}/explorer/has_installurl") + if [ 'yes' != "${has_installurl}" ]; then + # There is no default PKG_PATH, try to provide one + pkg_path="ftp://ftp.openbsd.org/pub/OpenBSD/${os_version}/packages/${machine}/" + fi fi -state_should="$(cat "$__object/parameter/state")" +state_is=$(cat "${__object}/explorer/pkg_state") +[ "${state_is}" = "${state_should}" ] && exit 0 -pkg_version="$(cat "$__object/explorer/pkg_version")" +case "${state_should}" in + present) + if [ -n "${pkg_path}" ]; then + echo "export PKG_PATH='${pkg_path}'" + fi -if [ -f "$__object/parameter/pkg_path" ]; then - pkg_path="$(cat "$__object/parameter/pkg_path")" -else - has_installurl=$(cat "${__object}/explorer/has_installurl") - if [ Xyes != X"${has_installurl}" ]; then - # there is no default PKG_PATH, try to provide one - pkg_path="ftp://ftp.openbsd.org/pub/OpenBSD/$os_version/packages/$machine/" - fi -fi + # Use this because pkg_add doesn't properly handle errors + cat << EOF +status=\$(pkg_add ${pkgopts} '${pkgid}' 2>&1 || true) -state_is="$(cat "$__object/explorer/pkg_state")" -[ "$state_is" = "$state_should" ] && exit 0 +if ! pkg_info -q -I 'inst:${pkgid}' | grep -q '^${name}-${version}.*${flavor}$' 2>/dev/null +then + # We didn't find the package in the list of 'installed packages', so it failed. + # This is necessary because pkg_add doesn't return properly -case "$state_should" in - present) - # use this because pkg_add doesn't properly handle errors - cat << eof -if [ X != X"${pkg_path}" ]; then - PKG_PATH="${pkg_path}"; export PKG_PATH + if [ -z "\${status}" ]; then + status='Failed to add package, uncaught exception.' + fi + echo "Error: \${status}" >&2 + exit 1 fi -status=\$(pkg_add "$pkgopts" "$pkgid" 2>&1) -pkg_info -q -I "inst:$pkgid" | grep -q "^${name}-${version}.*${flavor}$" 2>/dev/null +EOF + echo 'installed' >> "${__messages_out}" + ;; -# We didn't find the package in the list of 'installed packages', so it failed -# This is necessary because pkg_add doesn't return properly -if [ \$? -ne 0 ]; then - if [ -z "\${status}" ]; then - status="Failed to add package, uncaught exception." - fi - echo "Error: \$status" >&2 - exit 1 + absent) + # Use this because pkg_delete doesn't properly handle errors + cat << EOF +status=\$(pkg_delete ${pkgopts} '${pkgid}' || true) + +if pkg_info -q -I 'inst:${pkgid}' | grep -q '^${name}-${version}.*${flavor}' 2>/dev/null +then + # We found the package in the list of 'installed packages'. + # This would indicate that pkg_delete failed, send the output of pkg_delete + + if [ -z "\${status}" ]; then + status='Failed to remove package, uncaught exception.' + fi + echo "Error: \${status}" >&2 + exit 1 fi -eof - ;; - - absent) - # use this because pkg_add doesn't properly handle errors - cat << eof -status=\$(pkg_delete "$pkgopts" "$pkgid") -pkg_info -q -I "inst:$pkgid" | grep -q "^${name}-${version}.*${flavor}" 2>/dev/null - -# We found the package in the list of 'installed packages' -# This would indicate that pkg_delete failed, send the output of pkg_delete -if [ \$? -eq 0 ]; then - if [ -z "\${status}" ]; then - status="Failed to remove package, uncaught exception." - fi - echo "Error: \$status" >&2 - exit 1 -fi -eof - ;; - *) - echo "Unknown state: $state_should" >&2 +EOF + echo 'removed' >> "${__messages_out}" + ;; + *) + echo "Unknown state: ${state_should}" >&2 exit 1 - ;; + ;; esac From a7f1eda3280d4919c8da977674d4881ddf883929 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 7 Dec 2018 16:56:36 +0100 Subject: [PATCH 1011/1332] [type/__package_emerge] Send error messages to stderr --- cdist/conf/type/__package_emerge/gencode-remote | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote index c25f2be7..b144ede4 100755 --- a/cdist/conf/type/__package_emerge/gencode-remote +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -39,12 +39,12 @@ pkg_version="$(cat "$__object/explorer/pkg_version")" if [ -z "$pkg_version" ]; then state_is="absent" elif [ -z "$version" ] && [ "$(echo "$pkg_version" | wc -l)" -gt 1 ]; then - echo "Package name is not unique! The following packages are installed:" - echo "$pkg_version" + echo "Package name is not unique! The following packages are installed:" >&2 + echo "$pkg_version" >&2 exit 1 elif [ -n "$version" ] && [ "$(echo "$pkg_version" | cut -d " " -f 1 | sort | uniq | wc -l)" -gt 1 ]; then - echo "Package name is not unique! The following packages are installed:" - echo "$pkg_version" + echo "Package name is not unique! The following packages are installed:" >&2 + echo "$pkg_version" >&2 exit 1 else state_is="present" From 93b0727c3b1eb326edfa7db71926a16f482dabee Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 14 Dec 2018 16:19:30 +0100 Subject: [PATCH 1012/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e1e3fdb6..1c5e6a05 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Documentation: Fix broken links (Rage ) * Type __docker: Add version parameter (Jonas Weber) * Type __sysctl: Refactor for better OS support (Takashi Yoshi) + * Types __package_*: Add messaging upon installation/removal (Takashi Yoshi) 4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) From ede076e7c5bba2d5bac06f9fae8dfd54499acf90 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Fri, 14 Dec 2018 21:20:24 +0100 Subject: [PATCH 1013/1332] [type/__package_pkg_openbsd] Send messages local instead of remote --- cdist/conf/type/__package_pkg_openbsd/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index da63626b..4187a84c 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -99,8 +99,8 @@ if [ \$? -ne 0 ]; then echo "Error: \$status" exit 1 fi -echo "installed" >> "$__messages_out" eof +echo "installed" >> "$__messages_out" ;; absent) @@ -118,8 +118,8 @@ if [ \$? -eq 0 ]; then echo "Error: \$status" exit 1 fi -echo "removed" >> "$__messages_out" eof +echo "removed" >> "$__messages_out" ;; *) echo "Unknown state: $state_should" >&2 From 794f20007f1f5bd4c15bab9ae0f0e3329dbaf696 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 19 Dec 2018 17:14:37 +0100 Subject: [PATCH 1014/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 1c5e6a05..564d187c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Type __docker: Add version parameter (Jonas Weber) * Type __sysctl: Refactor for better OS support (Takashi Yoshi) * Types __package_*: Add messaging upon installation/removal (Takashi Yoshi) + * Type __package_pkg_openbsd: Reworked (Takashi Yoshi) 4.10.4: 2018-11-03 * Core: Transfer all files of a directory at once instead of calling copy once per file (myeisha) From 0cb3cbae1b1a3dbf05410bc598922c092da89220 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 21 Dec 2018 22:23:41 +0100 Subject: [PATCH 1015/1332] Remove unused explorer --- .../explorer/pkg_version | 38 ------------------- .../type/__package_pkg_openbsd/gencode-remote | 2 - 2 files changed, 40 deletions(-) delete mode 100755 cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version diff --git a/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version b/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version deleted file mode 100755 index 9b51a588..00000000 --- a/cdist/conf/type/__package_pkg_openbsd/explorer/pkg_version +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -# -# 2011 Andi Brönnimann (andi-cdist at v-net.ch) -# Copyright 2017, Philippe Gregoire -# Copyright 2018, Takashi Yoshi -# -# 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 . -# -# -# Retrieve the version of a package - parsed pkg_info output -# - -if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" -else - name="$__object_id" -fi - -# Extract version number from pkg_info. -# Refer to packages-specs(7) for more information regarding the format. - -# ATTENTION: If $name is just a stem (e.g. "php" or "python"), there may be -# multiple results. pkg_info prints a line for each version. - -pkg_info -q -I "inst:$name" | sed -e 's/^\([^-]*-\)*\([0-9][^-]*\).*$/\2/' diff --git a/cdist/conf/type/__package_pkg_openbsd/gencode-remote b/cdist/conf/type/__package_pkg_openbsd/gencode-remote index 9b9d8fc3..5a21ce12 100755 --- a/cdist/conf/type/__package_pkg_openbsd/gencode-remote +++ b/cdist/conf/type/__package_pkg_openbsd/gencode-remote @@ -54,8 +54,6 @@ fi state_should=$(cat "${__object}/parameter/state") -pkg_version=$(cat "${__object}/explorer/pkg_version") - if [ -f "${__object}/parameter/pkg_path" ]; then pkg_path=$(cat "${__object}/parameter/pkg_path") else From 5d3598b96ea6498d9b5c21e32420aa901f234e7d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 21 Dec 2018 22:24:02 +0100 Subject: [PATCH 1016/1332] Release 4.10.5 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 564d187c..5dbf9bb5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.5: 2018-12-21 * Type __group: Fix/remove '--' from echo command (Dimitrios Apostolou) * New type: __ping (Olliver Schinagl) * Type __postgres_role: Fix broken syntax (Nico Schottelius, Darko Poljak) From 0bdd590344ba424602cded5ddbfb34747d83718d Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 22 Jan 2019 13:30:06 +0100 Subject: [PATCH 1017/1332] readd the use of echo in my explorers this is nessessary for remove blanks in output (strip) catch exit codes of zypper (for example if no repo is defined at all) --- cdist/conf/type/__zypper_repo/explorer/all_repo_ids | 2 +- cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids | 2 +- cdist/conf/type/__zypper_repo/explorer/repo_id | 2 +- cdist/conf/type/__zypper_service/explorer/repo_ids | 2 +- cdist/conf/type/__zypper_service/explorer/service_id | 2 +- cdist/conf/type/__zypper_service/explorer/service_ids | 2 +- cdist/conf/type/__zypper_service/explorer/service_uri | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids index dde6d554..b37d8ac5 100644 --- a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids @@ -21,4 +21,4 @@ # Retrieve all repo id nummbers - parsed zypper output # # -zypper lr | cut -d'|' -f 1 | grep -E '^[0-9]' +echo $(zypper lr | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids index b011c258..2dfb946f 100644 --- a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids @@ -23,4 +23,4 @@ # # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper lr -E | cut -d'|' -f 1 | grep -E '^[0-9]') -zypper lr | grep -E '^[0-9]([^|]+\|){3,3} Yes' | cut -d'|' -f 1 +echo $(zypper lr | grep -E '^[0-9]([^|]+\|){3,3} Yes' | cut -d'|' -f 1) diff --git a/cdist/conf/type/__zypper_repo/explorer/repo_id b/cdist/conf/type/__zypper_repo/explorer/repo_id index 114c6fe7..93832ceb 100644 --- a/cdist/conf/type/__zypper_repo/explorer/repo_id +++ b/cdist/conf/type/__zypper_repo/explorer/repo_id @@ -26,4 +26,4 @@ if [ -f "$__object/parameter/uri" ]; then else uri="$__object_id" fi -zypper lr -u | grep -F "$uri" | cut -d'|' -f 1 | grep -E '^[0-9]' +echo $(zypper lr -u | grep -F "$uri" | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/repo_ids b/cdist/conf/type/__zypper_service/explorer/repo_ids index 787e9869..e831b76c 100644 --- a/cdist/conf/type/__zypper_service/explorer/repo_ids +++ b/cdist/conf/type/__zypper_service/explorer/repo_ids @@ -24,4 +24,4 @@ # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper lr -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') # on older systems, zypper doesn't know the parameter -E -zypper lr -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]' +echo $(zypper lr -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_id b/cdist/conf/type/__zypper_service/explorer/service_id index 7161f804..4da8ac01 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_id +++ b/cdist/conf/type/__zypper_service/explorer/service_id @@ -27,4 +27,4 @@ else fi # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 1 ) -zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\\<$uri\\>" | cut -d'|' -f 1 +echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\\<$uri\\>" | cut -d'|' -f 1) diff --git a/cdist/conf/type/__zypper_service/explorer/service_ids b/cdist/conf/type/__zypper_service/explorer/service_ids index 6491ab90..0f1f4186 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_ids +++ b/cdist/conf/type/__zypper_service/explorer/service_ids @@ -22,4 +22,4 @@ # # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') -zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]' +echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri index 2476ab71..06014df8 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_uri +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -25,4 +25,4 @@ if [ -f "$__object/parameter/uri" ]; then else uri="/$__object_id" fi -zypper ls -u | awk 'BEGIN { FS = "[ ]+\\|[ ]+" } ; $4 == "Yes" && $NF == "'"$uri"'" {print $NF}' +echo $(zypper ls -u | awk 'BEGIN { FS = "[ ]+\\|[ ]+" } ; $4 == "Yes" && $NF == "'"$uri"'" {print $NF}') From 67c3c8ca12987a0a69c94775283b66680d0b26e7 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Mon, 28 Jan 2019 09:32:02 +0100 Subject: [PATCH 1018/1332] Added a startup flag for prometheus alertmanager aded the flag --cluster.advertise-address since it is needed for startup on a machine which does not provide a private v4 --- cdist/conf/type/__prometheus_alertmanager/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__prometheus_alertmanager/manifest b/cdist/conf/type/__prometheus_alertmanager/manifest index 64ef76af..8ee818c3 100755 --- a/cdist/conf/type/__prometheus_alertmanager/manifest +++ b/cdist/conf/type/__prometheus_alertmanager/manifest @@ -49,7 +49,7 @@ __key_value alertmanager_fix_init_script --file /etc/init.d/prometheus-alertmana ##### CONFIGURE ############################################################# -FLAGS="--storage.path $storage_path --data.retention $((retention_days*24))h --web.listen-address [::]:9093" +FLAGS="--storage.path $storage_path --data.retention $((retention_days*24))h --web.listen-address [::]:9093 --cluster.advertise-address [::]:9093" require="$require $require_pkg" \ __key_value alertmanager_args --file /etc/default/prometheus-alertmanager \ From a77983aeadc1f5840f9be805b89373bb6d9cfb3e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 28 Jan 2019 19:09:36 +0100 Subject: [PATCH 1019/1332] Reorganize parsers right --- cdist/argparse.py | 42 ++++++++++++++++++++--------------------- docs/src/man1/cdist.rst | 32 +++++++++++++++---------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 0ee9d7b1..72fc0d0f 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -161,6 +161,16 @@ def get_parsers(): # Config parser['config_main'] = argparse.ArgumentParser(add_help=False) + parser['config_main'].add_argument( + '-4', '--force-ipv4', + help=('Force to use IPv4 addresses only. No influence for custom' + ' remote commands.'), + action='store_const', dest='force_ipv', const=4) + parser['config_main'].add_argument( + '-6', '--force-ipv6', + help=('Force to use IPv6 addresses only. No influence for custom' + ' remote commands.'), + action='store_const', dest='force_ipv', const=6) parser['config_main'].add_argument( '-C', '--cache-path-pattern', help=('Specify custom cache path pattern. If ' @@ -191,6 +201,11 @@ def get_parsers(): parser['config_main'].add_argument( '-o', '--out-dir', help='Directory to save cdist output in.', dest="out_path") + parser['config_main'].add_argument( + '-P', '--timestamp', + help=('Timestamp log messages with the current local date and time ' + 'in the format: YYYYMMDDHHMMSS.us.'), + action='store_true', dest='timestamp') parser['config_main'].add_argument( '-R', '--use-archiving', nargs='?', choices=('tar', 'tgz', 'tbz2', 'txz',), @@ -220,19 +235,13 @@ def get_parsers(): '(should behave like ssh).'), action='store', dest='remote_exec', default=None) + parser['config_main'].add_argument( + '-S', '--disable-saving-output-streams', + help='Disable saving output streams.', + action='store_false', dest='save_output_streams', default=True) # Config parser['config_args'] = argparse.ArgumentParser(add_help=False) - parser['config_args'].add_argument( - '-4', '--force-ipv4', - help=('Force to use IPv4 addresses only. No influence for custom' - ' remote commands.'), - action='store_const', dest='force_ipv', const=4) - parser['config_args'].add_argument( - '-6', '--force-ipv6', - help=('Force to use IPv6 addresses only. No influence for custom' - ' remote commands.'), - action='store_const', dest='force_ipv', const=6) parser['config_args'].add_argument( '-A', '--all-tagged', help=('Use all hosts present in tags db. Currently in beta.'), @@ -242,8 +251,6 @@ def get_parsers(): help=('List hosts that have all specified tags, ' 'if -t/--tag is specified.'), action="store_true", dest="has_all_tags", default=False) - parser['config_args'].add_argument( - 'host', nargs='*', help='Host(s) to operate on.') parser['config_args'].add_argument( '-f', '--file', help=('Read specified file for a list of additional hosts to ' @@ -251,11 +258,6 @@ def get_parsers(): 'line). If no host or host file is specified then, by ' 'default, read hosts from stdin.'), dest='hostfile', required=False) - parser['config_args'].add_argument( - '-P', '--timestamp', - help=('Timestamp log messages with the current local date and time ' - 'in the format: YYYYMMDDHHMMSS.us.'), - action='store_true', dest='timestamp') parser['config_args'].add_argument( '-p', '--parallel', nargs='?', metavar='HOST_MAX', type=functools.partial(check_lower_bounded_int, lower_bound=1, @@ -265,10 +267,6 @@ def get_parsers(): 'default.'), action='store', dest='parallel', const=multiprocessing.cpu_count()) - parser['config_args'].add_argument( - '-S', '--disable-saving-output-streams', - help='Disable saving output streams.', - action='store_false', dest='save_output_streams', default=True) parser['config_args'].add_argument( '-s', '--sequential', help='Operate on multiple hosts sequentially (default).', @@ -279,6 +277,8 @@ def get_parsers(): 'list all hosts that contain any of specified tags. ' 'Currently in beta.'), dest='tag', required=False, action="store_true", default=False) + parser['config_args'].add_argument( + 'host', nargs='*', help='Host(s) to operate on.') parser['config'] = parser['sub'].add_parser( 'config', parents=[parser['loglevel'], parser['beta'], parser['common'], diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 3a74f1ef..2eb0ce00 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -15,23 +15,23 @@ SYNOPSIS cdist banner [-h] [-l LOGLEVEL] [-q] [-v] - cdist config [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] - [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] - [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] - [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] - [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-4] [-6] - [-A] [-a] [-f HOSTFILE] [-P] [-p [HOST_MAX]] [-S] [-s] - [-t] - [host [host ...]] + cdist config [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] [-4] + [-6] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] + [-j [JOBS]] [-n] [-o OUT_PATH] [-P] + [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_PATH] + [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] + [-S] [-I INVENTORY_DIR] [-A] [-a] [-f HOSTFILE] + [-p [HOST_MAX]] [-s] [-t] + [host [host ...]] - cdist install [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] - [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] - [-j [JOBS]] [-n] [-o OUT_PATH] [-R [{tar,tgz,tbz2,txz}]] - [-r REMOTE_OUT_DIR] [--remote-copy REMOTE_COPY] - [--remote-exec REMOTE_EXEC] [-I INVENTORY_DIR] [-4] [-6] - [-A] [-a] [-f HOSTFILE] [-P] [-p [HOST_MAX]] [-S] [-s] - [-t] - [host [host ...]] + cdist install [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-g CONFIG_FILE] [-4] + [-6] [-C CACHE_PATH_PATTERN] [-c CONF_DIR] [-i MANIFEST] + [-j [JOBS]] [-n] [-o OUT_PATH] [-P] + [-R [{tar,tgz,tbz2,txz}]] [-r REMOTE_OUT_PATH] + [--remote-copy REMOTE_COPY] [--remote-exec REMOTE_EXEC] + [-S] [-I INVENTORY_DIR] [-A] [-a] [-f HOSTFILE] + [-p [HOST_MAX]] [-s] [-t] + [host [host ...]] cdist inventory [-h] {add-host,add-tag,del-host,del-tag,list} ... From 82cfea0f3c06f8dcd1707c051a7ecddf42ed2517 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 28 Jan 2019 19:14:28 +0100 Subject: [PATCH 1020/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 5dbf9bb5..2449c2ed 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) + 4.10.5: 2018-12-21 * Type __group: Fix/remove '--' from echo command (Dimitrios Apostolou) * New type: __ping (Olliver Schinagl) From df693b9f471bab051720f557c14d2be617bde9fe Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 13 Feb 2019 11:30:55 +0100 Subject: [PATCH 1021/1332] added # shellcheck disable=SC2005 where we need the echo in __zypper explorers --- cdist/conf/type/__zypper_repo/explorer/all_repo_ids | 1 + cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids | 2 ++ cdist/conf/type/__zypper_repo/explorer/repo_id | 1 + cdist/conf/type/__zypper_service/explorer/repo_ids | 2 ++ cdist/conf/type/__zypper_service/explorer/service_id | 2 ++ cdist/conf/type/__zypper_service/explorer/service_ids | 2 ++ cdist/conf/type/__zypper_service/explorer/service_uri | 1 + 7 files changed, 11 insertions(+) diff --git a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids index b37d8ac5..a4fd0368 100644 --- a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids @@ -21,4 +21,5 @@ # Retrieve all repo id nummbers - parsed zypper output # # +# shellcheck disable=SC2005 echo $(zypper lr | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids index 2dfb946f..b8e9ef3a 100644 --- a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids @@ -23,4 +23,6 @@ # # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper lr -E | cut -d'|' -f 1 | grep -E '^[0-9]') +# +# shellcheck disable=SC2005 echo $(zypper lr | grep -E '^[0-9]([^|]+\|){3,3} Yes' | cut -d'|' -f 1) diff --git a/cdist/conf/type/__zypper_repo/explorer/repo_id b/cdist/conf/type/__zypper_repo/explorer/repo_id index 93832ceb..43b2f1c0 100644 --- a/cdist/conf/type/__zypper_repo/explorer/repo_id +++ b/cdist/conf/type/__zypper_repo/explorer/repo_id @@ -26,4 +26,5 @@ if [ -f "$__object/parameter/uri" ]; then else uri="$__object_id" fi +# shellcheck disable=SC2005 echo $(zypper lr -u | grep -F "$uri" | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/repo_ids b/cdist/conf/type/__zypper_service/explorer/repo_ids index e831b76c..b7992402 100644 --- a/cdist/conf/type/__zypper_service/explorer/repo_ids +++ b/cdist/conf/type/__zypper_service/explorer/repo_ids @@ -24,4 +24,6 @@ # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper lr -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') # on older systems, zypper doesn't know the parameter -E +# +# shellcheck disable=SC2005 echo $(zypper lr -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_id b/cdist/conf/type/__zypper_service/explorer/service_id index 4da8ac01..5a0fc5fa 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_id +++ b/cdist/conf/type/__zypper_service/explorer/service_id @@ -27,4 +27,6 @@ else fi # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 1 ) +# +# shellcheck disable=SC2005 echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\\<$uri\\>" | cut -d'|' -f 1) diff --git a/cdist/conf/type/__zypper_service/explorer/service_ids b/cdist/conf/type/__zypper_service/explorer/service_ids index 0f1f4186..e9c66458 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_ids +++ b/cdist/conf/type/__zypper_service/explorer/service_ids @@ -22,4 +22,6 @@ # # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') +# +# shellcheck disable=SC2005 echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri index 06014df8..caccf237 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_uri +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -25,4 +25,5 @@ if [ -f "$__object/parameter/uri" ]; then else uri="/$__object_id" fi +# shellcheck disable=SC2005 echo $(zypper ls -u | awk 'BEGIN { FS = "[ ]+\\|[ ]+" } ; $4 == "Yes" && $NF == "'"$uri"'" {print $NF}') From ef9d5494cdfe9ec198b77de6898bd625b26c1952 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 13 Feb 2019 18:16:59 +0100 Subject: [PATCH 1022/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 2449c2ed..2c9be634 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) + * Types __zypper_repo, __zypper_service: Re-add the use of echo in explorers (Daniel Heule) 4.10.5: 2018-12-21 * Type __group: Fix/remove '--' from echo command (Dimitrios Apostolou) From 51fa8af6b7d2b43eaf8610479ac4d3e70feb7116 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Feb 2019 20:34:45 +0100 Subject: [PATCH 1023/1332] pycodestyle --- cdist/core/cdist_object.py | 11 ++++++++--- cdist/test/inventory/__init__.py | 1 + setup.py | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index e2cd22a2..237f0ddd 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -108,7 +108,9 @@ class CdistObject(object): @staticmethod def split_name(object_name): - """split_name('__type_name/the/object_id') -> ('__type_name', 'the/object_id') + """split_name('__type_name/the/object_id') + -> + ('__type_name', 'the/object_id') Split the given object name into it's type and object_id parts. @@ -119,7 +121,9 @@ class CdistObject(object): @staticmethod def join_name(type_name, object_id): - """join_name('__type_name', 'the/object_id') -> __type_name/the/object_id' + """join_name('__type_name', 'the/object_id') + -> + __type_name/the/object_id' Join the given type_name and object_id into an object name. @@ -162,7 +166,8 @@ class CdistObject(object): # (parameters: %s)" % (self.cdist_type.name, self.parameters)) def object_from_name(self, object_name): - """Convenience method for creating an object instance from an object name. + """Convenience method for creating an object instance from an object + name. Mainly intended to create objects when resolving requirements. diff --git a/cdist/test/inventory/__init__.py b/cdist/test/inventory/__init__.py index 4c0dd936..287c855c 100644 --- a/cdist/test/inventory/__init__.py +++ b/cdist/test/inventory/__init__.py @@ -472,5 +472,6 @@ class InventoryTestCase(test.CdistTestCase): self.assertEqual(htags, ()) os.remove(hostfile) + if __name__ == "__main__": unittest.main() diff --git a/setup.py b/setup.py index f29a8998..565b66ad 100644 --- a/setup.py +++ b/setup.py @@ -25,6 +25,7 @@ def data_finder(data_dir): return entries + cur = os.getcwd() os.chdir("cdist") package_data = data_finder("conf") From 867b9cb102f791cd0ecb8e616d2a6be6658703d6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Feb 2019 20:40:12 +0100 Subject: [PATCH 1024/1332] shellcheck: SC2236: use -n instead of ! -z --- cdist/conf/type/__package_emerge/gencode-remote | 2 +- cdist/conf/type/__systemd_unit/gencode-remote | 2 +- cdist/conf/type/__zypper_repo/gencode-remote | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote index b144ede4..e1b85ebb 100755 --- a/cdist/conf/type/__package_emerge/gencode-remote +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -58,7 +58,7 @@ fi # Exit if nothing is needed to be done [ "$state_is" = "$state_should" ] && { [ -z "$version" ] || [ "$installed_version" = "$version" ]; } && exit 0 -[ "$state_should" = "absent" ] && [ ! -z "$version" ] && [ "$installed_version" != "$version" ] && exit 0 +[ "$state_should" = "absent" ] && [ -n "$version" ] && [ "$installed_version" != "$version" ] && exit 0 case "$state_should" in diff --git a/cdist/conf/type/__systemd_unit/gencode-remote b/cdist/conf/type/__systemd_unit/gencode-remote index 60486c52..967a6c87 100644 --- a/cdist/conf/type/__systemd_unit/gencode-remote +++ b/cdist/conf/type/__systemd_unit/gencode-remote @@ -23,7 +23,7 @@ state=$(cat "${__object}/parameter/state") current_enablement_state=$(cat "${__object}/explorer/enablement-state") if [ "${state}" = "absent" ]; then - if [ ! -z "${current_enablement_state}" ]; then + if [ -n "${current_enablement_state}" ]; then echo "systemctl --now disable ${name}" echo "rm -f /etc/systemd/system/${name}" echo "systemctl daemon-reload" diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index b8eeef0f..336488ae 100755 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -74,19 +74,19 @@ case "$state" in fi ;; absent) - if [ ! -z "$act_id" ]; then + if [ -n "$act_id" ]; then # Repo present (act_id not ""), so we ned to delete it echo "zypper $zypper_def_opts removerepo $act_id" fi ;; enabled) - if [ ! -z "$act_id" ] && [ "$repostate" = "disabled" ]; then + if [ -n "$act_id" ] && [ "$repostate" = "disabled" ]; then # Repo present (act_id not "") and repostate not enabled, so a enable call is needed echo "zypper $zypper_def_opts modifyrepo -e $act_id" fi ;; disabled) - if [ ! -z "$act_id" ] && [ "$repostate" = "enabled" ]; then + if [ -n "$act_id" ] && [ "$repostate" = "enabled" ]; then # Repo present (act_id not "") and repostate enabled, so a disable call is needed echo "zypper $zypper_def_opts modifyrepo -d $act_id" fi From a40a81d36fad5f8856d1d2519ad60db75b800f9e Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Feb 2019 20:42:46 +0100 Subject: [PATCH 1025/1332] To keep original echo intentionally disable SC2046 too --- cdist/conf/type/__zypper_repo/explorer/all_repo_ids | 2 +- cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids | 2 +- cdist/conf/type/__zypper_repo/explorer/repo_id | 2 +- cdist/conf/type/__zypper_service/explorer/repo_ids | 2 +- cdist/conf/type/__zypper_service/explorer/service_id | 2 +- cdist/conf/type/__zypper_service/explorer/service_ids | 2 +- cdist/conf/type/__zypper_service/explorer/service_uri | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids index a4fd0368..7953158a 100644 --- a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids @@ -21,5 +21,5 @@ # Retrieve all repo id nummbers - parsed zypper output # # -# shellcheck disable=SC2005 +# shellcheck disable=SC2005,SC2046 echo $(zypper lr | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids index b8e9ef3a..261d6073 100644 --- a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids @@ -24,5 +24,5 @@ # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper lr -E | cut -d'|' -f 1 | grep -E '^[0-9]') # -# shellcheck disable=SC2005 +# shellcheck disable=SC2005,SC2046 echo $(zypper lr | grep -E '^[0-9]([^|]+\|){3,3} Yes' | cut -d'|' -f 1) diff --git a/cdist/conf/type/__zypper_repo/explorer/repo_id b/cdist/conf/type/__zypper_repo/explorer/repo_id index 43b2f1c0..d55a5cac 100644 --- a/cdist/conf/type/__zypper_repo/explorer/repo_id +++ b/cdist/conf/type/__zypper_repo/explorer/repo_id @@ -26,5 +26,5 @@ if [ -f "$__object/parameter/uri" ]; then else uri="$__object_id" fi -# shellcheck disable=SC2005 +# shellcheck disable=SC2005,SC2046 echo $(zypper lr -u | grep -F "$uri" | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/repo_ids b/cdist/conf/type/__zypper_service/explorer/repo_ids index b7992402..da506fea 100644 --- a/cdist/conf/type/__zypper_service/explorer/repo_ids +++ b/cdist/conf/type/__zypper_service/explorer/repo_ids @@ -25,5 +25,5 @@ # echo $(zypper lr -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') # on older systems, zypper doesn't know the parameter -E # -# shellcheck disable=SC2005 +# shellcheck disable=SC2005,SC2046 echo $(zypper lr -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_id b/cdist/conf/type/__zypper_service/explorer/service_id index 5a0fc5fa..fbb983c8 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_id +++ b/cdist/conf/type/__zypper_service/explorer/service_id @@ -28,5 +28,5 @@ fi # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 1 ) # -# shellcheck disable=SC2005 +# shellcheck disable=SC2005,SC2046 echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | grep -E "\\<$uri\\>" | cut -d'|' -f 1) diff --git a/cdist/conf/type/__zypper_service/explorer/service_ids b/cdist/conf/type/__zypper_service/explorer/service_ids index e9c66458..5a26740e 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_ids +++ b/cdist/conf/type/__zypper_service/explorer/service_ids @@ -23,5 +23,5 @@ # simpler command which works only on SLES11 SP3 or newer: # echo $(zypper ls -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') # -# shellcheck disable=SC2005 +# shellcheck disable=SC2005,SC2046 echo $(zypper ls -u | grep -E '^([^|]+\|){3,3} Yes' | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri index caccf237..2f3d0f94 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_uri +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -25,5 +25,5 @@ if [ -f "$__object/parameter/uri" ]; then else uri="/$__object_id" fi -# shellcheck disable=SC2005 +# shellcheck disable=SC2005,SC2046 echo $(zypper ls -u | awk 'BEGIN { FS = "[ ]+\\|[ ]+" } ; $4 == "Yes" && $NF == "'"$uri"'" {print $NF}') From afc7ca88b89c17d22ff7f2ed9e655b9000c984e0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Feb 2019 20:28:08 +0100 Subject: [PATCH 1026/1332] Release 4.10.6 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 2c9be634..437731bd 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.6: 2019-02-15 * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) * Types __zypper_repo, __zypper_service: Re-add the use of echo in explorers (Daniel Heule) From 689f37acf61feb0f7bb3d640a1ca14c63a103e17 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 15 Feb 2019 21:05:26 +0100 Subject: [PATCH 1027/1332] Migrate from pep8 to pycodestyle --- Makefile | 2 +- bin/build-helper | 12 ++++++------ bin/build-helper.freebsd | 12 ++++++------ docs/changelog | 3 +++ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 9f81cf06..e140d383 100644 --- a/Makefile +++ b/Makefile @@ -256,7 +256,7 @@ test: test-remote: $(helper) $@ -pep8: +pycodestyle pep8: $(helper) $@ shellcheck-global-explorers: diff --git a/bin/build-helper b/bin/build-helper index 02fa67d6..2179a5ed 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -249,7 +249,7 @@ eof # First check everything is sane "$0" check-date "$0" check-unittest - "$0" check-pep8 + "$0" check-pycodestyle "$0" shellcheck # Generate version file to be included in packaging @@ -365,13 +365,13 @@ eof python3 -m cdist.test.exec.remote ;; - pep8) - pep8 "${basedir}" "${basedir}/scripts/cdist" | less + pycodestyle|pep8) + pycodestyle "${basedir}" "${basedir}/scripts/cdist" | less ;; - check-pep8) - "$0" pep8 - printf "\\nPlease review pep8 report.\\n" + check-pycodestyle) + "$0" pycodestyle + printf "\\nPlease review pycodestyle report.\\n" while true do echo "Continue (yes/no)?" diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 081feb54..a2b8dde7 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -284,7 +284,7 @@ eof # First check everything is sane "$0" check-date "$0" check-unittest - "$0" check-pep8 + "$0" check-pycodestyle "$0" shellcheck # Generate version file to be included in packaging @@ -427,13 +427,13 @@ eof python3 -m cdist.test.exec.remote ;; - pep8) - pep8 "${basedir}" "${basedir}/scripts/cdist" | less + pycodestyle|pep8) + pycodestyle "${basedir}" "${basedir}/scripts/cdist" | less ;; - check-pep8) - "$0" pep8 - printf "\\nPlease review pep8 report.\\n" + check-pycodestyle) + "$0" pycodestyle + printf "\\nPlease review pycodestyle report.\\n" while true do echo "Continue (yes/no)?" diff --git a/docs/changelog b/docs/changelog index 437731bd..0695a4a0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Build: Migrate from pep8 to pycodestyle (Darko Poljak) + 4.10.6: 2019-02-15 * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) * Types __zypper_repo, __zypper_service: Re-add the use of echo in explorers (Daniel Heule) From 15ab7c0810ed3ca6e078dcb6c36e81d06e54dc83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20N=C3=A9ri?= Date: Sat, 16 Mar 2019 17:23:19 +0100 Subject: [PATCH 1028/1332] Implement "__start_on_boot --state absent" for OpenBSD --- cdist/conf/type/__start_on_boot/gencode-remote | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index b9346826..1a3b6ff6 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -82,7 +82,7 @@ case "$state_should" in ;; openbsd) - # OpenBSD 5.7 and phigher + # OpenBSD 5.7 and higher echo "rcctl enable '$name'" ;; @@ -116,6 +116,11 @@ case "$state_should" in openwrt) echo "'/etc/init.d/$name' disable" + ;; + + openbsd) + # OpenBSD 5.7 and higher + echo "rcctl disable '$name'" ;; *) From 73784b04df1c62e6e85eb47728ae7eab644b4318 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 16 Mar 2019 19:00:14 +0100 Subject: [PATCH 1029/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 0695a4a0..ff878471 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Build: Migrate from pep8 to pycodestyle (Darko Poljak) + * Type __start_on_boot: Implement state absent for OpenBSD (Daniel Néri) 4.10.6: 2019-02-15 * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) From 0fc64a951c5d8a3394fc2ac8aa1ae0f52402b56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20N=C3=A9ri?= Date: Tue, 19 Mar 2019 23:09:01 +0100 Subject: [PATCH 1030/1332] explorer/cpu_cores: Add support for OpenBSD --- cdist/conf/explorer/cpu_cores | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cdist/conf/explorer/cpu_cores b/cdist/conf/explorer/cpu_cores index 27cc6800..a52bddac 100755 --- a/cdist/conf/explorer/cpu_cores +++ b/cdist/conf/explorer/cpu_cores @@ -28,6 +28,10 @@ case "$os" in sysctl -n hw.physicalcpu ;; + "openbsd") + sysctl -n hw.ncpuonline + ;; + *) if [ -r /proc/cpuinfo ]; then cores="$(grep "core id" /proc/cpuinfo | sort | uniq | wc -l)" From dbcf7d55432c90bb6be4547d6e49a1e060279a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20N=C3=A9ri?= Date: Tue, 19 Mar 2019 23:13:24 +0100 Subject: [PATCH 1031/1332] explorer/disks: Add support for OpenBSD --- cdist/conf/explorer/disks | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks index 7c60b17a..1780e6d2 100755 --- a/cdist/conf/explorer/disks +++ b/cdist/conf/explorer/disks @@ -1,3 +1,16 @@ -#!/bin/sh -cd /dev || exit 0 -echo sd? hd? vd? +#!/bin/sh -e + +os=$("$__explorer/os") +case "$os" in + openbsd) + IFS=',' disks=$(sysctl -n hw.disknames) + for d in $disks; do + echo "${d%%:*}" + done | sed -n '/^[sw]d[0-9][0-9]*/p' + ;; + + *) + cd /dev || exit 0 + echo sd? hd? vd? + ;; +esac From 825a47b3d94457a7745a71028901e411e1928f31 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 19 Mar 2019 23:30:34 +0100 Subject: [PATCH 1032/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ff878471..502cb20b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Build: Migrate from pep8 to pycodestyle (Darko Poljak) * Type __start_on_boot: Implement state absent for OpenBSD (Daniel Néri) + * Explorers cpu_cores, disks: Add support for OpenBSD (Daniel Néri) 4.10.6: 2019-02-15 * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) From 28e2b058a4562a621b54a59f757764877d6440e1 Mon Sep 17 00:00:00 2001 From: Silas Date: Mon, 25 Mar 2019 18:36:55 -0300 Subject: [PATCH 1033/1332] Use portable -p instead of --tmpdir for mktemp -p is equivalent to --tmpdir, but more portable, since it works across GNU/Linux and *BSDs --- cdist/conf/type/__staged_file/gencode-local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__staged_file/gencode-local b/cdist/conf/type/__staged_file/gencode-local index e78b50bd..ba9e8798 100755 --- a/cdist/conf/type/__staged_file/gencode-local +++ b/cdist/conf/type/__staged_file/gencode-local @@ -63,7 +63,7 @@ fetch_file() { fetch_and_prepare_file() { # shellcheck disable=SC2016 - printf 'tmpdir="$(mktemp -d --tmpdir="/tmp" "%s")"\n' "${__type##*/}.XXXXXXXXXX" + printf 'tmpdir="$(mktemp -d -p "/tmp" "%s")"\n' "${__type##*/}.XXXXXXXXXX" # shellcheck disable=SC2016 printf 'cd "$tmpdir"\n' # shellcheck disable=SC2059 From 59bff817353adaf12f9173ebadd00a80cdd0b080 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 26 Mar 2019 19:01:26 +0100 Subject: [PATCH 1034/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 502cb20b..4f1d4474 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Build: Migrate from pep8 to pycodestyle (Darko Poljak) * Type __start_on_boot: Implement state absent for OpenBSD (Daniel Néri) * Explorers cpu_cores, disks: Add support for OpenBSD (Daniel Néri) + * Type __staged_file: Use portable -p instead of --tmpdir for mktemp (Silas Silva) 4.10.6: 2019-02-15 * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) From 0f6fe4764be5d138e1448c50dd19db743f838ab4 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Thu, 28 Mar 2019 23:31:38 +0200 Subject: [PATCH 1035/1332] add --onchange to __line --- cdist/conf/type/__line/gencode-remote | 4 ++++ cdist/conf/type/__line/man.rst | 2 ++ cdist/conf/type/__line/parameter/optional | 1 + 3 files changed, 7 insertions(+) diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index 044ebe90..03e90c1b 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -122,3 +122,7 @@ END { ' "$file" > "\$tmpfile" mv -f "\$tmpfile" "$file" DONE + +if [ -f "$__object/parameter/onchange" ]; then + cat "$__object/parameter/onchange" +fi diff --git a/cdist/conf/type/__line/man.rst b/cdist/conf/type/__line/man.rst index d651985e..f76cab64 100644 --- a/cdist/conf/type/__line/man.rst +++ b/cdist/conf/type/__line/man.rst @@ -46,6 +46,8 @@ regex state 'present' or 'absent', defaults to 'present' +onchange + The code to run if line is added, removed or updated. BOOLEAN PARAMETERS diff --git a/cdist/conf/type/__line/parameter/optional b/cdist/conf/type/__line/parameter/optional index f89a2115..1c34c699 100644 --- a/cdist/conf/type/__line/parameter/optional +++ b/cdist/conf/type/__line/parameter/optional @@ -4,3 +4,4 @@ file line regex state +onchange From d656058ff45abe7376bd7e9eb3d7e834288099c1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 29 Mar 2019 22:15:05 +0100 Subject: [PATCH 1036/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 4f1d4474..4a4f589c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Type __start_on_boot: Implement state absent for OpenBSD (Daniel Néri) * Explorers cpu_cores, disks: Add support for OpenBSD (Daniel Néri) * Type __staged_file: Use portable -p instead of --tmpdir for mktemp (Silas Silva) + * Type __line: Add onchange parameter (Ander Punnar) 4.10.6: 2019-02-15 * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) From c6fd43da81bbc35b607005b239d4819e453174f6 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 29 Mar 2019 00:38:50 +0200 Subject: [PATCH 1037/1332] add --onchange to __file, because having to use __config_file just for that feels redundant --- cdist/conf/type/__file/gencode-remote | 12 +++++++++++- cdist/conf/type/__file/man.rst | 3 +++ cdist/conf/type/__file/parameter/optional | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index e19d428b..a6f35c0b 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -23,7 +23,7 @@ destination="/$__object_id" state_should="$(cat "$__object/parameter/state")" type="$(cat "$__object/explorer/type")" stat_file="$__object/explorer/stat" - +fire_onchange='' get_current_value() { if [ -s "$stat_file" ]; then @@ -45,16 +45,19 @@ get_current_value() { set_group() { echo "chgrp '$1' '$destination'" echo "chgrp '$1'" >> "$__messages_out" + fire_onchange=1 } set_owner() { echo "chown '$1' '$destination'" echo "chown '$1'" >> "$__messages_out" + fire_onchange=1 } set_mode() { echo "chmod '$1' '$destination'" echo "chmod '$1'" >> "$__messages_out" + fire_onchange=1 } case "$state_should" in @@ -83,6 +86,7 @@ case "$state_should" in if [ "$type" = "file" ]; then echo "rm -f '$destination'" echo remove >> "$__messages_out" + fire_onchange=1 fi ;; @@ -91,3 +95,9 @@ case "$state_should" in exit 1 ;; esac + +if [ -f "$__object/parameter/onchange" ]; then + if [ -n "$fire_onchange" ]; then + cat "$__object/parameter/onchange" + fi +fi diff --git a/cdist/conf/type/__file/man.rst b/cdist/conf/type/__file/man.rst index a141d70b..7a0603bb 100644 --- a/cdist/conf/type/__file/man.rst +++ b/cdist/conf/type/__file/man.rst @@ -63,6 +63,9 @@ source If not supplied, an empty file or directory will be created. If source is '-' (dash), take what was written to stdin as the file content. +onchange + The code to run if file is modified. + MESSAGES -------- chgrp diff --git a/cdist/conf/type/__file/parameter/optional b/cdist/conf/type/__file/parameter/optional index c696d592..9b98352c 100644 --- a/cdist/conf/type/__file/parameter/optional +++ b/cdist/conf/type/__file/parameter/optional @@ -3,3 +3,4 @@ group mode owner source +onchange From 6440faf176ca42ffa90bf0bad05bdab86c8617e0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 29 Mar 2019 22:57:52 +0100 Subject: [PATCH 1038/1332] ++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 4a4f589c..d7f0c44f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: * Explorers cpu_cores, disks: Add support for OpenBSD (Daniel Néri) * Type __staged_file: Use portable -p instead of --tmpdir for mktemp (Silas Silva) * Type __line: Add onchange parameter (Ander Punnar) + * Type __file: Add onchange parameter (Ander Punnar) 4.10.6: 2019-02-15 * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) From 5f76bd5655b4407e831c8978ad5fdc683b85233c Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sat, 30 Mar 2019 13:21:13 +0200 Subject: [PATCH 1039/1332] new type: __clean_path --- cdist/conf/type/__clean_path/explorer/list | 39 ++++++++++++ cdist/conf/type/__clean_path/gencode-remote | 48 +++++++++++++++ cdist/conf/type/__clean_path/man.rst | 60 +++++++++++++++++++ .../conf/type/__clean_path/parameter/optional | 2 + .../conf/type/__clean_path/parameter/required | 1 + 5 files changed, 150 insertions(+) create mode 100755 cdist/conf/type/__clean_path/explorer/list create mode 100755 cdist/conf/type/__clean_path/gencode-remote create mode 100644 cdist/conf/type/__clean_path/man.rst create mode 100644 cdist/conf/type/__clean_path/parameter/optional create mode 100644 cdist/conf/type/__clean_path/parameter/required diff --git a/cdist/conf/type/__clean_path/explorer/list b/cdist/conf/type/__clean_path/explorer/list new file mode 100755 index 00000000..ef46887d --- /dev/null +++ b/cdist/conf/type/__clean_path/explorer/list @@ -0,0 +1,39 @@ +#!/bin/sh -e +# +# 2019 Ander Punnar (ander-at-kvlt-dot-ee) +# +# 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 . +# + +path="/$__object_id" + +if [ ! -d "$path" ] +then + echo "$path is not a directory" >&2 + exit 1 +fi + +pattern="$( cat "$__object/parameter/pattern" )" + +if [ -f "$__object/parameter/exclude" ] +then + exclude="$( cat "$__object/parameter/exclude" )" + + find "$path" -mindepth 1 -maxdepth 1 -regex "$pattern" \ + -and -not -regex "$exclude" +else + find "$path" -mindepth 1 -maxdepth 1 -regex "$pattern" +fi diff --git a/cdist/conf/type/__clean_path/gencode-remote b/cdist/conf/type/__clean_path/gencode-remote new file mode 100755 index 00000000..998a70d8 --- /dev/null +++ b/cdist/conf/type/__clean_path/gencode-remote @@ -0,0 +1,48 @@ +#!/bin/sh -e +# +# 2019 Ander Punnar (ander-at-kvlt-dot-ee) +# +# 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 . +# + +[ ! -s "$__object/explorer/list" ] && exit 0 + +path="/$__object_id" + +pattern="$( cat "$__object/parameter/pattern" )" + +if [ -f "$__object/parameter/exclude" ] +then + exclude="$( cat "$__object/parameter/exclude" )" + + echo "find '$path' -mindepth 1 -maxdepth 1 -regex '$pattern'" \ + "-and -not -regex '$exclude'" \ + '-exec rm -rf {} \;' +else + echo "find '$path' -mindepth 1 -maxdepth 1 -regex '$pattern'" \ + '-exec rm -rf {} \;' +fi + +while read -r f +do + echo "removed '$f'" >> "$__messages_out" +done \ +< "$__object/explorer/list" + +if [ -f "$__object/parameter/onchange" ] +then + cat "$__object/parameter/onchange" +fi diff --git a/cdist/conf/type/__clean_path/man.rst b/cdist/conf/type/__clean_path/man.rst new file mode 100644 index 00000000..826f4589 --- /dev/null +++ b/cdist/conf/type/__clean_path/man.rst @@ -0,0 +1,60 @@ +cdist-type__clean_path(7) +========================= + +NAME +---- +cdist-type__clean_path - Remove files and directories which match the pattern. + + +DESCRIPTION +----------- +Remove files and directories which match the pattern. + +Provided path (as __object_id) must be a directory. + +Patterns are passed to ``find``'s ``-regex`` - see ``find(1)`` for more details. + +Look up of files and directories is non-recursive (``-maxdepth 1``). + +Parent directory is excluded (``-mindepth 1``). + +This type is not POSIX compatible (sorry, Solaris users). + + +REQUIRED PARAMETERS +------------------- +pattern + Pattern of files which are removed from path. + + +OPTIONAL PARAMETERS +------------------- +exclude + Pattern of files which are excluded from removal. + +onchange + The code to run if files or directories were removed. + + +EXAMPLES +-------- + +.. code-block:: sh + + __clean_path /etc/apache2/conf-enabled \ + --pattern '.+' \ + --exclude '.+\(charset\.conf\|security\.conf\)' \ + --onchange 'service apache2 restart' + + +AUTHORS +------- +Ander Punnar + + +COPYING +------- +Copyright \(C) 2019 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/__clean_path/parameter/optional b/cdist/conf/type/__clean_path/parameter/optional new file mode 100644 index 00000000..6f313474 --- /dev/null +++ b/cdist/conf/type/__clean_path/parameter/optional @@ -0,0 +1,2 @@ +exclude +onchange diff --git a/cdist/conf/type/__clean_path/parameter/required b/cdist/conf/type/__clean_path/parameter/required new file mode 100644 index 00000000..54774947 --- /dev/null +++ b/cdist/conf/type/__clean_path/parameter/required @@ -0,0 +1 @@ +pattern From cbaf1b6d8e2bec9e3e45cdec61b512e4e9128dcd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 30 Mar 2019 12:37:25 +0100 Subject: [PATCH 1040/1332] ++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index d7f0c44f..f43e7da4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ next: * Type __staged_file: Use portable -p instead of --tmpdir for mktemp (Silas Silva) * Type __line: Add onchange parameter (Ander Punnar) * Type __file: Add onchange parameter (Ander Punnar) + * New type: __clean_path (Ander Punnar) 4.10.6: 2019-02-15 * Type __prometheus_alertmanager: Add startup flag (Dominique Roux) From 001f9023a24dab6db0ec19dde4bf661bbad2667d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 30 Mar 2019 19:11:13 +0100 Subject: [PATCH 1041/1332] Release 4.10.7 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index f43e7da4..02fab2e4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.7: 2019-03-30 * Build: Migrate from pep8 to pycodestyle (Darko Poljak) * Type __start_on_boot: Implement state absent for OpenBSD (Daniel Néri) * Explorers cpu_cores, disks: Add support for OpenBSD (Daniel Néri) From 668dc836324541a0bb432245dbf9085dcf7caefe Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 2 Apr 2019 17:52:00 +0300 Subject: [PATCH 1042/1332] do not exit with non-zero if path does not exist or not directory --- cdist/conf/type/__clean_path/explorer/list | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cdist/conf/type/__clean_path/explorer/list b/cdist/conf/type/__clean_path/explorer/list index ef46887d..07d38127 100755 --- a/cdist/conf/type/__clean_path/explorer/list +++ b/cdist/conf/type/__clean_path/explorer/list @@ -20,11 +20,7 @@ path="/$__object_id" -if [ ! -d "$path" ] -then - echo "$path is not a directory" >&2 - exit 1 -fi +[ ! -d "$path" ] && exit 0 pattern="$( cat "$__object/parameter/pattern" )" From 033e0611b509926faa4cfe4c0ff8dc160d9d3f34 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 2 Apr 2019 18:39:05 +0200 Subject: [PATCH 1043/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 02fab2e4..8c7fc337 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __clean_path: Fix list explorer exit code if path not directory or does not exist (Ander Punnar) + 4.10.7: 2019-03-30 * Build: Migrate from pep8 to pycodestyle (Darko Poljak) * Type __start_on_boot: Implement state absent for OpenBSD (Daniel Néri) From da6a22c71af46218a38766dc2e23ac8763f252c6 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Wed, 3 Apr 2019 01:11:03 +0300 Subject: [PATCH 1044/1332] new type: __check_messages --- .../conf/type/__check_messages/gencode-remote | 27 ++++++++++ cdist/conf/type/__check_messages/man.rst | 52 +++++++++++++++++++ .../type/__check_messages/parameter/required | 2 + 3 files changed, 81 insertions(+) create mode 100755 cdist/conf/type/__check_messages/gencode-remote create mode 100644 cdist/conf/type/__check_messages/man.rst create mode 100644 cdist/conf/type/__check_messages/parameter/required diff --git a/cdist/conf/type/__check_messages/gencode-remote b/cdist/conf/type/__check_messages/gencode-remote new file mode 100755 index 00000000..1b4cf247 --- /dev/null +++ b/cdist/conf/type/__check_messages/gencode-remote @@ -0,0 +1,27 @@ +#!/bin/sh -e +# +# 2019 Ander Punnar (ander-at-kvlt-dot-ee) +# +# 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 grep -Eq \ + "$( cat "$__object/parameter/pattern" )" \ + "$__messages_in" +then + cat "$__object/parameter/execute" \ + | tee "$__messages_out" +fi diff --git a/cdist/conf/type/__check_messages/man.rst b/cdist/conf/type/__check_messages/man.rst new file mode 100644 index 00000000..cb505cea --- /dev/null +++ b/cdist/conf/type/__check_messages/man.rst @@ -0,0 +1,52 @@ +cdist-type__check_messages(7) +============================= + +NAME +---- +cdist-type__check_messages - Check messages for pattern and execute command on match. + + +DESCRIPTION +----------- +Check messages for pattern and execute command on match. + +This type is useful if you chain together multiple related types using +dependencies and want to restart service if at least one type changes +something. + +For more information about messages see `cdist messaging `_. + +For more information about dependencies and execution order see +`cdist manifest `_ documentation. + + +REQUIRED PARAMETERS +------------------- +pattern + Search pattern (passed to ``grep -E``). + +execute + Command to execute on pattern match. + + +EXAMPLES +-------- + +.. code-block:: sh + + __check_messages munin \ + --pattern '^__(file|link|line)/etc/munin/' \ + --execute 'service munin-node restart' + + +AUTHORS +------- +Ander Punnar + + +COPYING +------- +Copyright \(C) 2019 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/__check_messages/parameter/required b/cdist/conf/type/__check_messages/parameter/required new file mode 100644 index 00000000..374363cb --- /dev/null +++ b/cdist/conf/type/__check_messages/parameter/required @@ -0,0 +1,2 @@ +pattern +execute From decd80bf5de84398db266ea688a2f8c4cde1f31c Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Thu, 4 Apr 2019 00:20:46 +0300 Subject: [PATCH 1045/1332] be more explicit --- cdist/conf/type/__check_messages/man.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__check_messages/man.rst b/cdist/conf/type/__check_messages/man.rst index cb505cea..5c80a0ae 100644 --- a/cdist/conf/type/__check_messages/man.rst +++ b/cdist/conf/type/__check_messages/man.rst @@ -23,7 +23,7 @@ For more information about dependencies and execution order see REQUIRED PARAMETERS ------------------- pattern - Search pattern (passed to ``grep -E``). + Extended regular expression pattern for search (passed to ``grep -E``). execute Command to execute on pattern match. From a5e66bc3f60155410062f891f1fa6d78c86a31a8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Apr 2019 10:43:11 +0200 Subject: [PATCH 1046/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8c7fc337..ee1cd5a0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Type __clean_path: Fix list explorer exit code if path not directory or does not exist (Ander Punnar) + * New type: __check_messages (Ander Punnar) 4.10.7: 2019-03-30 * Build: Migrate from pep8 to pycodestyle (Darko Poljak) From b47c6e3fe4ea0c64d359bb9b41736ff4ef2823c7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Apr 2019 10:52:23 +0200 Subject: [PATCH 1047/1332] Fix shellcheck SC2002 --- cdist/conf/type/__check_messages/gencode-remote | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cdist/conf/type/__check_messages/gencode-remote b/cdist/conf/type/__check_messages/gencode-remote index 1b4cf247..ec36cecc 100755 --- a/cdist/conf/type/__check_messages/gencode-remote +++ b/cdist/conf/type/__check_messages/gencode-remote @@ -22,6 +22,5 @@ if grep -Eq \ "$( cat "$__object/parameter/pattern" )" \ "$__messages_in" then - cat "$__object/parameter/execute" \ - | tee "$__messages_out" + tee "$__messages_out" < "$__object/parameter/execute" fi From 0583cdff09f7f2aec5c522eea3a29c56d76039b2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 6 Apr 2019 10:46:36 +0200 Subject: [PATCH 1048/1332] Release 4.10.8 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index ee1cd5a0..70e3070f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.8: 2019-04-06 * Type __clean_path: Fix list explorer exit code if path not directory or does not exist (Ander Punnar) * New type: __check_messages (Ander Punnar) From 88513e669337c4c59efd277d391c99409ba97a3d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sun, 7 Apr 2019 12:17:19 +0200 Subject: [PATCH 1049/1332] __ssh_authorized_keys: properly handle multiple --option parameters, fixes #393 Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_keys/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index f6ff74c3..8d702875 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -69,7 +69,7 @@ while read -r key; do set -- "$@" --key "$key" set -- "$@" --state "$state" if [ -f "$__object/parameter/option" ]; then - set -- "$@" --option "$(cat "$__object/parameter/option")" + set -- "$@" $(printf -- '--option %s ' $(cat "$__object/parameter/option")) fi if [ -f "$__object/parameter/comment" ]; then set -- "$@" --comment "$(cat "$__object/parameter/comment")" From cabb0be7b645751058e9c0eff7ee6ea686ea90e4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 8 Apr 2019 08:25:53 +0200 Subject: [PATCH 1050/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 70e3070f..1b4fceb8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __ssh_authorized_keys: Properly handle multiple --option params (Steven Armstrong) + 4.10.8: 2019-04-06 * Type __clean_path: Fix list explorer exit code if path not directory or does not exist (Ander Punnar) * New type: __check_messages (Ander Punnar) From 9cd95f12dc0d3532c5b69a1038b4ccae42bf9876 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 5 Apr 2019 12:13:53 +0200 Subject: [PATCH 1051/1332] Add debug dump script --- docs/src/cdist-troubleshooting.rst | 18 ++ scripts/debug-dump.sh | 325 +++++++++++++++++++++++++++++ setup.py | 2 +- 3 files changed, 344 insertions(+), 1 deletion(-) create mode 100755 scripts/debug-dump.sh diff --git a/docs/src/cdist-troubleshooting.rst b/docs/src/cdist-troubleshooting.rst index b016e845..b76f3859 100644 --- a/docs/src/cdist-troubleshooting.rst +++ b/docs/src/cdist-troubleshooting.rst @@ -43,3 +43,21 @@ you write to use the -e flag: % cat ~/.cdist/manifest/special #!/bin/sh -e ... + +Using debug dump helper script +------------------------------ +Since cdist stores data to local cache that can be used for debugging there +is a helper script that dumps data from local cache. + +For more info see: + +.. code-block:: sh + + debug-dump.sh -h + +Or from cdist git cloned directory: + +.. code-block:: sh + + ./scripts/debug-dump.sh -h + diff --git a/scripts/debug-dump.sh b/scripts/debug-dump.sh new file mode 100755 index 00000000..d52273a6 --- /dev/null +++ b/scripts/debug-dump.sh @@ -0,0 +1,325 @@ +#!/bin/sh + +VERSION="0.0.1" +RELEASE="" + +set -u +# set -x + +hosts= +cache_dir=~/.cdist/cache + +do_all=1 +do_global_explorer= +do_type_explorer= +do_script_stdout= +do_script_stderr= +do_gencode= +do_code= +do_messages= +do_parameter= +delimiter=':' +ln= +filename_prefix=1 +verbose=0 + +myname=${0##*/} + +print_version() +{ + printf "%s %s %s\n" "${myname}" "${VERSION}" "${RELEASE}" +} + +usage() +{ + cat << eof +${myname}: [options] [host...] +eof + + print_version + + cat << eof + +Dump data from cache directories. + +host + Dump data for specified hosts. If not specified then all data + from cache directory is dumped. + +Options + -a dump all + -C CACHE-DIR use specified CACHE-DIR (default: ~/.cdist/cache) + -c dump code-* + -d delimiter used for filename and line number prefix (default: ':') + -E dump global explorers + -e dump type explorers + -F disable filename prefix (enabled by default) + -f enable filename prefix (default) + -g dump gencode-* + -h show this help screen and exit + -L disable line number prefix (default) + -l enable line number prefix (disabled by default) + -m dump messages + -o dump executions' stdout + -p dump parameters + -r dump executions' stderr + -V show version and exit + -v increase verbosity +eof +} + +exit_err() +{ + printf "%s\n" "$1" + exit 1 +} + +# parse options +while [ "$#" -ge 1 ] +do + case "$1" in + -a) + do_all=1 + ;; + -C) + if [ "$#" -ge 2 ] + then + case "$2" in + -*) + exit_err "Missing cache directory" + ;; + *) + cache_dir="$2" + shift + ;; + esac + else + exit_err "Missing cache directory" + fi + ;; + -c) + do_code=1 + do_all= + ;; + -d) + if [ "$#" -ge 2 ] + then + case "$2" in + -*) + exit_err "Missing delimiter" + ;; + *) + delimiter="$2" + shift + ;; + esac + else + exit_err "Missing delimiter" + fi + ;; + -E) + do_global_explorer=1 + do_all= + ;; + -e) + do_type_explorer=1 + do_all= + ;; + -F) + filename_prefix= + ;; + -f) + filename_prefix=1 + ;; + -g) + do_gencode=1 + do_all= + ;; + -h) + usage + exit 0 + ;; + -L) + ln= + ;; + -l) + ln=1 + ;; + -m) + do_messages=1 + do_all= + ;; + -o) + do_script_stdout=1 + do_all= + ;; + -p) + do_parameter=1 + do_all= + ;; + -r) + do_script_stderr=1 + do_all= + ;; + -V) + print_version + exit 0 + ;; + -v) + verbose=$((verbose + 1)) + ;; + *) + hosts="${hosts} $1" + break + ;; + esac + shift +done + +if [ "${ln}" = "1" ] +then + ln="NR \"${delimiter}\"" +fi + +if [ "${filename_prefix}" = "1" ] +then + filename_prefix="{}${delimiter}" +fi + +if [ "${do_all}" = "1" ] +then + do_global_explorer=1 + do_type_explorer=1 + do_script_stdout=1 + do_script_stderr=1 + do_gencode=1 + do_code=1 + do_messages=1 + do_parameter=1 +fi + +set -- -size +0 +set -- "$@" \( +or= + +print_verbose() +{ + if [ ${verbose} -ge $1 ] + then + printf "%s\n" "$2" + fi +} + +hor_line() +{ + if [ $# -gt 0 ] + then + c=$1 + else + c='=' + fi + printf "%78s\n" "" | tr ' ' "${c}" +} + +if [ "${do_global_explorer}" ] +then + print_verbose 2 "Dumping global explorers" + set -- "$@" ${or} \( \ + -path "*/explorer/*" -a \ + ! -path "*/conf/*" -a \ + ! -path "*/object/*/explorer/*" \ + \) + or="-o" +fi + +if [ "${do_type_explorer}" ] +then + print_verbose 2 "Dumping type explorers" + set -- "$@" ${or} -path "*/object/*/explorer/*" + or="-o" +fi + +if [ "${do_script_stdout}" ] +then + print_verbose 2 "Dumping execution's stdout" + set -- "$@" ${or} -path "*/stdout/*" + or="-o" +fi + +if [ "${do_script_stderr}" ] +then + print_verbose 2 "Dumping execution's stderr" + set -- "$@" ${or} -path "*/stderr/*" + or="-o" +fi + +if [ "${do_gencode}" ] +then + print_verbose 2 "Dumping gencode-*" + set -- "$@" ${or} \( -name "gencode-*" -a ! -path "*/stdout/*" -a ! -path "*/stderr/*" \) + or="-o" +fi + +if [ "${do_code}" ] +then + print_verbose 2 "Dumping code-*" + set -- "$@" ${or} \( -name "code-*" -a ! -path "*/stdout/*" -a ! -path "*/stderr/*" \) + or="-o" +fi + +if [ "${do_messages}" ] +then + print_verbose 2 "Dumping messages" + set -- "$@" ${or} -name "messages" + or="-o" +fi + +if [ "${do_parameter}" ] +then + print_verbose 2 "Dumping parameters" + set -- "$@" ${or} -path "*/parameter/*" + or="-o" +fi + +set -- "$@" \) +set -- '.' "$@" -exec awk -v prefix="${filename_prefix}" "{print prefix ${ln} \$0}" {} \; + +# printf "+ %s\n" "$*" + +print_verbose 2 "Using cache dir: ${cache_dir}" + +OLD_PWD=$(pwd) +cd "${cache_dir}" + +# If no host is specified then search all. +[ -z "${hosts}" ] && hosts="-" + +for host in ${hosts} +do + [ "${host}" = "-" ] && host= + # find host cache directory + host_dir=$(find . -name target_host -exec grep -l "${host}" {} +) + print_verbose 3 "found host directory files:" + print_verbose 3 "${host_dir}" + + OLD_IFS="${IFS}" + IFS=" + " + + for d in ${host_dir} + do + dir=$(dirname "${d}") + + print_verbose 0 "target host: $(cat ${dir}/target_host), host directory: ${dir}" + hor_line + + PREV_PWD=$(pwd) + cd "${dir}" + # set -x + find "$@" + # set +x + cd "${PREV_PWD}" + done + IFS="${OLD_IFS}" +done +cd "${OLD_PWD}" diff --git a/setup.py b/setup.py index 565b66ad..767f5bf7 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ setup( name="cdist", packages=["cdist", "cdist.core", "cdist.exec", "cdist.util", ], package_data={'cdist': package_data}, - scripts=["scripts/cdist"], + scripts=["scripts/cdist", "scripts/debug-dump.sh"], version=cdist.version.VERSION, description="A Usable Configuration Management System", author="Nico Schottelius", From 8ee667f57f1479ad3fc147ed22e8f7e1d8e10198 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 9 Apr 2019 22:08:47 +0200 Subject: [PATCH 1052/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 1b4fceb8..b3f87c1f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Type __ssh_authorized_keys: Properly handle multiple --option params (Steven Armstrong) + * Debugging: Add debug dump helper script (Darko Poljak) 4.10.8: 2019-04-06 * Type __clean_path: Fix list explorer exit code if path not directory or does not exist (Ander Punnar) From f6b318bb00e63c2fe5d4fae26c66d0fd48470db8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 9 Apr 2019 22:23:21 +0200 Subject: [PATCH 1053/1332] Fire onchange for present and exists states Even if no attribute is changed. Fixes #750. --- cdist/conf/type/__file/gencode-remote | 4 ++++ docs/changelog | 1 + 2 files changed, 5 insertions(+) diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index a6f35c0b..b04c471e 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -79,6 +79,10 @@ case "$state_should" in fi fi done + if [ -f "$__object/files/set-attributes" ]; then + # set-attributes is created if file is created or uploaded in gencode-local + fire_onchange=1 + fi ;; diff --git a/docs/changelog b/docs/changelog index b3f87c1f..7f0b4131 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __ssh_authorized_keys: Properly handle multiple --option params (Steven Armstrong) * Debugging: Add debug dump helper script (Darko Poljak) + * Type __file: Bugfix: fire onchange for present and exists states if no attribute is changed (Darko Poljak) 4.10.8: 2019-04-06 * Type __clean_path: Fix list explorer exit code if path not directory or does not exist (Ander Punnar) From 671bb82a46a982ee580c3445339b09c742c6f686 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 9 Apr 2019 22:44:40 +0200 Subject: [PATCH 1054/1332] Fix shellcheck issues --- Makefile | 5 ++++- cdist/conf/type/__ssh_authorized_keys/manifest | 1 + scripts/debug-dump.sh | 16 ++++++++-------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index e140d383..4ed97c7b 100644 --- a/Makefile +++ b/Makefile @@ -274,11 +274,14 @@ shellcheck-local-gencodes: shellcheck-remote-gencodes: @find cdist/conf/type -type f -name gencode-remote -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 +shellcheck-scripts: + @$(SHELLCHECKCMD) scripts/debug-dump.sh || exit 0 + shellcheck-gencodes: shellcheck-local-gencodes shellcheck-remote-gencodes shellcheck-types: shellcheck-type-explorers shellcheck-manifests shellcheck-gencodes -shellcheck: shellcheck-global-explorers shellcheck-types +shellcheck: shellcheck-global-explorers shellcheck-types shellcheck-scripts shellcheck-type-files: @find cdist/conf/type -type f -path "*/files/*" -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 8d702875..a8ded2f6 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -69,6 +69,7 @@ while read -r key; do set -- "$@" --key "$key" set -- "$@" --state "$state" if [ -f "$__object/parameter/option" ]; then + # shellcheck disable=SC2046 set -- "$@" $(printf -- '--option %s ' $(cat "$__object/parameter/option")) fi if [ -f "$__object/parameter/comment" ]; then diff --git a/scripts/debug-dump.sh b/scripts/debug-dump.sh index d52273a6..ac1190b7 100755 --- a/scripts/debug-dump.sh +++ b/scripts/debug-dump.sh @@ -204,7 +204,7 @@ or= print_verbose() { - if [ ${verbose} -ge $1 ] + if [ "${verbose}" -ge "$1" ] then printf "%s\n" "$2" fi @@ -214,7 +214,7 @@ hor_line() { if [ $# -gt 0 ] then - c=$1 + c="$1" else c='=' fi @@ -289,7 +289,7 @@ set -- '.' "$@" -exec awk -v prefix="${filename_prefix}" "{print prefix ${ln} \$ print_verbose 2 "Using cache dir: ${cache_dir}" OLD_PWD=$(pwd) -cd "${cache_dir}" +cd "${cache_dir}" || exit # If no host is specified then search all. [ -z "${hosts}" ] && hosts="-" @@ -310,16 +310,16 @@ do do dir=$(dirname "${d}") - print_verbose 0 "target host: $(cat ${dir}/target_host), host directory: ${dir}" - hor_line + print_verbose 0 "target host: $(cat "${dir}/target_host"), host directory: ${dir}" + hor_line '=' PREV_PWD=$(pwd) - cd "${dir}" + cd "${dir}" || exit # set -x find "$@" # set +x - cd "${PREV_PWD}" + cd "${PREV_PWD}" || exit done IFS="${OLD_IFS}" done -cd "${OLD_PWD}" +cd "${OLD_PWD}" || exit From e90e29626677c72fdbb47b7437cdffd98fc3b7ac Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 9 Apr 2019 22:46:03 +0200 Subject: [PATCH 1055/1332] Release 4.10.9 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 7f0b4131..dc6164f3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.9: 2019-04-09 * Type __ssh_authorized_keys: Properly handle multiple --option params (Steven Armstrong) * Debugging: Add debug dump helper script (Darko Poljak) * Type __file: Bugfix: fire onchange for present and exists states if no attribute is changed (Darko Poljak) From 0ce96f0860971898d2956b4d73aa2c54253890c9 Mon Sep 17 00:00:00 2001 From: Mark Polyakov Date: Mon, 1 Apr 2019 16:24:08 -0700 Subject: [PATCH 1056/1332] Added __ufw and __ufw_rule. --- cdist/conf/type/__ufw/gencode-remote | 62 +++++++++++++++++ cdist/conf/type/__ufw/man.rst | 59 ++++++++++++++++ cdist/conf/type/__ufw/manifest | 67 +++++++++++++++++++ cdist/conf/type/__ufw/parameter/default/state | 1 + cdist/conf/type/__ufw/parameter/optional | 5 ++ cdist/conf/type/__ufw/singleton | 0 cdist/conf/type/__ufw_rule/gencode-remote | 45 +++++++++++++ cdist/conf/type/__ufw_rule/man.rst | 53 +++++++++++++++ .../type/__ufw_rule/parameter/default/state | 1 + cdist/conf/type/__ufw_rule/parameter/optional | 2 + 10 files changed, 295 insertions(+) create mode 100644 cdist/conf/type/__ufw/gencode-remote create mode 100644 cdist/conf/type/__ufw/man.rst create mode 100755 cdist/conf/type/__ufw/manifest create mode 100644 cdist/conf/type/__ufw/parameter/default/state create mode 100644 cdist/conf/type/__ufw/parameter/optional create mode 100644 cdist/conf/type/__ufw/singleton create mode 100755 cdist/conf/type/__ufw_rule/gencode-remote create mode 100644 cdist/conf/type/__ufw_rule/man.rst create mode 100644 cdist/conf/type/__ufw_rule/parameter/default/state create mode 100644 cdist/conf/type/__ufw_rule/parameter/optional diff --git a/cdist/conf/type/__ufw/gencode-remote b/cdist/conf/type/__ufw/gencode-remote new file mode 100644 index 00000000..fc62b591 --- /dev/null +++ b/cdist/conf/type/__ufw/gencode-remote @@ -0,0 +1,62 @@ +#!/bin/sh -e +# +# 2019 Mark Polyakov (mark--@--markasoftware.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 . +# + +state="$(cat "$__object/parameter/state")" + +case "$state" in + enabled) + echo 'ufw --force enable' + ;; + + present) + echo 'ufw --force disable' + ;; + # absent will be uninstalled in manifest +esac + +if [ "$state" != absent ]; then + if [ -f "$__object/parameter/logging" ]; then + logging="$(cat "$__object/parameter/logging")" + case "$logging" in + off|low|medium|high|full) + echo "ufw --force logging $logging" + ;; + *) + echo 'Logging parameter must be off, low, medium, high, or full!' >&2 + exit 1 + ;; + esac + fi + + for direction in incoming outgoing routed; do + if [ -f "$__object/parameter/default_$direction" ]; then + treatment="$(cat "$__object/parameter/default_$direction")" + case "$treatment" in + allow|deny|reject) + echo "ufw --force default $treatment $direction" + ;; + *) + echo 'UFW default policies must be either "allow", "deny", or "reject".' >&2 + exit 1 + ;; + esac + fi + done +fi diff --git a/cdist/conf/type/__ufw/man.rst b/cdist/conf/type/__ufw/man.rst new file mode 100644 index 00000000..cc64fbb5 --- /dev/null +++ b/cdist/conf/type/__ufw/man.rst @@ -0,0 +1,59 @@ +cdist-type__ufw(7) +================== + +NAME +---- +cdist-type__ufw - Install the Uncomplicated FireWall + + +DESCRIPTION +----------- +Installs the Uncomplicated FireWall. Most modern distributions carry UFW in their main repositories, but on CentOS this type will automatically enable the EPEL repository. + +Some global configuration can also be set with this type. + +OPTIONAL PARAMETERS +------------------- +state + Either "enabled", "running", "present", or "absent". Defaults to "enabled", which registers UFW to start on boot. + +logging + Either "off", "low", "medium", "high", or "full". Will be passed to `ufw logging`. If not specified, logging level is not modified. + +default_incoming + Either "allow", "deny", or "reject". The default policy for dealing with ingress packets. + +default_outgoing + Either "allow", "deny", or "reject". The default policy for dealing with egress packets. + +default_routed + Either "allow", "deny", or "reject". The default policy for dealing with routed packets (passing through this machine). + + +EXAMPLES +-------- + +.. code-block:: sh + + # Install UFW + __ufw + # Setup UFW with maximum logging and no restrictions on routed packets. + __ufw --logging full --default_routed allow + + +SEE ALSO +-------- +:strong:`ufw`\ (8) + + +AUTHORS +------- +Mark Polyakov + + +COPYING +------- +Copyright \(C) 2019 Mark Polyakov. 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/__ufw/manifest b/cdist/conf/type/__ufw/manifest new file mode 100755 index 00000000..54309ff5 --- /dev/null +++ b/cdist/conf/type/__ufw/manifest @@ -0,0 +1,67 @@ +#!/bin/sh -e +# +# 2019 Mark Polyakov (mark--@--markasoftware.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 . +# + +state="$(cat "$__object/parameter/state")" + +case "$state" in + present|enabled) + os="$(cat "$__global/explorer/os")" + + case "$os" in + centos) + # shellcheck source=/dev/null + if (. "$__global/explorer/os_release" && [ "${VERSION_ID}" = "7" ]); then + __package epel-release + require='__package/epel-release' __package ufw + else + echo 'CentOS version 7 is required!' + exit 1 + fi + ;; + *) + __package ufw + ;; + esac + + # ufw expects to always be enabled, then uses a switch in /etc to + # determine whether to "actually start" after the init system calls it. + # So, we have to both enable on bootup through init and run `ufw enable` + + # operators ae left-associative, so if !enabled it will never run + if [ "$(cat "$__global/explorer/os")" != ubuntu ] || \ + [ "$(cat "$__global/explorer/init")" != init ] && \ + [ "$state" = enabled ]; then + # Why don't we disable start_on_boot when state=present|absent? + # Because UFW should always be enabled at boot -- /etc/ufw/ufw.conf + # will stop it from "really" starting + require='__package/ufw' __start_on_boot ufw + fi + ;; + + absent) + __package ufw --state absent + ;; + + *) + echo 'State must be "enabled", "present", or "absent".' + exit 1 + ;; +esac + diff --git a/cdist/conf/type/__ufw/parameter/default/state b/cdist/conf/type/__ufw/parameter/default/state new file mode 100644 index 00000000..26ed6c9b --- /dev/null +++ b/cdist/conf/type/__ufw/parameter/default/state @@ -0,0 +1 @@ +enabled \ No newline at end of file diff --git a/cdist/conf/type/__ufw/parameter/optional b/cdist/conf/type/__ufw/parameter/optional new file mode 100644 index 00000000..0a4dec97 --- /dev/null +++ b/cdist/conf/type/__ufw/parameter/optional @@ -0,0 +1,5 @@ +state +logging +default_incoming +default_outgoing +default_routed \ No newline at end of file diff --git a/cdist/conf/type/__ufw/singleton b/cdist/conf/type/__ufw/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__ufw_rule/gencode-remote b/cdist/conf/type/__ufw_rule/gencode-remote new file mode 100755 index 00000000..4f1bf2c9 --- /dev/null +++ b/cdist/conf/type/__ufw_rule/gencode-remote @@ -0,0 +1,45 @@ +#!/bin/sh -e +# +# 2019 Mark Polyakov (mark@markasoftware.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 . +# + +# This type does not bother with checking the current state of the rules. +# While it is possible to retrieve the list of rules in a consistent format from +# `ufw status`, it is a completely different format than the one used on the +# command line. I also do not suspect it is any faster. + +ufw='ufw --force rule' + +case "$(cat "$__object/parameter/state")" in + present) ;; + absent) + ufw="$ufw delete" + ;; + *) + echo 'State must be "present" or "absent".' >&2 + exit 1 + ;; +esac + +if [ -f "$__object/parameter/rule" ]; then + ufw="$ufw $(cat "$__object/parameter/rule")" +else + ufw="$ufw allow $__object_id" +fi + +echo "$ufw" diff --git a/cdist/conf/type/__ufw_rule/man.rst b/cdist/conf/type/__ufw_rule/man.rst new file mode 100644 index 00000000..996557f8 --- /dev/null +++ b/cdist/conf/type/__ufw_rule/man.rst @@ -0,0 +1,53 @@ +cdist-type__ufw_rule(7) +======================= + +NAME +---- +cdist-type__ufw_rule - A single UFW rule + + +DESCRIPTION +----------- +Adds or removes a single UFW rule. This type supports adding and deleting rules for port ranges or applications. + +Understanding what is "to" and what is "from" can be confusing. If the rule is ingress (default), then "from" is the remote machine and "to" is the local one. The opposite is true for egress traffic (--out). + +OPTIONAL PARAMETERS +------------------- +state + Either "present" or "absent". Defaults to "present". If "absent", only removes rules that exactly match the rule expected. + +rule + A firewall rule in UFW syntax. This is what you would usually write after `ufw` on the command line. Defaults to "allow" followed by the object ID. You can use either the short syntax (just allow|deny|reject|limit followed by a port or application name) or the full syntax. Do not include `delete` in your command. Set `--state absent` instead. + +EXAMPLES +-------- + +.. code-block:: sh + + # open port 80 (ufw allow 80) + __ufw_rule 80 + # Allow mosh application (if installed) + __ufw_rule mosh + # Allow all traffic from local network (ufw allow from 10.0.0.0/24) + __ufw_rule local --rule 'allow from 10.0.0.0/24' + # Block egress traffic from port 25 to 111.55.55.55 on interface eth0 + __ufw_rule block_smtp --rule 'deny out on eth0 from any port 25 to 111.55.55.55' + + +SEE ALSO +-------- +:strong:`ufw`\ (8) + + +AUTHORS +------- +Mark Polyakov + + +COPYING +------- +Copyright \(C) 2019 Mark Polyakov. 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/__ufw_rule/parameter/default/state b/cdist/conf/type/__ufw_rule/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__ufw_rule/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__ufw_rule/parameter/optional b/cdist/conf/type/__ufw_rule/parameter/optional new file mode 100644 index 00000000..0732d53d --- /dev/null +++ b/cdist/conf/type/__ufw_rule/parameter/optional @@ -0,0 +1,2 @@ +state +rule From 13671c666c5ace5a1401ebdf1edb402981e9b9ce Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 11 Apr 2019 08:20:52 +0200 Subject: [PATCH 1057/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index dc6164f3..40606fb9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * New types: __ufw and __ufw_rule (Mark Polyakov) + 4.10.9: 2019-04-09 * Type __ssh_authorized_keys: Properly handle multiple --option params (Steven Armstrong) * Debugging: Add debug dump helper script (Darko Poljak) From 204a572709054986bc574bf7bf455513cb7bc671 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Thu, 11 Apr 2019 13:59:15 +0300 Subject: [PATCH 1058/1332] __link: add messaging --- cdist/conf/type/__link/gencode-remote | 4 ++++ cdist/conf/type/__link/man.rst | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index dc7f3193..45c22fcc 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -48,21 +48,25 @@ case "$state_should" in if [ "$file_type" = "directory" ]; then # our destination is currently a directory, delete it printf 'rm -rf "%s" &&\n' "$destination" + echo "removed '$destination' (directory)" >> "$__messages_out" else if [ "$state_is" = "wrongsource" ]; then # our destination is a symlink but points to the wrong source, # delete it printf 'rm -f "%s" &&\n' "$destination" + echo "removed '$destination' (wrongsource)" >> "$__messages_out" fi fi # create our link printf 'ln %s -f "%s" "%s"\n' "$lnopt" "$source" "$destination" + echo "created '$destination'" >> "$__messages_out" ;; absent) # only delete if it is a sym/hard link if [ "$file_type" = "symlink" ] || [ "$file_type" = "hardlink" ]; then printf 'rm -f "%s"\n' "$destination" + echo "removed '$destination'" >> "$__messages_out" fi ;; *) diff --git a/cdist/conf/type/__link/man.rst b/cdist/conf/type/__link/man.rst index 9dc4665f..fe0ce425 100644 --- a/cdist/conf/type/__link/man.rst +++ b/cdist/conf/type/__link/man.rst @@ -27,6 +27,22 @@ state 'present' or 'absent', defaults to 'present' +MESSAGES +-------- + +created + Link to destination was created. + +removed + Link to destination was removed. + +removed (directory) + Destination was removed because state is ``present`` and destination was directory. + +removed (wrongsource) + Destination was removed because state is ``present`` and destination link source was wrong. + + EXAMPLES -------- From 540434557dedd51248c7d444ca0fd869bd6a2002 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 11 Apr 2019 13:43:13 +0200 Subject: [PATCH 1059/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 40606fb9..830d49e0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Type __link: Add messaging (Ander Punnar) * New types: __ufw and __ufw_rule (Mark Polyakov) 4.10.9: 2019-04-09 From d11ac7dda40b10424a765f4aaff7f54821244382 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 11 Apr 2019 13:52:33 +0200 Subject: [PATCH 1060/1332] Rename debug-dump.sh to cdist-dump --- Makefile | 2 +- docs/changelog | 1 + docs/src/cdist-troubleshooting.rst | 4 ++-- scripts/{debug-dump.sh => cdist-dump} | 0 setup.py | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) rename scripts/{debug-dump.sh => cdist-dump} (100%) diff --git a/Makefile b/Makefile index 4ed97c7b..5f03997a 100644 --- a/Makefile +++ b/Makefile @@ -275,7 +275,7 @@ shellcheck-remote-gencodes: @find cdist/conf/type -type f -name gencode-remote -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 shellcheck-scripts: - @$(SHELLCHECKCMD) scripts/debug-dump.sh || exit 0 + @$(SHELLCHECKCMD) scripts/cdist-dump || exit 0 shellcheck-gencodes: shellcheck-local-gencodes shellcheck-remote-gencodes diff --git a/docs/changelog b/docs/changelog index 830d49e0..c06715b7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,6 +2,7 @@ Changelog --------- next: + * Debugging: Rename debug-dump.sh to cdist-dump(Darko Poljak) * Type __link: Add messaging (Ander Punnar) * New types: __ufw and __ufw_rule (Mark Polyakov) diff --git a/docs/src/cdist-troubleshooting.rst b/docs/src/cdist-troubleshooting.rst index b76f3859..6b7fb4af 100644 --- a/docs/src/cdist-troubleshooting.rst +++ b/docs/src/cdist-troubleshooting.rst @@ -53,11 +53,11 @@ For more info see: .. code-block:: sh - debug-dump.sh -h + cdist-dump -h Or from cdist git cloned directory: .. code-block:: sh - ./scripts/debug-dump.sh -h + ./scripts/cdist-dump -h diff --git a/scripts/debug-dump.sh b/scripts/cdist-dump similarity index 100% rename from scripts/debug-dump.sh rename to scripts/cdist-dump diff --git a/setup.py b/setup.py index 767f5bf7..d76bbd4b 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ setup( name="cdist", packages=["cdist", "cdist.core", "cdist.exec", "cdist.util", ], package_data={'cdist': package_data}, - scripts=["scripts/cdist", "scripts/debug-dump.sh"], + scripts=["scripts/cdist", "scripts/cdist-dump"], version=cdist.version.VERSION, description="A Usable Configuration Management System", author="Nico Schottelius", From 7a68df48f185006ec2a9536b272c92e61fa9b692 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 11 Apr 2019 14:10:18 +0200 Subject: [PATCH 1061/1332] Add missing delimiter argument --- scripts/cdist-dump | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/cdist-dump b/scripts/cdist-dump index ac1190b7..83b09eb8 100755 --- a/scripts/cdist-dump +++ b/scripts/cdist-dump @@ -50,7 +50,7 @@ Options -a dump all -C CACHE-DIR use specified CACHE-DIR (default: ~/.cdist/cache) -c dump code-* - -d delimiter used for filename and line number prefix (default: ':') + -d DELIMITER delimiter used for filename and line number prefix (default: ':') -E dump global explorers -e dump type explorers -F disable filename prefix (enabled by default) From 2ec553b4803095ff05a9cb8f79fdb9c245813a4f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 11 Apr 2019 14:30:23 +0200 Subject: [PATCH 1062/1332] Add cdist-dump man page --- docs/changelog | 5 +- docs/src/index.rst | 1 + docs/src/man1/cdist-dump.rst | 110 +++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 docs/src/man1/cdist-dump.rst diff --git a/docs/changelog b/docs/changelog index c06715b7..e670ef49 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,9 +2,10 @@ Changelog --------- next: - * Debugging: Rename debug-dump.sh to cdist-dump(Darko Poljak) - * Type __link: Add messaging (Ander Punnar) * New types: __ufw and __ufw_rule (Mark Polyakov) + * Type __link: Add messaging (Ander Punnar) + * Debugging: Rename debug-dump.sh to cdist-dump (Darko Poljak) + * Documentation: Add cdist-dump man page (Darko Poljak) 4.10.9: 2019-04-09 * Type __ssh_authorized_keys: Properly handle multiple --option params (Steven Armstrong) diff --git a/docs/src/index.rst b/docs/src/index.rst index bef91e1c..af303f5b 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -18,6 +18,7 @@ Contents: cdist-quickstart cdist-real-world man1/cdist + man1/cdist-dump cdist-bootstrap cdist-configuration cdist-manifest diff --git a/docs/src/man1/cdist-dump.rst b/docs/src/man1/cdist-dump.rst new file mode 100644 index 00000000..907cd192 --- /dev/null +++ b/docs/src/man1/cdist-dump.rst @@ -0,0 +1,110 @@ +cdist-dump(1) +============= + +NAME +---- +cdist-dump - Dump data from local cdist cache + + +SYNOPSIS +-------- + +:: + + cdist-dump [options] [host...] + + + +DESCRIPTION +----------- +cdist-dump is a helper script that dumps data from local cdist cache for +specified hosts. If host is not specified then all data from cache directory +is dumped. Default cache directory is '~/.cdist/cache'. + +cdist-dump can be used for debugging existing types, host configuration and +new types. + + +OPTIONS +------- +**-a** + dump all + +**-C CACHE-DIR** + use specified CACHE-DIR (default: ~/.cdist/cache) + +**-c** + dump code-* + +**-d DELIMITER** + delimiter used for filename and line number prefix (default: ':') + +**-E** + dump global explorers + +**-e** + dump type explorers + +**-F** + disable filename prefix (enabled by default) + +**-f** + enable filename prefix (default) + +**-g** + dump gencode-* + +**-h** + show this help screen and exit + +**-L** + disable line number prefix (default) + +**-l** + enable line number prefix (disabled by default) + +**-m** + dump messages + +**-o** + dump executions' stdout + +**-p** + dump parameters + +**-r** + dump executions' stderr + +**-V** + show version and exit + +**-v** + increase verbosity + + +EXAMPLES +-------- + +.. code-block:: sh + + # Dump all + % cdist-dump -a + + # Dump only code-* output + % cdist-dump -c + + +SEE ALSO +-------- +:strong:`cdist`\ (1) + + +AUTHORS +------- +Darko Poljak + + +COPYING +------- +Copyright \(C) 2019 Darko Poljak. Free use of this software is +granted under the terms of the GNU General Public License v3 or later (GPLv3+). From a4ed9e4d0ebccdcaac05cd4f6328b56dd1633ffc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 11 Apr 2019 14:46:56 +0200 Subject: [PATCH 1063/1332] Release 4.10.10 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index e670ef49..67851747 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.10: 2019-04-11 * New types: __ufw and __ufw_rule (Mark Polyakov) * Type __link: Add messaging (Ander Punnar) * Debugging: Rename debug-dump.sh to cdist-dump (Darko Poljak) From 279aada5db4b01f8937dcf193012981cbe0b3aa5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Apr 2019 09:13:25 +0200 Subject: [PATCH 1064/1332] Fix broken quiet mode Resolves #754 --- cdist/exec/remote.py | 1 + docs/changelog | 3 +++ 2 files changed, 4 insertions(+) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 9e3e279e..e0ef66ec 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -304,6 +304,7 @@ class Remote(object): try: if self.quiet_mode: stderr = subprocess.DEVNULL + close_stderr = False if return_output: output = subprocess.check_output(command, env=os_environ, stderr=stderr).decode() diff --git a/docs/changelog b/docs/changelog index 67851747..fccf2583 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Fix broken quiet mode (Darko Poljak) + 4.10.10: 2019-04-11 * New types: __ufw and __ufw_rule (Mark Polyakov) * Type __link: Add messaging (Ander Punnar) From 20a16fe8539842e9931a9180d93dda6996631d60 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Apr 2019 19:58:43 +0200 Subject: [PATCH 1065/1332] Add version.py into generated raw source archive Resolves #751 --- bin/build-helper | 9 +++++++-- bin/build-helper.freebsd | 9 +++++++-- docs/changelog | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 2179a5ed..de4ced71 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -195,9 +195,14 @@ eof then archivename="$3" else - archivename="cdist-${tag}.tar.gz" + archivename="cdist-${tag}.tar" git archive --prefix="cdist-${tag}/" -o "${archivename}" "${tag}" \ || exit 1 + # make sure target version is generated + "$0" target-version + tar -r -f "${archivename}" cdist/version.py || exit 1 + gzip "${archivename}" || exit 1 + archivename="${archivename}.gz" fi gpg --armor --detach-sign "${archivename}" || exit 1 @@ -232,7 +237,7 @@ eof || exit 1 # remove generated files (archive and asc) - if [ $# -eq 2] + if [ $# -eq 2 ] then rm -f "${archivename}" fi diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index a2b8dde7..2c5a54a7 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -230,9 +230,14 @@ eof then archivename="$3" else - archivename="cdist-${tag}.tar.gz" + archivename="cdist-${tag}.tar" git archive --prefix="cdist-${tag}/" -o "${archivename}" "${tag}" \ || exit 1 + # make sure target version is generated + "$0" target-version + tar -r -f "${archivename}" cdist/version.py || exit 1 + gzip "${archivename}" || exit 1 + archivename="${archivename}.gz" fi gpg --armor --detach-sign "${archivename}" || exit 1 @@ -267,7 +272,7 @@ eof || exit 1 # remove generated files (archive and asc) - if [ $# -eq 2] + if [ $# -eq 2 ] then rm -f "${archivename}" fi diff --git a/docs/changelog b/docs/changelog index fccf2583..3bb5f03d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Core: Fix broken quiet mode (Darko Poljak) + * Build: Add version.py into generated raw source archive (Darko Poljak) 4.10.10: 2019-04-11 * New types: __ufw and __ufw_rule (Mark Polyakov) From 1c152f0acbf2f7531fd4c129b04a1658654aa05e Mon Sep 17 00:00:00 2001 From: Ander Punnar <4ND3R@users.noreply.github.com> Date: Fri, 12 Apr 2019 21:41:05 +0300 Subject: [PATCH 1066/1332] fix disks explorer (#753) * fix disks explorer * fix SC2230 * exclude floppies * update comment about excluded floppies * add link to linux documentation about device majors * try to support netbsd * update possible netbsd disk devices --- cdist/conf/explorer/disks | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks index 1780e6d2..405a273a 100755 --- a/cdist/conf/explorer/disks +++ b/cdist/conf/explorer/disks @@ -1,16 +1,30 @@ #!/bin/sh -e -os=$("$__explorer/os") -case "$os" in - openbsd) - IFS=',' disks=$(sysctl -n hw.disknames) - for d in $disks; do - echo "${d%%:*}" - done | sed -n '/^[sw]d[0-9][0-9]*/p' - ;; +os="$( "$__explorer/os" )" +case "$os" in + freebsd) + sysctl -n kern.disks + ;; + openbsd) + sysctl -n hw.disknames | grep -Eo '[sw]d[0-9]+' | xargs + ;; + netbsd) + sysctl -n hw.disknames | grep -Eo '[lsw]d[0-9]' | xargs + ;; *) - cd /dev || exit 0 - echo sd? hd? vd? + # hopefully everything else is linux + if command -v lsblk > /dev/null + then + # exclude ram disks, floppies and cdroms + # https://www.kernel.org/doc/Documentation/admin-guide/devices.txt + lsblk -e 1,2,11 -dno name | xargs + else + # fallback + find /dev \ + -type b \ + -regex '/dev/\(hd\|sd\|vd\)[a-z]+' \ + -printf '%f ' + fi ;; esac From 4c8037764a3dd6b19548c4fbab8bcb9979bf65fd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 12 Apr 2019 20:41:11 +0200 Subject: [PATCH 1067/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 3bb5f03d..7a89dd75 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Core: Fix broken quiet mode (Darko Poljak) * Build: Add version.py into generated raw source archive (Darko Poljak) + * Explorer disks: Fix detecting disks, fix/add support for BSDs (Ander Punnar) 4.10.10: 2019-04-11 * New types: __ufw and __ufw_rule (Mark Polyakov) From 44c9d09383ca8b3d9fc54fe6574e6fde65e30d83 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 12 Apr 2019 16:03:38 +0300 Subject: [PATCH 1068/1332] fix __(file|directory)/explorer/stat for BSDs --- cdist/conf/type/__directory/explorer/stat | 16 ++++------------ cdist/conf/type/__file/explorer/stat | 16 +++------------- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat index 41bc8b04..3d150a21 100755 --- a/cdist/conf/type/__directory/explorer/stat +++ b/cdist/conf/type/__directory/explorer/stat @@ -25,21 +25,13 @@ destination="/$__object_id" os=$("$__explorer/os") case "$os" in - "freebsd"|"netbsd"|"openbsd") - # FIXME: should be something like this based on man page, but can not test - stat -f "type: %ST + "freebsd"|"netbsd"|"openbsd"|"macosx") + stat -f "type: %HT owner: %Du %Su group: %Dg %Sg -mode: %Op %Sp -" "$destination" +mode: %Lp %Sp +" "$destination" | awk '/^type/ { print tolower($0); next; } { print; }' ;; - "macosx") - stat -f "type: %HT - owner: %Du %Su - group: %Dg %Sg - mode: %Lp %Sp - " "$destination" - ;; *) stat --printf="type: %F owner: %u %U diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat index 8a917556..fec0d6f3 100755 --- a/cdist/conf/type/__file/explorer/stat +++ b/cdist/conf/type/__file/explorer/stat @@ -25,24 +25,14 @@ destination="/$__object_id" os=$("$__explorer/os") case "$os" in - "freebsd"|"netbsd"|"openbsd") - # FIXME: should be something like this based on man page, but can not test - stat -f "type: %ST -owner: %Du %Su -group: %Dg %Sg -mode: %Op %Sp -size: %Dz -links: %Dl -" "$destination" - ;; - "macosx") - stat -f "type: %HT + "freebsd"|"netbsd"|"openbsd"|"macosx") + stat -f "type: %HT owner: %Du %Su group: %Dg %Sg mode: %Lp %Sp size: %Dz links: %Dl -" "$destination" +" "$destination" | awk '/^type/ { print tolower($0); next; } { print; }' ;; *) stat --printf="type: %F From 4d9a8d78f7cac887e8589e05aba511941db85117 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 13 Apr 2019 19:50:44 +0200 Subject: [PATCH 1069/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 7a89dd75..202fa00c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,8 @@ next: * Core: Fix broken quiet mode (Darko Poljak) * Build: Add version.py into generated raw source archive (Darko Poljak) * Explorer disks: Fix detecting disks, fix/add support for BSDs (Ander Punnar) + * Type __file: Fix stat explorer for BSDs (Ander Punnar) + * Type __directory: Fix stat explorer for BSDs (Ander Punnar) 4.10.10: 2019-04-11 * New types: __ufw and __ufw_rule (Mark Polyakov) From b37b25f57332aaf9fd91b09503a3e88cf213a6fc Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 13 Apr 2019 19:53:54 +0200 Subject: [PATCH 1070/1332] Release 4.10.11 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 202fa00c..84c59d98 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.10.11: 2019-04-13 * Core: Fix broken quiet mode (Darko Poljak) * Build: Add version.py into generated raw source archive (Darko Poljak) * Explorer disks: Fix detecting disks, fix/add support for BSDs (Ander Punnar) From 51e650423e1075d3a49816c31a6fefee5896517b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 13 Apr 2019 20:43:11 +0200 Subject: [PATCH 1071/1332] Fix version.py location inside raw source archive Note that this fix only matters for maintainers using build-helper script. Source archive is generated during release process and uploaded to github, along its signature. For 4.10.11 those files were fixed and uploaded manually after build-helper script process has been finished. In future releases this process will be automatic - no need for manual step that was necessary for 4.10.11. --- bin/build-helper | 5 ++++- bin/build-helper.freebsd | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index de4ced71..963f02f9 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -200,7 +200,10 @@ eof || exit 1 # make sure target version is generated "$0" target-version - tar -r -f "${archivename}" cdist/version.py || exit 1 + tar -x -f "${archivename}" || exit 1 + cp cdist/version.py "cdist-${tag}/cdist/version.py" || exit 1 + tar -c -f "${archivename}" "cdist-${tag}/" || exit 1 + rm -r -f "cdist-${tag}/" gzip "${archivename}" || exit 1 archivename="${archivename}.gz" fi diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 2c5a54a7..58d985a6 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -235,7 +235,10 @@ eof || exit 1 # make sure target version is generated "$0" target-version - tar -r -f "${archivename}" cdist/version.py || exit 1 + tar -x -f "${archivename}" || exit 1 + cp cdist/version.py "cdist-${tag}/cdist/version.py" || exit 1 + tar -c -f "${archivename}" "cdist-${tag}/" || exit 1 + rm -r -f "cdist-${tag}/" gzip "${archivename}" || exit 1 archivename="${archivename}.gz" fi From d18584b4ffd29e295042b0498953ba622adccfd0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 13 Apr 2019 20:54:59 +0200 Subject: [PATCH 1072/1332] Update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 320d150d..460bbf28 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ _build/ docs/dist # Ignore temp files used for signing +cdist-*.tar cdist-*.tar.gz cdist-*.tar.gz.asc From 797522f91eb3e9d928ae26d2e1b78eeb0f02f467 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 14 Apr 2019 16:54:59 +0200 Subject: [PATCH 1073/1332] Fix circular dep for CDIST_ORDER_DEPENDENCY Fixes #756 --- cdist/emulator.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 65d044d7..5103f1a4 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -283,7 +283,8 @@ class Emulator(object): self.object_source))) raise - self.log.debug("Recording requirement: %s", requirement) + self.log.debug("Recording requirement %s for %s", + requirement, self.cdist_object.name) # Save the sanitised version, not the user supplied one # (__file//bar => __file/bar) @@ -305,13 +306,26 @@ class Emulator(object): # get the type created before this one ... try: lastcreatedtype = typecreationorder[-2].strip() - if 'require' in self.env: - self.env['require'] += " " + lastcreatedtype + # __object_name is the name of the object whose type + # manifest is currently executed + __object_name = self.env.get('__object_name', None) + if lastcreatedtype == __object_name: + self.log.debug(("Not injecting require for " + "CDIST_ORDER_DEPENDENCY: %s for %s," + " %s's type manifest is currently" + " being executed"), + lastcreatedtype, + self.cdist_object.name, + lastcreatedtype) else: - self.env['require'] = lastcreatedtype - self.log.debug(("Injecting require for " - "CDIST_ORDER_DEPENDENCY: %s for %s"), - lastcreatedtype, self.cdist_object.name) + if 'require' in self.env: + self.env['require'] += " " + lastcreatedtype + else: + self.env['require'] = lastcreatedtype + self.log.debug(("Injecting require for " + "CDIST_ORDER_DEPENDENCY: %s for %s"), + lastcreatedtype, + self.cdist_object.name) except IndexError: # if no second last line, we are on the first type, # so do not set a requirement @@ -360,4 +374,6 @@ class Emulator(object): # But only if the user hasn't said otherwise. # Must prevent circular dependencies. if parent.name not in current_object.requirements: + self.log.debug("Recording autorequirement %s for %s", + current_object.name, parent.name) parent.autorequire.append(current_object.name) From 3a2041019b5e878a0c81ef78dd719d10db48a6f6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 16:11:58 +0200 Subject: [PATCH 1074/1332] [alpine] add support for alpine in __package and __package_apk --- cdist/conf/type/__package/manifest | 2 + cdist/conf/type/__package_apk/explorer/state | 36 ++++++++++++ cdist/conf/type/__package_apk/gencode-remote | 49 +++++++++++++++++ cdist/conf/type/__package_apk/man.rst | 55 +++++++++++++++++++ cdist/conf/type/__package_apk/nonparallel | 0 .../__package_apk/parameter/default/state | 1 + .../type/__package_apk/parameter/optional | 2 + 7 files changed, 145 insertions(+) create mode 100755 cdist/conf/type/__package_apk/explorer/state create mode 100755 cdist/conf/type/__package_apk/gencode-remote create mode 100644 cdist/conf/type/__package_apk/man.rst create mode 100644 cdist/conf/type/__package_apk/nonparallel create mode 100644 cdist/conf/type/__package_apk/parameter/default/state create mode 100644 cdist/conf/type/__package_apk/parameter/optional diff --git a/cdist/conf/type/__package/manifest b/cdist/conf/type/__package/manifest index f9de1145..a453c32b 100755 --- a/cdist/conf/type/__package/manifest +++ b/cdist/conf/type/__package/manifest @@ -1,6 +1,7 @@ #!/bin/sh -e # # 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) +# 2019 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -44,6 +45,7 @@ else suse) type="zypper" ;; openwrt) type="opkg" ;; openbsd) type="pkg_openbsd" ;; + alpine) type="apk" ;; *) echo "Don't know how to manage packages on: $os" >&2 exit 1 diff --git a/cdist/conf/type/__package_apk/explorer/state b/cdist/conf/type/__package_apk/explorer/state new file mode 100755 index 00000000..3fc405a2 --- /dev/null +++ b/cdist/conf/type/__package_apk/explorer/state @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2019 Nico Schottelius (nico-cdist at schottelius.org) +# +# 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 . +# +# +# Retrieve the status of a package - parsed dpkg output +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +output= + +if [ "$(apk list -I "$name")" ]; then + echo present +else + echo absent +fi diff --git a/cdist/conf/type/__package_apk/gencode-remote b/cdist/conf/type/__package_apk/gencode-remote new file mode 100755 index 00000000..79e3d2b6 --- /dev/null +++ b/cdist/conf/type/__package_apk/gencode-remote @@ -0,0 +1,49 @@ +#!/bin/sh -e +# +# 2019 Nico Schottelius (nico-cdist at schottelius.org) +# +# 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 . +# +# +# Manage packages on Debian and co. +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +state_should="$(cat "$__object/parameter/state")" +state_is="$(cat "$__object/explorer/state")" + +# Nothing to be done +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + echo "apk add -q '$name'" + echo "installed" >> "$__messages_out" + ;; + absent) + echo "apk del -q '$name'" + echo "removed" >> "$__messages_out" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__package_apk/man.rst b/cdist/conf/type/__package_apk/man.rst new file mode 100644 index 00000000..bc2408b4 --- /dev/null +++ b/cdist/conf/type/__package_apk/man.rst @@ -0,0 +1,55 @@ +cdist-type__package_akp(7) +========================== + +NAME +---- +cdist-type__package_akp - Manage packages with akp + + +DESCRIPTION +----------- +apk is usually used on Alpine to manage packages. + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +name + If supplied, use the name and not the object id as the package name. + +state + Either "present" or "absent", defaults to "present" + + +EXAMPLES +-------- + +.. code-block:: sh + + # Ensure zsh in installed + __package_apk zsh --state present + + # Remove package + __package_apk apache2 --state absent + + +SEE ALSO +-------- +:strong:`cdist-type__package`\ (7) + + +AUTHORS +------- +Nico Schottelius + + +COPYING +------- +Copyright \(C) 2019 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. diff --git a/cdist/conf/type/__package_apk/nonparallel b/cdist/conf/type/__package_apk/nonparallel new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__package_apk/parameter/default/state b/cdist/conf/type/__package_apk/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__package_apk/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__package_apk/parameter/optional b/cdist/conf/type/__package_apk/parameter/optional new file mode 100644 index 00000000..1b423dc4 --- /dev/null +++ b/cdist/conf/type/__package_apk/parameter/optional @@ -0,0 +1,2 @@ +name +state From c17f5a7ccde307a16db60224722401a58a69c8c9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 16:13:25 +0200 Subject: [PATCH 1075/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 7a89dd75..536b99e6 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,8 @@ next: * Core: Fix broken quiet mode (Darko Poljak) * Build: Add version.py into generated raw source archive (Darko Poljak) * Explorer disks: Fix detecting disks, fix/add support for BSDs (Ander Punnar) + * Type __package: Add __package_apk support (Nico Schottelius) + * New type: __package_apk (Nico Schottelius) 4.10.10: 2019-04-11 * New types: __ufw and __ufw_rule (Mark Polyakov) From e32d92c109ac64c9b8b3f48cea007b67ebc3c5c5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 16:32:54 +0200 Subject: [PATCH 1076/1332] [__start_on_boot] Begin to add alpine support --- cdist/conf/type/__start_on_boot/explorer/state | 5 ++++- cdist/conf/type/__start_on_boot/man.rst | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 19dfc74b..75764979 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012-2015 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2019 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. @@ -88,6 +88,9 @@ else # OpenBSD 5.7 and higher rcctl ls on | grep "^${name}$" && state='present' ;; + alpine) + state="absent" + rc-update show | sed 's/ *//' | grep -q "^${name} |" && state="present" *) echo "Unsupported os: $os" >&2 exit 1 diff --git a/cdist/conf/type/__start_on_boot/man.rst b/cdist/conf/type/__start_on_boot/man.rst index 851d1a89..b7c73ab1 100644 --- a/cdist/conf/type/__start_on_boot/man.rst +++ b/cdist/conf/type/__start_on_boot/man.rst @@ -55,7 +55,7 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2012 Nico Schottelius. You can redistribute it +Copyright \(C) 2012-2019 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. From 707426d1f0c513c86019f1e7c7d866fa026619ff Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 16:35:10 +0200 Subject: [PATCH 1077/1332] [__start_on_boot] add code for alpine handling, fix explorer --- cdist/conf/type/__start_on_boot/gencode-remote | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 1a3b6ff6..56f0dbdb 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -40,6 +40,9 @@ case "$state_should" in echo "systemctl -q enable '$name'" else case "$os" in + alpine) + echo "rc-update -q add '${name}'" + ;; debian) case "$os_version" in [1-7]*) @@ -102,6 +105,9 @@ case "$state_should" in else case "$os" in + alpine) + echo "rc-update -q del '${name}'" + ;; debian|ubuntu|devuan) echo "update-rc.d -f '$name' remove" ;; From dbf29c18c124f4c9b9026180819ec2cfba6c1e16 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 16:41:27 +0200 Subject: [PATCH 1078/1332] [__start_on_boot] alpine fix --- cdist/conf/type/__start_on_boot/explorer/state | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 75764979..37f41806 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -89,8 +89,10 @@ else rcctl ls on | grep "^${name}$" && state='present' ;; alpine) - state="absent" - rc-update show | sed 's/ *//' | grep -q "^${name} |" && state="present" + state="$(rc-update show | sed 's/ *//' | grep -q "^${name} |" && echo present)" + [ "$state" ] || state="absent" + ;; + *) echo "Unsupported os: $os" >&2 exit 1 From ec935353d75a3bfde5f37862668ba18ab0d63181 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 17:02:09 +0200 Subject: [PATCH 1079/1332] [__start_on_boot] Merge alpine and gentoo, update gentoo --- cdist/conf/type/__start_on_boot/explorer/state | 15 ++++++++------- cdist/conf/type/__start_on_boot/gencode-remote | 10 ++-------- docs/changelog | 1 + 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 37f41806..b7a6cf0f 100644 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -75,9 +75,14 @@ else state=$(chkconfig --check "$name" "$runlevel" || echo absent) [ "$state" ] || state="present" ;; - gentoo) - state="present" - [ -f "/etc/runlevels/${target_runlevel}/${name}" ] || state="absent" + gentoo|alpine) + state="absent" + for d in /etc/runlevels/*; do + if [ -f "/etc/runlevels/${d}/${name}" ];then + state="present" + break + fi + done ;; freebsd) state="absent" @@ -88,10 +93,6 @@ else # OpenBSD 5.7 and higher rcctl ls on | grep "^${name}$" && state='present' ;; - alpine) - state="$(rc-update show | sed 's/ *//' | grep -q "^${name} |" && echo present)" - [ "$state" ] || state="absent" - ;; *) echo "Unsupported os: $os" >&2 diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 56f0dbdb..c900933f 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -40,9 +40,6 @@ case "$state_should" in echo "systemctl -q enable '$name'" else case "$os" in - alpine) - echo "rc-update -q add '${name}'" - ;; debian) case "$os_version" in [1-7]*) @@ -61,7 +58,7 @@ case "$state_should" in echo "update-rc.d '$name' defaults >/dev/null" ;; - gentoo) + alpine|gentoo) echo "rc-update add '$name' '$target_runlevel'" ;; @@ -105,14 +102,11 @@ case "$state_should" in else case "$os" in - alpine) - echo "rc-update -q del '${name}'" - ;; debian|ubuntu|devuan) echo "update-rc.d -f '$name' remove" ;; - gentoo) + alpine|gentoo) echo "rc-update del '$name' '$target_runlevel'" ;; diff --git a/docs/changelog b/docs/changelog index da503525..ab239357 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Type __package: Add __package_apk support (Nico Schottelius) + * Type __start_on_boot: Add alpine support (Nico Schottelius) * New type: __package_apk (Nico Schottelius) 4.10.11: 2019-04-13 From 978aee668ca12be97043026206457847d411ceda Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 17:03:12 +0200 Subject: [PATCH 1080/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ab239357..84507ac4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __package: Add __package_apk support (Nico Schottelius) * Type __start_on_boot: Add alpine support (Nico Schottelius) + * Type __start_on_boot: gentoo: check all runlevels in explorer (Nico Schottelius) * New type: __package_apk (Nico Schottelius) 4.10.11: 2019-04-13 From 45e9ed441e6271982702e5c0eb25022142c1177a Mon Sep 17 00:00:00 2001 From: Dimitrios Apostolou Date: Mon, 15 Apr 2019 13:04:07 +0200 Subject: [PATCH 1081/1332] Add support for ACL mask. --- cdist/conf/type/__acl/explorer/acl_is | 5 ++++- cdist/conf/type/__acl/gencode-remote | 13 ++++++++++++- cdist/conf/type/__acl/man.rst | 9 ++++++++- cdist/conf/type/__acl/parameter/optional | 1 + 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 cdist/conf/type/__acl/parameter/optional diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index 4dc98c51..fbb1be3f 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -19,5 +19,8 @@ # if [ -e "/$__object_id" ] -then getfacl "/$__object_id" | grep -E '^((default:|)(user|group)):[a-z]' || true +then + getfacl "/$__object_id" \ + | grep -E '^((default:)?(user|group):[^:]|(default:)?mask::)' \ + || true fi diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index a59d49e0..1c1a1b06 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -37,7 +37,18 @@ do then echo "default:$parameter:$l" fi done < "$__object/parameter/$parameter" -done )" +done +if [ -f "$__object/parameter/mask" ] +then + l=$( cat "$__object/parameter/mask" ) + + echo "mask::$l" + + if [ -f "$__object/parameter/default" ] + then echo "default:mask::$l" + fi +fi +)" setfacl_exec='setfacl' diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst index 39db4d75..c10ee1a0 100644 --- a/cdist/conf/type/__acl/man.rst +++ b/cdist/conf/type/__acl/man.rst @@ -13,6 +13,12 @@ ACL must be defined as 3-symbol combination, using `r`, `w`, `x` and `-`. See setfacl(1) and acl(5) for more details. +OPTIONAL PARAMETERS +------------------- +mask + Add mask ACL entry. + + OPTIONAL MULTIPLE PARAMETERS ---------------------------- user @@ -46,7 +52,8 @@ EXAMPLES --user alice:rwx \ --user bob:r-x \ --group project-group:rwx \ - --group some-other-group:r-x + --group some-other-group:r-x \ + --mask r-x AUTHORS diff --git a/cdist/conf/type/__acl/parameter/optional b/cdist/conf/type/__acl/parameter/optional new file mode 100644 index 00000000..bb4fcf2b --- /dev/null +++ b/cdist/conf/type/__acl/parameter/optional @@ -0,0 +1 @@ +mask From 6062e3557c3e359320c386c356405dd98fbdd5f6 Mon Sep 17 00:00:00 2001 From: Dimitrios Apostolou Date: Mon, 15 Apr 2019 16:32:11 +0200 Subject: [PATCH 1082/1332] Output of grep should be quiet, as we care only for the exit code. --- cdist/conf/type/__acl/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 1c1a1b06..8ab7b566 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -54,7 +54,7 @@ setfacl_exec='setfacl' if [ -f "$__object/parameter/recursive" ] then - if echo "$os" | grep -E 'macosx|netbsd|freebsd|openbsd' + if echo "$os" | grep -Eq 'macosx|netbsd|freebsd|openbsd' then echo "$os setfacl do not support recursive operations" >&2 else @@ -64,7 +64,7 @@ fi if [ -f "$__object/parameter/remove" ] then - if echo "$os" | grep 'solaris' + if echo "$os" | grep -Fq 'solaris' then # Solaris setfacl behaves differently. # We will not support Solaris for now, because no way to test it. From c801fb4965b6aa7726c5b20cd3db3b02712759b2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 18:44:30 +0200 Subject: [PATCH 1083/1332] [timezone] + alpine support --- cdist/conf/type/__timezone/gencode-remote | 3 ++- cdist/conf/type/__timezone/manifest | 4 ++-- docs/changelog | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__timezone/gencode-remote b/cdist/conf/type/__timezone/gencode-remote index 1f3f0196..5299f548 100755 --- a/cdist/conf/type/__timezone/gencode-remote +++ b/cdist/conf/type/__timezone/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh -e # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2019 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -29,7 +30,7 @@ if [ "$timezone_is" = "$timezone_should" ]; then fi case "$os" in - ubuntu|debian|devuan|coreos) + ubuntu|debian|devuan|coreos|alpine) echo "echo \"$timezone_should\" > /etc/timezone" ;; esac diff --git a/cdist/conf/type/__timezone/manifest b/cdist/conf/type/__timezone/manifest index c908f087..3d28ccba 100755 --- a/cdist/conf/type/__timezone/manifest +++ b/cdist/conf/type/__timezone/manifest @@ -2,7 +2,7 @@ # # 2011 Ramon Salvadó (rsalvado at gnuine dot com) # 2012-2015 Steven Armstrong (steven-cdist at armstrong.cc) -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2019 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -26,7 +26,7 @@ timezone="$__object_id" os=$(cat "$__global/explorer/os") case "$os" in - archlinux|debian|ubuntu|devuan) + archlinux|debian|ubuntu|devuan|alpine) __package tzdata export require="__package/tzdata" ;; diff --git a/docs/changelog b/docs/changelog index 84507ac4..2df98118 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __package: Add __package_apk support (Nico Schottelius) * Type __start_on_boot: Add alpine support (Nico Schottelius) + * Type __timezone: Add alpine support (Nico Schottelius) * Type __start_on_boot: gentoo: check all runlevels in explorer (Nico Schottelius) * New type: __package_apk (Nico Schottelius) From f4db6e908efa8b3c79cc6a5f937a148c4d886341 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 18:48:49 +0200 Subject: [PATCH 1084/1332] [hostname] add alpine support --- cdist/conf/type/__hostname/gencode-remote | 4 ++-- cdist/conf/type/__hostname/manifest | 2 +- docs/changelog | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 33947f7f..8b5797dd 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -35,7 +35,7 @@ has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") # If everything is ok -> exit # case "$os" in - archlinux|debian|suse|ubuntu|devuan|coreos) + archlinux|debian|suse|ubuntu|devuan|coreos|alpine) if [ "$name_config" = "$name_should" ] && [ "$name_running" = "$name_should" ]; then exit 0 fi @@ -58,7 +58,7 @@ echo changed >> "$__messages_out" # Use the good old way to set the hostname even on machines running systemd. case "$os" in - archlinux|debian|ubuntu|devuan|centos|coreos) + archlinux|debian|ubuntu|devuan|centos|coreos|alpine) printf "printf '%%s\\\\n' '$name_should' > /etc/hostname\\n" echo "hostname -F /etc/hostname" ;; diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index c03b2eac..8f1adf12 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -41,7 +41,7 @@ not_supported() { } case "$os" in - archlinux|debian|suse|ubuntu|devuan|coreos) + archlinux|debian|suse|ubuntu|devuan|coreos|alpine) # handled in gencode-remote : ;; diff --git a/docs/changelog b/docs/changelog index 2df98118..55800f25 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __package: Add __package_apk support (Nico Schottelius) * Type __start_on_boot: Add alpine support (Nico Schottelius) * Type __timezone: Add alpine support (Nico Schottelius) + * Type __hostname: Add alpine support (Nico Schottelius) * Type __start_on_boot: gentoo: check all runlevels in explorer (Nico Schottelius) * New type: __package_apk (Nico Schottelius) From e290733a00dbf2e6f743f8fce8318b5518f523a1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 18:54:30 +0200 Subject: [PATCH 1085/1332] [locale] Add alpine support --- cdist/conf/type/__locale/gencode-remote | 2 +- cdist/conf/type/__locale/man.rst | 5 +++-- cdist/conf/type/__locale/manifest | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__locale/gencode-remote b/cdist/conf/type/__locale/gencode-remote index 04e48712..db939a2a 100755 --- a/cdist/conf/type/__locale/gencode-remote +++ b/cdist/conf/type/__locale/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh -e # -# 2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013-2019 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # diff --git a/cdist/conf/type/__locale/man.rst b/cdist/conf/type/__locale/man.rst index 60a4eacc..e36ab061 100644 --- a/cdist/conf/type/__locale/man.rst +++ b/cdist/conf/type/__locale/man.rst @@ -8,7 +8,8 @@ cdist-type__locale - Configure locales DESCRIPTION ----------- -This cdist type allows you to setup locales. +This cdist type allows you to setup locales. On systems that don't +support locale setting like alpine/musl libc, it is a no-op. OPTIONAL PARAMETERS @@ -44,6 +45,6 @@ Nico Schottelius COPYING ------- -Copyright \(C) 2013-2016 Nico Schottelius. Free use of this software is +Copyright \(C) 2013-2019 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 or later (GPLv3+). diff --git a/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest index cacd0b42..9f1e17ac 100755 --- a/cdist/conf/type/__locale/manifest +++ b/cdist/conf/type/__locale/manifest @@ -1,6 +1,6 @@ #!/bin/sh -e # -# 2013-2015 Nico Schottelius (nico-cdist at schottelius.org) +# 2013-2019 Nico Schottelius (nico-cdist at schottelius.org) # 2015 David Hürlimann (david at ungleich.ch) # # This file is part of cdist. @@ -19,7 +19,7 @@ # along with cdist. If not, see . # # -# Install required packages +# Install required packages # os=$(cat "$__global/explorer/os") @@ -30,7 +30,7 @@ case "$os" in # Debian needs a seperate package __package locales --state present ;; - archlinux|suse|ubuntu|scientific|centos) + archlinux|suse|ubuntu|scientific|centos|alpine) : ;; *) From a1cb9ee869f3eea117a2cfb8c16903eac5690e5c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 18:56:51 +0200 Subject: [PATCH 1086/1332] [locale/alpine] exit 0 in gencode-remote --- cdist/conf/type/__locale/gencode-remote | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cdist/conf/type/__locale/gencode-remote b/cdist/conf/type/__locale/gencode-remote index db939a2a..1feb9884 100755 --- a/cdist/conf/type/__locale/gencode-remote +++ b/cdist/conf/type/__locale/gencode-remote @@ -37,6 +37,15 @@ locale_remove=$(echo "$locale" | sed 's/UTF-8/utf8/') state=$(cat "$__object/parameter/state") +os=$(cat "$__global/explorer/os") + +# Nothing to be done on alpine +case "$os" in + alpine) + exit 0 + ;; +esac + case "$state" in present) echo localedef -A "$alias" -f "$charmap" -i "$input" "$locale" From 1722fced721e7e61f0b1b3748a3f253502e62574 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 19:13:44 +0200 Subject: [PATCH 1087/1332] [file] add alpine support --- cdist/conf/type/__file/explorer/stat | 15 +++++++++++++-- docs/changelog | 4 +++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat index fec0d6f3..a0f35dcc 100755 --- a/cdist/conf/type/__file/explorer/stat +++ b/cdist/conf/type/__file/explorer/stat @@ -1,6 +1,7 @@ #!/bin/sh # # 2013 Steven Armstrong (steven-cdist armstrong.cc) +# 2019 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -33,7 +34,17 @@ mode: %Lp %Sp size: %Dz links: %Dl " "$destination" | awk '/^type/ { print tolower($0); next; } { print; }' - ;; + ;; + alpine) + # busybox stat + stat -c "type: %F +owner: %u %U +group: %g %G +mode: %a %A +size: %s +links: %h +" "$destination" + ;; *) stat --printf="type: %F owner: %u %U @@ -42,5 +53,5 @@ mode: %a %A size: %s links: %h " "$destination" - ;; + ;; esac diff --git a/docs/changelog b/docs/changelog index 55800f25..a6ad0749 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,9 +3,11 @@ Changelog next: * Type __package: Add __package_apk support (Nico Schottelius) + * Type __file: Add alpine support (Nico Schottelius) + * Type __hostname: Add alpine support (Nico Schottelius) + * Type __locale: Add alpine support (Nico Schottelius) * Type __start_on_boot: Add alpine support (Nico Schottelius) * Type __timezone: Add alpine support (Nico Schottelius) - * Type __hostname: Add alpine support (Nico Schottelius) * Type __start_on_boot: gentoo: check all runlevels in explorer (Nico Schottelius) * New type: __package_apk (Nico Schottelius) From 63d7499b755a22319a5e0e85ecf1dea7f1225b57 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 15 Apr 2019 19:27:42 +0200 Subject: [PATCH 1088/1332] [directory] add alpine support --- cdist/conf/type/__directory/explorer/stat | 11 +++++++++-- docs/changelog | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat index 3d150a21..db3c149a 100755 --- a/cdist/conf/type/__directory/explorer/stat +++ b/cdist/conf/type/__directory/explorer/stat @@ -31,9 +31,16 @@ owner: %Du %Su group: %Dg %Sg mode: %Lp %Sp " "$destination" | awk '/^type/ { print tolower($0); next; } { print; }' - ;; + ;; + alpine) + stat -c "type: %F +owner: %u %U +group: %g %G +mode: %a %A +" "$destination" + ;; *) - stat --printf="type: %F + stat --printf="type: %F owner: %u %U group: %g %G mode: %a %A diff --git a/docs/changelog b/docs/changelog index a6ad0749..ab824681 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Type __package: Add __package_apk support (Nico Schottelius) + * Type __directory: Add alpine support (Nico Schottelius) * Type __file: Add alpine support (Nico Schottelius) * Type __hostname: Add alpine support (Nico Schottelius) * Type __locale: Add alpine support (Nico Schottelius) From 437af3a0a381a70ae85b9784a25e24a1794a9e1c Mon Sep 17 00:00:00 2001 From: Dimitrios Apostolou Date: Mon, 15 Apr 2019 20:51:02 +0200 Subject: [PATCH 1089/1332] Silence getfacl otherwise it always prints the message: getfacl: Removing leading '/' from absolute path names --- cdist/conf/type/__acl/explorer/acl_is | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index fbb1be3f..e2ae0932 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -20,7 +20,7 @@ if [ -e "/$__object_id" ] then - getfacl "/$__object_id" \ + getfacl "/$__object_id" 2>/dev/null \ | grep -E '^((default:)?(user|group):[^:]|(default:)?mask::)' \ || true fi From e997e98a730a97e224bf8f445adb95b8aea161d2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 16 Apr 2019 11:02:51 +0200 Subject: [PATCH 1090/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ab824681..eaa11449 100644 --- a/docs/changelog +++ b/docs/changelog @@ -11,6 +11,7 @@ next: * Type __timezone: Add alpine support (Nico Schottelius) * Type __start_on_boot: gentoo: check all runlevels in explorer (Nico Schottelius) * New type: __package_apk (Nico Schottelius) + * Type __acl: Add support for ACL mask (Dimitrios Apostolou) 4.10.11: 2019-04-13 * Core: Fix broken quiet mode (Darko Poljak) From 2cde09648cc9be18a1d857d994c270ca2e1b52c2 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 14:15:48 +0300 Subject: [PATCH 1091/1332] __acl: check if getfacl is available --- cdist/conf/type/__acl/explorer/acl_is | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index e2ae0932..bb1db89d 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -18,6 +18,12 @@ # along with cdist. If not, see . # +if ! command -v getfacl 2>/dev/null +then + echo 'getfacl not available' >&2 + exit 1 +fi + if [ -e "/$__object_id" ] then getfacl "/$__object_id" 2>/dev/null \ From d71eb3d8bdbd46848bc9c53b2523be050b083410 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 14:20:13 +0300 Subject: [PATCH 1092/1332] __acl: (open|net)bsd do not have (get|set)facl --- cdist/conf/type/__acl/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 8ab7b566..2ea01524 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -54,7 +54,7 @@ setfacl_exec='setfacl' if [ -f "$__object/parameter/recursive" ] then - if echo "$os" | grep -Eq 'macosx|netbsd|freebsd|openbsd' + if echo "$os" | grep -Eq 'macosx|freebsd' then echo "$os setfacl do not support recursive operations" >&2 else From ef8ff06b5f20a73c744769aecc047ff7c05e5fbb Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 14:39:45 +0300 Subject: [PATCH 1093/1332] __acl: only directories can have default ACLs --- cdist/conf/type/__acl/explorer/file_type | 28 ++++++++++++++++++++++++ cdist/conf/type/__acl/gencode-remote | 8 +++++-- 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100755 cdist/conf/type/__acl/explorer/file_type diff --git a/cdist/conf/type/__acl/explorer/file_type b/cdist/conf/type/__acl/explorer/file_type new file mode 100755 index 00000000..0d1edb7d --- /dev/null +++ b/cdist/conf/type/__acl/explorer/file_type @@ -0,0 +1,28 @@ +#!/bin/sh -e +# +# 2018 Ander Punnar (ander-at-kvlt-dot-ee) +# +# 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 [ -e "/$__object_id" ] +then + if [ -d "/$__object_id" ] + then echo d + elif [ -f "/$__object_id" ] + then echo f + fi +fi diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 2ea01524..355cc88e 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -20,6 +20,8 @@ os="$( cat "$__global/explorer/os" )" +file_type="$( cat "$__object/explorer/file_type" )" + acl_path="/$__object_id" acl_is="$( cat "$__object/explorer/acl_is" )" @@ -33,7 +35,8 @@ do do echo "$parameter:$l" - if [ -f "$__object/parameter/default" ] + if [ -f "$__object/parameter/default" ] \ + && [ "$file_type" = 'd' ] then echo "default:$parameter:$l" fi done < "$__object/parameter/$parameter" @@ -44,7 +47,8 @@ then echo "mask::$l" - if [ -f "$__object/parameter/default" ] + if [ -f "$__object/parameter/default" ] \ + && [ "$file_type" = 'd' ] then echo "default:mask::$l" fi fi From ab954ffbcf285d3d83b7e61070468afc8cab1610 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 14:44:32 +0300 Subject: [PATCH 1094/1332] __acl: always check first if path exists --- cdist/conf/type/__acl/explorer/acl_is | 13 +++++++------ cdist/conf/type/__acl/explorer/file_type | 15 ++++++++------- cdist/conf/type/__acl/gencode-remote | 6 ++++-- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index bb1db89d..c5d8468d 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -18,15 +18,16 @@ # along with cdist. If not, see . # +acl_path="/$__object_id" + +[ ! -e "$acl_path" ] && exit 0 + if ! command -v getfacl 2>/dev/null then echo 'getfacl not available' >&2 exit 1 fi -if [ -e "/$__object_id" ] -then - getfacl "/$__object_id" 2>/dev/null \ - | grep -E '^((default:)?(user|group):[^:]|(default:)?mask::)' \ - || true -fi +getfacl "$acl_path" 2>/dev/null \ + | grep -E '^((default:)?(user|group):[^:]|(default:)?mask::)' \ + || true diff --git a/cdist/conf/type/__acl/explorer/file_type b/cdist/conf/type/__acl/explorer/file_type index 0d1edb7d..f45e302b 100755 --- a/cdist/conf/type/__acl/explorer/file_type +++ b/cdist/conf/type/__acl/explorer/file_type @@ -18,11 +18,12 @@ # along with cdist. If not, see . # -if [ -e "/$__object_id" ] -then - if [ -d "/$__object_id" ] - then echo d - elif [ -f "/$__object_id" ] - then echo f - fi +acl_path="/$__object_id" + +[ ! -e "$acl_path" ] && exit 0 + +if [ -d "$acl_path" ] +then echo d +elif [ -f "$acl_path" ] +then echo f fi diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 355cc88e..88fc8ce0 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -18,12 +18,14 @@ # along with cdist. If not, see . # +acl_path="/$__object_id" + +[ ! -e "$acl_path" ] && exit 0 + os="$( cat "$__global/explorer/os" )" file_type="$( cat "$__object/explorer/file_type" )" -acl_path="/$__object_id" - acl_is="$( cat "$__object/explorer/acl_is" )" acl_should="$( for parameter in user group From 2b5887bdbd3229d75da48e32dc7e55b29b6abd54 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 14:51:26 +0300 Subject: [PATCH 1095/1332] __acl: we only care whether file is directory --- cdist/conf/type/__acl/explorer/{file_type => is_dir} | 5 ++--- cdist/conf/type/__acl/gencode-remote | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) rename cdist/conf/type/__acl/explorer/{file_type => is_dir} (94%) diff --git a/cdist/conf/type/__acl/explorer/file_type b/cdist/conf/type/__acl/explorer/is_dir similarity index 94% rename from cdist/conf/type/__acl/explorer/file_type rename to cdist/conf/type/__acl/explorer/is_dir index f45e302b..d3080de6 100755 --- a/cdist/conf/type/__acl/explorer/file_type +++ b/cdist/conf/type/__acl/explorer/is_dir @@ -23,7 +23,6 @@ acl_path="/$__object_id" [ ! -e "$acl_path" ] && exit 0 if [ -d "$acl_path" ] -then echo d -elif [ -f "$acl_path" ] -then echo f +then echo 1 +else echo 0 fi diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 88fc8ce0..a50174fa 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -24,7 +24,7 @@ acl_path="/$__object_id" os="$( cat "$__global/explorer/os" )" -file_type="$( cat "$__object/explorer/file_type" )" +is_dir="$( cat "$__object/explorer/is_dir" )" acl_is="$( cat "$__object/explorer/acl_is" )" @@ -38,7 +38,7 @@ do echo "$parameter:$l" if [ -f "$__object/parameter/default" ] \ - && [ "$file_type" = 'd' ] + && [ "$is_dir" = '1' ] then echo "default:$parameter:$l" fi done < "$__object/parameter/$parameter" @@ -50,7 +50,7 @@ then echo "mask::$l" if [ -f "$__object/parameter/default" ] \ - && [ "$file_type" = 'd' ] + && [ "$is_dir" = '1' ] then echo "default:mask::$l" fi fi From 9e3cd47b9afa0a13276ca5967d689773111f6990 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 15:03:07 +0300 Subject: [PATCH 1096/1332] __acl: command -v stdout to devnull --- cdist/conf/type/__acl/explorer/acl_is | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index c5d8468d..f75f4003 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -22,7 +22,7 @@ acl_path="/$__object_id" [ ! -e "$acl_path" ] && exit 0 -if ! command -v getfacl 2>/dev/null +if ! command -v getfacl > /dev/null then echo 'getfacl not available' >&2 exit 1 From 731986ef8b417cdc0284ffd3b43c66a9bd851f55 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 15:21:41 +0300 Subject: [PATCH 1097/1332] __acl: trying to understand X --- cdist/conf/type/__acl/gencode-remote | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index a50174fa..651bfce0 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -35,6 +35,16 @@ do fi while read -r l do + if echo "$l" | grep -Fq 'X' + then + if [ "$is_dir" = '1' ] + then + l="$( echo "$l" | sed 's/X/x/' )" + else + l="$( echo "$l" | sed 's/X/-/' )" + fi + fi + echo "$parameter:$l" if [ -f "$__object/parameter/default" ] \ From cea639d1c901de298818c303202b9332d0f20d1a Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 15:27:47 +0300 Subject: [PATCH 1098/1332] __acl: we can't remove mask --- cdist/conf/type/__acl/gencode-remote | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 651bfce0..47e39e0a 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -89,7 +89,8 @@ then else echo "$acl_is" | while read -r acl do - if echo "$acl_should" | grep -Fq "$acl" + if echo "$acl_should" | grep -Fq "$acl" \ + || echo "$acl" | grep -Eq '^(default:)?mask' then continue fi From 8b9b2c56ab534d619148e497b2e1342128168d21 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 15:28:25 +0300 Subject: [PATCH 1099/1332] __acl: be more strict because of reasons --- cdist/conf/type/__acl/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 47e39e0a..a989f95f 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -89,7 +89,7 @@ then else echo "$acl_is" | while read -r acl do - if echo "$acl_should" | grep -Fq "$acl" \ + if echo "$acl_should" | grep -Eq "^$acl" \ || echo "$acl" | grep -Eq '^(default:)?mask' then continue fi From 53c963b2eec3eab529bece57cdc25cd00b5557d3 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 15:35:11 +0300 Subject: [PATCH 1100/1332] __acl: be bit more precise where the X is --- cdist/conf/type/__acl/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index a989f95f..7003c26f 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -39,9 +39,9 @@ do then if [ "$is_dir" = '1' ] then - l="$( echo "$l" | sed 's/X/x/' )" + l="$( echo "$l" | sed 's/X$/x/' )" else - l="$( echo "$l" | sed 's/X/-/' )" + l="$( echo "$l" | sed 's/X$/-/' )" fi fi From e04d647d8e9f1450cdb461b3af4aa14f1d589e24 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 18:09:47 +0300 Subject: [PATCH 1101/1332] __acl: fix always check first if path exists --- cdist/conf/type/__acl/explorer/acl_is | 6 ++---- cdist/conf/type/__acl/explorer/file_exists | 24 ++++++++++++++++++++++ cdist/conf/type/__acl/explorer/is_dir | 6 ++---- cdist/conf/type/__acl/gencode-remote | 6 +++--- 4 files changed, 31 insertions(+), 11 deletions(-) create mode 100755 cdist/conf/type/__acl/explorer/file_exists diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index f75f4003..89da89f1 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -18,9 +18,7 @@ # along with cdist. If not, see . # -acl_path="/$__object_id" - -[ ! -e "$acl_path" ] && exit 0 +[ ! -e "/$__object_id" ] && exit 0 if ! command -v getfacl > /dev/null then @@ -28,6 +26,6 @@ then exit 1 fi -getfacl "$acl_path" 2>/dev/null \ +getfacl "/$__object_id" 2>/dev/null \ | grep -E '^((default:)?(user|group):[^:]|(default:)?mask::)' \ || true diff --git a/cdist/conf/type/__acl/explorer/file_exists b/cdist/conf/type/__acl/explorer/file_exists new file mode 100755 index 00000000..998d407c --- /dev/null +++ b/cdist/conf/type/__acl/explorer/file_exists @@ -0,0 +1,24 @@ +#!/bin/sh -e +# +# 2018 Ander Punnar (ander-at-kvlt-dot-ee) +# +# 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 [ -e "/$__object_id" ] +then echo 1 +else echo 0 +fi diff --git a/cdist/conf/type/__acl/explorer/is_dir b/cdist/conf/type/__acl/explorer/is_dir index d3080de6..7c4e2538 100755 --- a/cdist/conf/type/__acl/explorer/is_dir +++ b/cdist/conf/type/__acl/explorer/is_dir @@ -18,11 +18,9 @@ # along with cdist. If not, see . # -acl_path="/$__object_id" +[ ! -e "/$__object_id" ] && exit 0 -[ ! -e "$acl_path" ] && exit 0 - -if [ -d "$acl_path" ] +if [ -d "/$__object_id" ] then echo 1 else echo 0 fi diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 7003c26f..91fb7117 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -18,9 +18,7 @@ # along with cdist. If not, see . # -acl_path="/$__object_id" - -[ ! -e "$acl_path" ] && exit 0 +[ "$( cat "$__object/explorer/file_exists" )" = '0' ] && exit 0 os="$( cat "$__global/explorer/os" )" @@ -28,6 +26,8 @@ is_dir="$( cat "$__object/explorer/is_dir" )" acl_is="$( cat "$__object/explorer/acl_is" )" +acl_path="/$__object_id" + acl_should="$( for parameter in user group do if [ ! -f "$__object/parameter/$parameter" ] From c1a34caba7c39d3f27f7dd6ba249046e04a83e1c Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 19:06:48 +0300 Subject: [PATCH 1102/1332] __acl: add "other" ACL entry support and some comments, remove getfacl's inline comments --- cdist/conf/type/__acl/explorer/acl_is | 5 +++-- cdist/conf/type/__acl/gencode-remote | 21 +++++++++++++++++++-- cdist/conf/type/__acl/man.rst | 6 +++++- cdist/conf/type/__acl/parameter/optional | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index 89da89f1..70e18116 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -26,6 +26,7 @@ then exit 1 fi -getfacl "/$__object_id" 2>/dev/null \ - | grep -E '^((default:)?(user|group):[^:]|(default:)?mask::)' \ +getfacl -E "/$__object_id" 2>/dev/null \ + | grep -E '^(default:)?(user|group|(mask|other):):[^:]' \ + | sed -r 's/#.+$//' \ || true diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 91fb7117..ce88afc4 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -28,7 +28,8 @@ acl_is="$( cat "$__object/explorer/acl_is" )" acl_path="/$__object_id" -acl_should="$( for parameter in user group +acl_should="$( +for parameter in user group do if [ ! -f "$__object/parameter/$parameter" ] then continue @@ -53,6 +54,7 @@ do fi done < "$__object/parameter/$parameter" done + if [ -f "$__object/parameter/mask" ] then l=$( cat "$__object/parameter/mask" ) @@ -64,6 +66,18 @@ then then echo "default:mask::$l" fi fi + +if [ -f "$__object/parameter/other" ] +then + l=$( cat "$__object/parameter/other" ) + + echo "other::$l" + + if [ -f "$__object/parameter/default" ] \ + && [ "$is_dir" = '1' ] + then echo "default:other::$l" + fi +fi )" setfacl_exec='setfacl' @@ -89,8 +103,11 @@ then else echo "$acl_is" | while read -r acl do + # Skip wanted ACL entries which already exist + # and skip mask and other entries, because we + # can't actually remove them, but only change. if echo "$acl_should" | grep -Eq "^$acl" \ - || echo "$acl" | grep -Eq '^(default:)?mask' + || echo "$acl" | grep -Eq '^(default:)?(mask|other)' then continue fi diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst index c10ee1a0..40c3ead4 100644 --- a/cdist/conf/type/__acl/man.rst +++ b/cdist/conf/type/__acl/man.rst @@ -18,6 +18,9 @@ OPTIONAL PARAMETERS mask Add mask ACL entry. +other + Add other ACL entry. + OPTIONAL MULTIPLE PARAMETERS ---------------------------- @@ -53,7 +56,8 @@ EXAMPLES --user bob:r-x \ --group project-group:rwx \ --group some-other-group:r-x \ - --mask r-x + --mask r-x \ + --other r-x AUTHORS diff --git a/cdist/conf/type/__acl/parameter/optional b/cdist/conf/type/__acl/parameter/optional index bb4fcf2b..4b32086b 100644 --- a/cdist/conf/type/__acl/parameter/optional +++ b/cdist/conf/type/__acl/parameter/optional @@ -1 +1,2 @@ mask +other From a1634b3ec0d8797cff33be88bf9e1487532ed12a Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 19:24:38 +0300 Subject: [PATCH 1103/1332] __acl: optimize gencode-remote --- cdist/conf/type/__acl/gencode-remote | 57 ++++++++++------------------ 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index ce88afc4..fd763b8f 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -28,57 +28,42 @@ acl_is="$( cat "$__object/explorer/acl_is" )" acl_path="/$__object_id" -acl_should="$( -for parameter in user group +acl_should="$( for parameter in user group mask other do if [ ! -f "$__object/parameter/$parameter" ] - then continue + then + continue fi - while read -r l + + while read -r acl do - if echo "$l" | grep -Fq 'X' + if echo "$acl" | grep -Fq 'X' then if [ "$is_dir" = '1' ] then - l="$( echo "$l" | sed 's/X$/x/' )" + acl="$( echo "$acl" | sed 's/X$/x/' )" else - l="$( echo "$l" | sed 's/X$/-/' )" + acl="$( echo "$acl" | sed 's/X$/-/' )" fi fi - echo "$parameter:$l" + if echo "$parameter" | grep -Eq '(mask|other)' + then + sep=:: + else + sep=: + fi + + echo "$parameter$sep$acl" if [ -f "$__object/parameter/default" ] \ && [ "$is_dir" = '1' ] - then echo "default:$parameter:$l" + then + echo "default:$parameter$sep$acl" fi - done < "$__object/parameter/$parameter" -done - -if [ -f "$__object/parameter/mask" ] -then - l=$( cat "$__object/parameter/mask" ) - - echo "mask::$l" - - if [ -f "$__object/parameter/default" ] \ - && [ "$is_dir" = '1' ] - then echo "default:mask::$l" - fi -fi - -if [ -f "$__object/parameter/other" ] -then - l=$( cat "$__object/parameter/other" ) - - echo "other::$l" - - if [ -f "$__object/parameter/default" ] \ - && [ "$is_dir" = '1' ] - then echo "default:other::$l" - fi -fi -)" + done \ + < "$__object/parameter/$parameter" +done )" setfacl_exec='setfacl' From 8b3c84dfefc5e44fa4f5ae1daa40b87e46a5076a Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 23:15:58 +0300 Subject: [PATCH 1104/1332] __acl: remove whitespace before inline comments too --- cdist/conf/type/__acl/explorer/acl_is | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index 70e18116..1c64ffb3 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -28,5 +28,5 @@ fi getfacl -E "/$__object_id" 2>/dev/null \ | grep -E '^(default:)?(user|group|(mask|other):):[^:]' \ - | sed -r 's/#.+$//' \ + | sed -r 's/\s*#.+$//' \ || true From 7924c1339cc76bb7f8ab2c4a17cea751be7ef509 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 23:28:30 +0300 Subject: [PATCH 1105/1332] __acl: avoid duplication and safer sed for last occurence replacement --- cdist/conf/type/__acl/gencode-remote | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index fd763b8f..56c1cbc1 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -41,10 +41,12 @@ do then if [ "$is_dir" = '1' ] then - acl="$( echo "$acl" | sed 's/X$/x/' )" + rep=x else - acl="$( echo "$acl" | sed 's/X$/-/' )" + rep=- fi + + acl="$( echo "$acl" | sed -r "s/(.*)X/\1$rep/" )" fi if echo "$parameter" | grep -Eq '(mask|other)' From f23099218ab8918efde5798d15d5c025e3a0c5da Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 23:29:38 +0300 Subject: [PATCH 1106/1332] __acl: juggle man sections around because user/group are more important parameters --- cdist/conf/type/__acl/man.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst index 40c3ead4..b7e74d59 100644 --- a/cdist/conf/type/__acl/man.rst +++ b/cdist/conf/type/__acl/man.rst @@ -13,15 +13,6 @@ ACL must be defined as 3-symbol combination, using `r`, `w`, `x` and `-`. See setfacl(1) and acl(5) for more details. -OPTIONAL PARAMETERS -------------------- -mask - Add mask ACL entry. - -other - Add other ACL entry. - - OPTIONAL MULTIPLE PARAMETERS ---------------------------- user @@ -31,6 +22,15 @@ group Add group ACL entry. +OPTIONAL PARAMETERS +------------------- +mask + Add mask ACL entry. + +other + Add other ACL entry. + + BOOLEAN PARAMETERS ------------------ recursive From 68f61c35ff89971a93ebd511ab35d13b40dce690 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 16 Apr 2019 23:36:54 +0300 Subject: [PATCH 1107/1332] __acl: check for X after last occurrence of colon --- cdist/conf/type/__acl/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 56c1cbc1..96b4a57c 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -37,7 +37,7 @@ do while read -r acl do - if echo "$acl" | grep -Fq 'X' + if echo "$acl" | sed -r 's/(.*)://' | grep -Fq 'X' then if [ "$is_dir" = '1' ] then From aba1ae68f073382d7f0488b98c69af3e46b8d26a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 17 Apr 2019 20:50:39 +0200 Subject: [PATCH 1108/1332] [explorer] disks: use echo instead of find as fallback Fixes #761 --- cdist/conf/explorer/disks | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks index 405a273a..ae93efc8 100755 --- a/cdist/conf/explorer/disks +++ b/cdist/conf/explorer/disks @@ -16,15 +16,12 @@ case "$os" in # hopefully everything else is linux if command -v lsblk > /dev/null then - # exclude ram disks, floppies and cdroms + # exclude ram disks, floppies and cdroms # https://www.kernel.org/doc/Documentation/admin-guide/devices.txt lsblk -e 1,2,11 -dno name | xargs else # fallback - find /dev \ - -type b \ - -regex '/dev/\(hd\|sd\|vd\)[a-z]+' \ - -printf '%f ' + cd /dev && echo [vsh]d? fi ;; esac From 82f310f4f8116544d1817203a88eb0c65de10fa9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 19 Apr 2019 09:36:24 +0200 Subject: [PATCH 1109/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index eaa11449..d0fbb0e8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -12,6 +12,7 @@ next: * Type __start_on_boot: gentoo: check all runlevels in explorer (Nico Schottelius) * New type: __package_apk (Nico Schottelius) * Type __acl: Add support for ACL mask (Dimitrios Apostolou) + * Core: Fix circular dependency for CDIST_ORDER_DEPENDENCY (Darko Poljak) 4.10.11: 2019-04-13 * Core: Fix broken quiet mode (Darko Poljak) From f5d3196dd4f142c4b28c9641126d98cfb7eaaab7 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 11:31:38 +0300 Subject: [PATCH 1110/1332] __acl: getfacl's -E not supported on FreeBSD --- cdist/conf/type/__acl/explorer/acl_is | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index 1c64ffb3..9ca30281 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -26,7 +26,7 @@ then exit 1 fi -getfacl -E "/$__object_id" 2>/dev/null \ +getfacl "/$__object_id" 2>/dev/null \ | grep -E '^(default:)?(user|group|(mask|other):):[^:]' \ | sed -r 's/\s*#.+$//' \ || true From 0809d89836e633af8da983df3f1333ee281938dc Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 12:56:55 +0300 Subject: [PATCH 1111/1332] __acl: replace sed -r where possible or make it portable without -r --- cdist/conf/type/__acl/explorer/acl_is | 3 +-- cdist/conf/type/__acl/gencode-remote | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__acl/explorer/acl_is b/cdist/conf/type/__acl/explorer/acl_is index 9ca30281..a693c023 100755 --- a/cdist/conf/type/__acl/explorer/acl_is +++ b/cdist/conf/type/__acl/explorer/acl_is @@ -27,6 +27,5 @@ then fi getfacl "/$__object_id" 2>/dev/null \ - | grep -E '^(default:)?(user|group|(mask|other):):[^:]' \ - | sed -r 's/\s*#.+$//' \ + | grep -Eo '^(default:)?(user|group|(mask|other):):[^:][[:graph:]]+' \ || true diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 96b4a57c..08ba60ac 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -37,7 +37,7 @@ do while read -r acl do - if echo "$acl" | sed -r 's/(.*)://' | grep -Fq 'X' + if echo "$acl" | awk -F: '{ print $NF }' | grep -Fq 'X' then if [ "$is_dir" = '1' ] then @@ -46,7 +46,7 @@ do rep=- fi - acl="$( echo "$acl" | sed -r "s/(.*)X/\1$rep/" )" + acl="$( echo "$acl" | sed "s/\(.*\)X/\1$rep/" )" fi if echo "$parameter" | grep -Eq '(mask|other)' @@ -98,7 +98,7 @@ then then continue fi - no_bits="$( echo "$acl" | sed -r 's/:[rwx-]+$//' )" + no_bits="$( echo "$acl" | sed 's/:...$//' )" echo "$setfacl_exec -x \"$no_bits\" \"$acl_path\"" done From 0f3c162696c8c35afc155752f47af276c37b1acf Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 13:16:35 +0300 Subject: [PATCH 1112/1332] __acl: setting default ACL in FreeBSD and macOS is currently not supported --- cdist/conf/type/__acl/gencode-remote | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 08ba60ac..9cdcd3be 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -108,6 +108,13 @@ fi for acl in $acl_should do if ! echo "$acl_is" | grep -Eq "^$acl" - then echo "$setfacl_exec -m \"$acl\" \"$acl_path\"" + then + if echo "$os" | grep -Eq 'macosx|freebsd' \ + && echo "$acl" | grep -Eq '^default:' + then + echo "setting default ACL in $os is currently not supported. sorry :(" >&2 + else + echo "$setfacl_exec -m \"$acl\" \"$acl_path\"" + fi fi done From 86f45db1b9b5bf91ea55e5014e39b2437a06bc70 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 13:30:50 +0300 Subject: [PATCH 1113/1332] __acl: add nice oneliners and move default ACL decision out of the loop --- cdist/conf/type/__acl/gencode-remote | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 9cdcd3be..99c0f7f2 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -28,6 +28,13 @@ acl_is="$( cat "$__object/explorer/acl_is" )" acl_path="/$__object_id" +if [ -f "$__object/parameter/default" ] && [ "$is_dir" = '1' ] +then + set_default=1 +else + set_default=0 +fi + acl_should="$( for parameter in user group mask other do if [ ! -f "$__object/parameter/$parameter" ] @@ -39,30 +46,16 @@ do do if echo "$acl" | awk -F: '{ print $NF }' | grep -Fq 'X' then - if [ "$is_dir" = '1' ] - then - rep=x - else - rep=- - fi + [ "$is_dir" = '1' ] && rep=x || rep=- acl="$( echo "$acl" | sed "s/\(.*\)X/\1$rep/" )" fi - if echo "$parameter" | grep -Eq '(mask|other)' - then - sep=:: - else - sep=: - fi + echo "$parameter" | grep -Eq '(mask|other)' && sep=:: || sep=: echo "$parameter$sep$acl" - if [ -f "$__object/parameter/default" ] \ - && [ "$is_dir" = '1' ] - then - echo "default:$parameter$sep$acl" - fi + [ "$set_default" = '1' ] && echo "default:$parameter$sep$acl" done \ < "$__object/parameter/$parameter" done )" From 8729e39c215381e9bdffe6269cedfba85d0e0f85 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 13:48:24 +0300 Subject: [PATCH 1114/1332] __acl: combine two explorers into one --- .../__acl/explorer/{file_exists => file_is} | 11 ++++++-- cdist/conf/type/__acl/explorer/is_dir | 26 ------------------- cdist/conf/type/__acl/gencode-remote | 10 +++---- 3 files changed, 14 insertions(+), 33 deletions(-) rename cdist/conf/type/__acl/explorer/{file_exists => file_is} (81%) delete mode 100755 cdist/conf/type/__acl/explorer/is_dir diff --git a/cdist/conf/type/__acl/explorer/file_exists b/cdist/conf/type/__acl/explorer/file_is similarity index 81% rename from cdist/conf/type/__acl/explorer/file_exists rename to cdist/conf/type/__acl/explorer/file_is index 998d407c..096cffd1 100755 --- a/cdist/conf/type/__acl/explorer/file_exists +++ b/cdist/conf/type/__acl/explorer/file_is @@ -19,6 +19,13 @@ # if [ -e "/$__object_id" ] -then echo 1 -else echo 0 +then + if [ -d "/$__object_id" ] + then echo directory + elif [ -f "/$__object_id" ] + then echo regular + else echo other + fi +else + echo missing fi diff --git a/cdist/conf/type/__acl/explorer/is_dir b/cdist/conf/type/__acl/explorer/is_dir deleted file mode 100755 index 7c4e2538..00000000 --- a/cdist/conf/type/__acl/explorer/is_dir +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -e -# -# 2018 Ander Punnar (ander-at-kvlt-dot-ee) -# -# 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 . -# - -[ ! -e "/$__object_id" ] && exit 0 - -if [ -d "/$__object_id" ] -then echo 1 -else echo 0 -fi diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 99c0f7f2..5bb19aa8 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -18,17 +18,17 @@ # along with cdist. If not, see . # -[ "$( cat "$__object/explorer/file_exists" )" = '0' ] && exit 0 +file_is="$( cat "$__object/explorer/file_is" )" + +[ "$file_is" = 'missing' ] && exit 0 os="$( cat "$__global/explorer/os" )" -is_dir="$( cat "$__object/explorer/is_dir" )" - acl_is="$( cat "$__object/explorer/acl_is" )" acl_path="/$__object_id" -if [ -f "$__object/parameter/default" ] && [ "$is_dir" = '1' ] +if [ -f "$__object/parameter/default" ] && [ "$file_is" = 'directory' ] then set_default=1 else @@ -46,7 +46,7 @@ do do if echo "$acl" | awk -F: '{ print $NF }' | grep -Fq 'X' then - [ "$is_dir" = '1' ] && rep=x || rep=- + [ "$file_is" = 'directory' ] && rep=x || rep=- acl="$( echo "$acl" | sed "s/\(.*\)X/\1$rep/" )" fi From 13df0a2a2b8ac2724821fc72369eaf9f4ca1fe66 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 14:11:29 +0300 Subject: [PATCH 1115/1332] __acl: update man --- cdist/conf/type/__acl/man.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst index b7e74d59..bc71a0cc 100644 --- a/cdist/conf/type/__acl/man.rst +++ b/cdist/conf/type/__acl/man.rst @@ -3,14 +3,16 @@ cdist-type__acl(7) NAME ---- -cdist-type__acl - Basic wrapper around `setfacl` +cdist-type__acl - Set ACL entries DESCRIPTION ----------- -ACL must be defined as 3-symbol combination, using `r`, `w`, `x` and `-`. +ACL must be defined as 3-symbol combination, using ``r``, ``w``, ``x`` and ``-``. -See setfacl(1) and acl(5) for more details. +Fully supported on Linux, partial support for FreeBSD, OSX and Solaris. + +See ``setfacl`` and ``acl`` manpages for more details. OPTIONAL MULTIPLE PARAMETERS @@ -34,13 +36,14 @@ other BOOLEAN PARAMETERS ------------------ recursive - Operate recursively (Linux only). + Make ``setfacl`` recursive (Linux only), but not ``getfacl`` in explorer. default - Add default ACL entries. + Add default ACL entries (FreeBSD not supported). remove Remove undefined ACL entries (Solaris not supported). + ACL entries for ``mask`` and ``other`` can't be removed. EXAMPLES From 6d71ae342ad826aac73dd34d7334e7b4ef97bf41 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 14:47:16 +0300 Subject: [PATCH 1116/1332] __acl: update man more --- cdist/conf/type/__acl/man.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst index bc71a0cc..092eb555 100644 --- a/cdist/conf/type/__acl/man.rst +++ b/cdist/conf/type/__acl/man.rst @@ -10,7 +10,11 @@ DESCRIPTION ----------- ACL must be defined as 3-symbol combination, using ``r``, ``w``, ``x`` and ``-``. -Fully supported on Linux, partial support for FreeBSD, OSX and Solaris. +Fully supported on Linux (tested on Debian and CentOS). + +Partial support for FreeBSD, OSX and Solaris. + +OpenBSD and NetBSD support is not possible. See ``setfacl`` and ``acl`` manpages for more details. From 05225352aa7434ec35d2691420adb1f81923d4ec Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 14:48:26 +0300 Subject: [PATCH 1117/1332] __acl: check for missing users and groups (common mistake) --- .../type/__acl/explorer/missing_users_groups | 47 +++++++++++++++++++ cdist/conf/type/__acl/gencode-remote | 8 ++++ 2 files changed, 55 insertions(+) create mode 100755 cdist/conf/type/__acl/explorer/missing_users_groups diff --git a/cdist/conf/type/__acl/explorer/missing_users_groups b/cdist/conf/type/__acl/explorer/missing_users_groups new file mode 100755 index 00000000..883fb84d --- /dev/null +++ b/cdist/conf/type/__acl/explorer/missing_users_groups @@ -0,0 +1,47 @@ +#!/bin/sh -e +# +# 2019 Ander Punnar (ander-at-kvlt-dot-ee) +# +# 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 . +# + +[ ! -e "/$__object_id" ] && exit 0 + +for parameter in user group +do + if [ ! -f "$__object/parameter/$parameter" ] + then + continue + fi + + while read -r acl + do + check="$( echo "$acl" | awk -F: '{print $1}' )" + + if [ "$parameter" = 'user' ] + then + getent_db=passwd + else + getent_db="$parameter" + fi + + if ! getent "$getent_db" "$check" > /dev/null + then + echo "missing $parameter '$check'" + fi + done \ + < "$__object/parameter/$parameter" +done diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 5bb19aa8..3dd0aef6 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -22,6 +22,14 @@ file_is="$( cat "$__object/explorer/file_is" )" [ "$file_is" = 'missing' ] && exit 0 +missing_users_groups="$( cat "$__object/explorer/missing_users_groups" )" + +if [ -n "$missing_users_groups" ] +then + echo "$missing_users_groups" >&2 + exit 1 +fi + os="$( cat "$__global/explorer/os" )" acl_is="$( cat "$__object/explorer/acl_is" )" From c7e6109462eab6201ae4fee5bf1b9baa2d48314c Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 14:49:02 +0300 Subject: [PATCH 1118/1332] __acl: tabs vs spaces --- cdist/conf/type/__acl/explorer/missing_users_groups | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__acl/explorer/missing_users_groups b/cdist/conf/type/__acl/explorer/missing_users_groups index 883fb84d..b4af614c 100755 --- a/cdist/conf/type/__acl/explorer/missing_users_groups +++ b/cdist/conf/type/__acl/explorer/missing_users_groups @@ -29,7 +29,7 @@ do while read -r acl do - check="$( echo "$acl" | awk -F: '{print $1}' )" + check="$( echo "$acl" | awk -F: '{print $1}' )" if [ "$parameter" = 'user' ] then @@ -38,10 +38,10 @@ do getent_db="$parameter" fi - if ! getent "$getent_db" "$check" > /dev/null - then - echo "missing $parameter '$check'" - fi + if ! getent "$getent_db" "$check" > /dev/null + then + echo "missing $parameter '$check'" + fi done \ < "$__object/parameter/$parameter" done From 186ce77bb24ddb089b69a28c4c27dd1bfbbd1a71 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 14:58:44 +0300 Subject: [PATCH 1119/1332] __acl: add messaging --- cdist/conf/type/__acl/gencode-remote | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 3dd0aef6..c9583520 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -102,6 +102,7 @@ then no_bits="$( echo "$acl" | sed 's/:...$//' )" echo "$setfacl_exec -x \"$no_bits\" \"$acl_path\"" + echo "removed '$no_bits'" >> "$__messages_out" done fi fi @@ -116,6 +117,7 @@ do echo "setting default ACL in $os is currently not supported. sorry :(" >&2 else echo "$setfacl_exec -m \"$acl\" \"$acl_path\"" + echo "added '$acl'" >> "$__messages_out" fi fi done From 108e46abee03eaca789eb43393aaccf9f699bf7a Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 19 Apr 2019 15:04:18 +0300 Subject: [PATCH 1120/1332] __acl: fix removal in freebsd --- cdist/conf/type/__acl/gencode-remote | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index c9583520..a0f25a15 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -99,10 +99,15 @@ then then continue fi - no_bits="$( echo "$acl" | sed 's/:...$//' )" + if echo "$os" | grep -Eq 'macosx|freebsd' + then + remove="$acl" + else + remove="$( echo "$acl" | sed 's/:...$//' )" + fi - echo "$setfacl_exec -x \"$no_bits\" \"$acl_path\"" - echo "removed '$no_bits'" >> "$__messages_out" + echo "$setfacl_exec -x \"$remove\" \"$acl_path\"" + echo "removed '$remove'" >> "$__messages_out" done fi fi From 69fc80ec951deeddb94ff6b396175881e769c78c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 19 Apr 2019 17:50:09 +0200 Subject: [PATCH 1121/1332] ++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index d0fbb0e8..eeb91dc4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,7 @@ next: * New type: __package_apk (Nico Schottelius) * Type __acl: Add support for ACL mask (Dimitrios Apostolou) * Core: Fix circular dependency for CDIST_ORDER_DEPENDENCY (Darko Poljak) + * Type __acl: Improve the type (Ander Punnar) 4.10.11: 2019-04-13 * Core: Fix broken quiet mode (Darko Poljak) From ab3544d5e8955484c755ce3f6f3d261d6a2f8a0f Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sat, 20 Apr 2019 01:59:21 +0300 Subject: [PATCH 1122/1332] global interfaces explorer: only check if we have ip or ifconfig and be more compatible. tests on debian, centos, freebsd, openbsd, netbsd and solaris confirm that this is enough and extra os check is not needed here. --- cdist/conf/explorer/interfaces | 41 +++++++++------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/cdist/conf/explorer/interfaces b/cdist/conf/explorer/interfaces index c1f2a57a..55287971 100755 --- a/cdist/conf/explorer/interfaces +++ b/cdist/conf/explorer/interfaces @@ -1,6 +1,6 @@ -#!/bin/sh +#!/bin/sh -e # -# 2012 Sébastien Gross +# 2019 Ander Punnar (ander-at-kvlt-dot-ee) # # This file is part of cdist. # @@ -17,35 +17,14 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# List all network interfaces in explorer/ifaces. One interface per line. -# -# If your OS is not supported please provide a ifconfig output -# -# Use ip, if available -if command -v ip >/dev/null; then +if command -v ip > /dev/null +then ip -o link show | sed -n 's/^[0-9]\+: \(.\+\): <.*/\1/p' - exit 0 + +elif command -v ifconfig > /dev/null +then + ifconfig -a \ + | sed -n -E 's/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' \ + | sort -u fi - -if ! command -v ifconfig >/dev/null; then - # no ifconfig, nothing we could do - exit 0 -fi - -uname_s="$(uname -s)" -REGEXP='s/^(.*)(:[[:space:]]*flags=|Link encap).*/\1/p' - -case "$uname_s" in - Darwin) - ifconfig -a | sed -n -E "$REGEXP" - ;; - Linux|*BSD) - ifconfig -a | sed -n -r "$REGEXP" - ;; - *) - echo "Unsupported ifconfig output for $uname_s" >&2 - exit 1 - ;; -esac From 3b3ac95ac3f8cefa897f9b6a443315da7762495c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 20 Apr 2019 12:35:42 +0200 Subject: [PATCH 1123/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index eeb91dc4..c2e5b941 100644 --- a/docs/changelog +++ b/docs/changelog @@ -14,6 +14,7 @@ next: * Type __acl: Add support for ACL mask (Dimitrios Apostolou) * Core: Fix circular dependency for CDIST_ORDER_DEPENDENCY (Darko Poljak) * Type __acl: Improve the type (Ander Punnar) + * Explorer interfaces: Simplify code, be more compatible (Ander Punnar) 4.10.11: 2019-04-13 * Core: Fix broken quiet mode (Darko Poljak) From 250f3d3fb896c9f7d44ff4eddb6c9368ac221765 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 20 Apr 2019 12:40:04 +0200 Subject: [PATCH 1124/1332] shellcheck: remove unused var --- cdist/conf/type/__package_apk/explorer/state | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cdist/conf/type/__package_apk/explorer/state b/cdist/conf/type/__package_apk/explorer/state index 3fc405a2..29ccf3a5 100755 --- a/cdist/conf/type/__package_apk/explorer/state +++ b/cdist/conf/type/__package_apk/explorer/state @@ -18,7 +18,7 @@ # along with cdist. If not, see . # # -# Retrieve the status of a package - parsed dpkg output +# Retrieve the status of a package - parsed apk output # if [ -f "$__object/parameter/name" ]; then @@ -27,8 +27,6 @@ else name="$__object_id" fi -output= - if [ "$(apk list -I "$name")" ]; then echo present else From b5bdb54b7f75d5ff5d935c21730959a57509d0ec Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 19 Apr 2019 09:44:29 +0200 Subject: [PATCH 1125/1332] Currently support only Linux, FreeBSD, OpenBSD, NetBSD Make no assumptions, but rather output that system is unsupported and ask the user to add support for it. --- cdist/conf/explorer/disks | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks index ae93efc8..51660e13 100755 --- a/cdist/conf/explorer/disks +++ b/cdist/conf/explorer/disks @@ -1,27 +1,27 @@ #!/bin/sh -e -os="$( "$__explorer/os" )" +uname_s="$(uname -s)" -case "$os" in - freebsd) +case "${uname_s}" in + FreeBSD) sysctl -n kern.disks ;; - openbsd) - sysctl -n hw.disknames | grep -Eo '[sw]d[0-9]+' | xargs + OpenBSD|NetBSD) + sysctl -n hw.disknames | grep -Eo '[lsw]d[0-9]+' | xargs ;; - netbsd) - sysctl -n hw.disknames | grep -Eo '[lsw]d[0-9]' | xargs - ;; - *) - # hopefully everything else is linux + Linux) if command -v lsblk > /dev/null then # exclude ram disks, floppies and cdroms # https://www.kernel.org/doc/Documentation/admin-guide/devices.txt lsblk -e 1,2,11 -dno name | xargs else - # fallback - cd /dev && echo [vsh]d? + printf "%s operating system without lsblk is not supported, if you can please submit a patch\n" "${uname_s}" >&2 + exit 1 fi ;; + *) + printf "%s operating system is not supported, if you can please submit a patch\n" "${uname_s}" >&2 + exit 1 + ;; esac From 087066687cf96690e08863a748a0dd24eed0e7e6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 20 Apr 2019 14:26:09 +0200 Subject: [PATCH 1126/1332] Report explorer error better Fixes #766 --- cdist/__init__.py | 41 +++++++++++++++++++++++++++++++++++++++-- cdist/config.py | 9 ++++----- cdist/core/explorer.py | 30 +++++++++++++++++++++++------- 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index 000a571c..c673b3ba 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -181,17 +181,40 @@ class CdistObjectError(CdistEntityError): params, stdout_paths, stderr_paths, subject) +class CdistObjectExplorerError(CdistEntityError): + """ + Something went wrong while working on a specific + cdist object explorer + """ + def __init__(self, cdist_object, explorer_name, explorer_path, + stderr_path, subject=''): + params = [ + ('object name', cdist_object.name, ), + ('object path', cdist_object.absolute_path, ), + ('object source', " ".join(cdist_object.source), ), + ('object type', os.path.realpath( + cdist_object.cdist_type.absolute_path), ), + ('explorer name', explorer_name, ), + ('explorer path', explorer_path, ), + ] + stdout_paths = [] + stderr_paths = [ + ('remote', stderr_path, ), + ] + super().__init__("explorer '{}' of object '{}'".format( + explorer_name, cdist_object.name), params, stdout_paths, + stderr_paths, subject) + + class InitialManifestError(CdistEntityError): """Something went wrong while executing initial manifest""" def __init__(self, initial_manifest, stdout_path, stderr_path, subject=''): params = [ ('path', initial_manifest, ), ] - stdout_paths = [] stdout_paths = [ ('init', stdout_path, ), ] - stderr_paths = [] stderr_paths = [ ('init', stderr_path, ), ] @@ -199,6 +222,20 @@ class InitialManifestError(CdistEntityError): stderr_paths, subject) +class GlobalExplorerError(CdistEntityError): + """Something went wrong while executing global explorer""" + def __init__(self, name, path, stderr_path, subject=''): + params = [ + ('name', name, ), + ('path', path, ), + ] + stderr_paths = [ + ('remote', stderr_path, ), + ] + super().__init__("global explorer '{}'".format(name), + params, [], stderr_paths, subject) + + def file_to_list(filename): """Return list from \n seperated file""" if os.path.isfile(filename): diff --git a/cdist/config.py b/cdist/config.py index 11c433db..fae2ff46 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -702,12 +702,11 @@ class Config(object): def object_prepare(self, cdist_object, transfer_type_explorers=True): """Prepare object: Run type explorer + manifest""" + self.log.verbose("Preparing object {}".format(cdist_object.name)) + self.log.verbose( + "Running manifest and explorers for " + cdist_object.name) + self.explorer.run_type_explorers(cdist_object, transfer_type_explorers) try: - self.log.verbose("Preparing object {}".format(cdist_object.name)) - self.log.verbose( - "Running manifest and explorers for " + cdist_object.name) - self.explorer.run_type_explorers(cdist_object, - transfer_type_explorers) self.manifest.run_type_manifest(cdist_object) cdist_object.state = core.CdistObject.STATE_PREPARED except cdist.Error as e: diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 0b3d7b2e..26b7021a 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -109,10 +109,17 @@ class Explorer(object): self._run_global_explorers_parallel(out_path) def _run_global_explorer(self, explorer, out_path): - output = self.run_global_explorer(explorer) - path = os.path.join(out_path, explorer) - with open(path, 'w') as fd: - fd.write(output) + try: + path = os.path.join(out_path, explorer) + output = self.run_global_explorer(explorer) + with open(path, 'w') as fd: + fd.write(output) + except cdist.Error as e: + local_path = os.path.join(self.local.global_explorer_path, + explorer) + stderr_path = os.path.join(self.local.stderr_base_path, "remote") + raise cdist.GlobalExplorerError(explorer, local_path, stderr_path, + e) def _run_global_explorers_seq(self, out_path): self.log.debug("Running global explorers sequentially") @@ -186,11 +193,20 @@ class Explorer(object): self.log.trace("Transferring object parameters for object: %s", cdist_object.name) self.transfer_object_parameters(cdist_object) - for explorer in self.list_type_explorer_names(cdist_object.cdist_type): - output = self.run_type_explorer(explorer, cdist_object) + cdist_type = cdist_object.cdist_type + for explorer in self.list_type_explorer_names(cdist_type): self.log.trace("Running type explorer '%s' for object '%s'", explorer, cdist_object.name) - cdist_object.explorers[explorer] = output + try: + output = self.run_type_explorer(explorer, cdist_object) + cdist_object.explorers[explorer] = output + except cdist.Error as e: + path = os.path.join(self.local.type_path, + cdist_type.explorer_path, + explorer) + stderr_path = os.path.join(self.local.stderr_base_path, "remote") + raise cdist.CdistObjectExplorerError( + cdist_object, explorer, path, stderr_path, e) def run_type_explorer(self, explorer, cdist_object): """Run the given type explorer for the given object and return From e3a900c1c931d1242543caa4c3947362f1a8cc7e Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sat, 20 Apr 2019 12:14:38 +0300 Subject: [PATCH 1127/1332] __ssh_authorized_keys: remove legacy code --- cdist/conf/type/__ssh_authorized_keys/manifest | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index a8ded2f6..b507c7ff 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -45,18 +45,6 @@ if [ ! -f "$__object/parameter/noparent" ] || [ ! -f "$__object/parameter/nofile fi fi -# Remove legacy blocks created by old versions of this type -# FIXME: remove me in 3.2+ -__block "$__object_name" \ - --file "$file" \ - --prefix "#cdist:$__object_name" \ - --suffix "#/cdist:$__object_name" \ - --state 'absent' \ - --text - << DONE -remove legacy block -DONE -export require="__block/$__object_name" - _cksum() { echo "$1" | cksum | cut -d' ' -f 1 } From 038524ba30168e0205c4f391d6bf09f7b992fe28 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sat, 20 Apr 2019 16:09:47 +0300 Subject: [PATCH 1128/1332] support solaris in __(file|directory)/explorer/stat --- cdist/conf/type/__directory/explorer/stat | 29 +++++++++++++++++++++ cdist/conf/type/__file/explorer/stat | 31 +++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat index db3c149a..03d466ba 100755 --- a/cdist/conf/type/__directory/explorer/stat +++ b/cdist/conf/type/__directory/explorer/stat @@ -39,6 +39,35 @@ group: %g %G mode: %a %A " "$destination" ;; + solaris) + ls1="$( ls -ld "$destination" )" + ls2="$( ls -ldn "$destination" )" + + if [ -f "$__object/parameter/mode" ] + then mode_should="$( cat "$__object/parameter/mode" )" + fi + + # yes, it is ugly hack, but if you know better way... + if [ -z "$( find "$destination" -perm "$mode_should" )" ] + then octets=888 + else octets="$( echo "$mode_should" | sed 's/^0//' )" + fi + + case "$( echo "$ls1" | cut -c1-1 )" in + -) echo 'type: regular file' ;; + d) echo 'type: directory' ;; + esac + + echo "owner: $( echo "$ls2" \ + | awk '{print $3}' ) $( echo "$ls1" \ + | awk '{print $3}' )" + + echo "group: $( echo "$ls2" \ + | awk '{print $4}' ) $( echo "$ls1" \ + | awk '{print $4}' )" + + echo "mode: $octets $( echo "$ls1" | awk '{print $1}' )" + ;; *) stat --printf="type: %F owner: %u %U diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat index a0f35dcc..13c1c208 100755 --- a/cdist/conf/type/__file/explorer/stat +++ b/cdist/conf/type/__file/explorer/stat @@ -45,6 +45,37 @@ size: %s links: %h " "$destination" ;; + solaris) + ls1="$( ls -ld "$destination" )" + ls2="$( ls -ldn "$destination" )" + + if [ -f "$__object/parameter/mode" ] + then mode_should="$( cat "$__object/parameter/mode" )" + fi + + # yes, it is ugly hack, but if you know better way... + if [ -z "$( find "$destination" -perm "$mode_should" )" ] + then octets=888 + else octets="$( echo "$mode_should" | sed 's/^0//' )" + fi + + case "$( echo "$ls1" | cut -c1-1 )" in + -) echo 'type: regular file' ;; + d) echo 'type: directory' ;; + esac + + echo "owner: $( echo "$ls2" \ + | awk '{print $3}' ) $( echo "$ls1" \ + | awk '{print $3}' )" + + echo "group: $( echo "$ls2" \ + | awk '{print $4}' ) $( echo "$ls1" \ + | awk '{print $4}' )" + + echo "mode: $octets $( echo "$ls1" | awk '{print $1}' )" + echo "size: $( echo "$ls1" | awk '{print $5}' )" + echo "links: $( echo "$ls1" | awk '{print $2}' )" + ;; *) stat --printf="type: %F owner: %u %U From d08ab628da0252dd5876ca1aded72d53fc7804cf Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 20 Apr 2019 17:04:34 +0200 Subject: [PATCH 1129/1332] ++ --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index c2e5b941..48b0e6ee 100644 --- a/docs/changelog +++ b/docs/changelog @@ -15,6 +15,7 @@ next: * Core: Fix circular dependency for CDIST_ORDER_DEPENDENCY (Darko Poljak) * Type __acl: Improve the type (Ander Punnar) * Explorer interfaces: Simplify code, be more compatible (Ander Punnar) + * Explorer disks: Remove assumable default/fallback, for now explicitly support only Linux and BSDs (Ander Punnar, Darko Poljak) 4.10.11: 2019-04-13 * Core: Fix broken quiet mode (Darko Poljak) From c10074780e4399cbd828726d953efd8b9cfd6559 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 20 Apr 2019 17:09:26 +0200 Subject: [PATCH 1130/1332] Release 4.11.0 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 48b0e6ee..bb9642ea 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.11.0: 2019-04-20 * Type __package: Add __package_apk support (Nico Schottelius) * Type __directory: Add alpine support (Nico Schottelius) * Type __file: Add alpine support (Nico Schottelius) From b0273af0d4fbadf9151ed97b95026c6399ddb5aa Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 20 Apr 2019 17:41:07 +0200 Subject: [PATCH 1131/1332] Rm relicts, pypi before web publishing --- bin/build-helper.freebsd | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 58d985a6..ea16ef42 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -372,6 +372,12 @@ eof ;; esac + # Ensure that pypi release has the right version + "$0" version + + # Create and publish package for pypi + make helper=${helper} WEBDIR=${WEBDIR} pypi-release + # publish man, speeches, website if [ "$masterbranch" = yes ]; then make helper=${helper} WEBDIR=${WEBDIR} web-release-all @@ -379,12 +385,6 @@ eof make helper=${helper} WEBDIR=${WEBDIR} web-release-all-no-latest fi - # Ensure that pypi release has the right version - "$0" version - - # Create and publish package for pypi - make helper=${helper} WEBDIR=${WEBDIR} pypi-release - case "$run_as" in freebsd) ;; @@ -396,28 +396,6 @@ eof # Announce change on ML make helper=${helper} WEBDIR=${WEBDIR} ml-release - - cat << eof -Manual steps post release: - - - linkedin - - hackernews - - reddit - - twitter - -eof - - case "$run_as" in - freebsd) - cat < Date: Sun, 21 Apr 2019 07:46:32 +0200 Subject: [PATCH 1132/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index bb9642ea..cade2b71 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Improve explorer error reporting (Darko Poljak) + 4.11.0: 2019-04-20 * Type __package: Add __package_apk support (Nico Schottelius) * Type __directory: Add alpine support (Nico Schottelius) From 5314f514c5937875537a37aa98225c771fb4abed Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Apr 2019 09:12:13 +0200 Subject: [PATCH 1133/1332] Print empty disk list for unsupported OS --- cdist/conf/explorer/disks | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks index 51660e13..87a6b5c6 100755 --- a/cdist/conf/explorer/disks +++ b/cdist/conf/explorer/disks @@ -1,4 +1,4 @@ -#!/bin/sh -e +#!/bin/sh uname_s="$(uname -s)" @@ -16,12 +16,12 @@ case "${uname_s}" in # https://www.kernel.org/doc/Documentation/admin-guide/devices.txt lsblk -e 1,2,11 -dno name | xargs else - printf "%s operating system without lsblk is not supported, if you can please submit a patch\n" "${uname_s}" >&2 - exit 1 + printf "Don't know how to list disks for %s operating system without lsblk, if you can please submit a patch\n" "${uname_s}" >&2 fi ;; *) - printf "%s operating system is not supported, if you can please submit a patch\n" "${uname_s}" >&2 - exit 1 + printf "Don't know how to list disks for %s operating system, if you can please submit a patch\n" "${uname_s}" >&2 ;; esac + +exit 0 From 7ca66b7b6a3229fa87a4e1db649ccaf0b72af282 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Apr 2019 09:22:52 +0200 Subject: [PATCH 1134/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index cade2b71..92c97565 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,9 @@ Changelog next: * Core: Improve explorer error reporting (Darko Poljak) + * Type __directory: explorer stat: add support for Solaris (Ander Punnar) + * Type __file: explorer stat: add support for Solaris (Ander Punnar) + * Type __ssh_authorized_keys: Remove legacy code (Ander Punnar) 4.11.0: 2019-04-20 * Type __package: Add __package_apk support (Nico Schottelius) From 6bd34c74d3a57355b36018edf34717a57bf4c312 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Apr 2019 21:03:53 +0200 Subject: [PATCH 1135/1332] ++ --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 92c97565..f4b70ae0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,9 @@ next: * Type __directory: explorer stat: add support for Solaris (Ander Punnar) * Type __file: explorer stat: add support for Solaris (Ander Punnar) * Type __ssh_authorized_keys: Remove legacy code (Ander Punnar) + * Explorer disks: Bugfix: do not break config in case of unsupported OS + which was introduced in 4.11.0, print message to stderr and empty disk list + to stdout instead (Darko Poljak) 4.11.0: 2019-04-20 * Type __package: Add __package_apk support (Nico Schottelius) From 7c0ba0d5bece0a8f6a3b82f0d7476fe3015c2166 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Apr 2019 21:11:36 +0200 Subject: [PATCH 1136/1332] pycodestyle --- cdist/core/explorer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 26b7021a..acceacac 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -204,7 +204,8 @@ class Explorer(object): path = os.path.join(self.local.type_path, cdist_type.explorer_path, explorer) - stderr_path = os.path.join(self.local.stderr_base_path, "remote") + stderr_path = os.path.join(self.local.stderr_base_path, + "remote") raise cdist.CdistObjectExplorerError( cdist_object, explorer, path, stderr_path, e) From 2536cd6f95f519649db84bda50e11934edadb580 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 22 Apr 2019 21:12:09 +0200 Subject: [PATCH 1137/1332] Release 4.11.1 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index f4b70ae0..bf106861 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +4.11.1: 2019-04-22 * Core: Improve explorer error reporting (Darko Poljak) * Type __directory: explorer stat: add support for Solaris (Ander Punnar) * Type __file: explorer stat: add support for Solaris (Ander Punnar) From a95d4ffefafaf3e7142bacbc33951ab9f2dc3d74 Mon Sep 17 00:00:00 2001 From: Dmitry Bogatov Date: Tue, 23 Apr 2019 12:36:24 +0000 Subject: [PATCH 1138/1332] Fix spelling error in manpage --- cdist/conf/type/__zypper_service/man.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__zypper_service/man.rst b/cdist/conf/type/__zypper_service/man.rst index ea48aebb..e082dc02 100644 --- a/cdist/conf/type/__zypper_service/man.rst +++ b/cdist/conf/type/__zypper_service/man.rst @@ -46,10 +46,10 @@ EXAMPLES # Ensure that internal SLES11 SP3 RIS is in installed and all other services and repos are discarded __zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --uri "http://path/to/your/ris/dir" --remove-all-other-services --remove-all-repos - # Ensure that internal SLES11 SP3 RIS is in installed, no changes to ohter services or repos + # Ensure that internal SLES11 SP3 RIS is in installed, no changes to other services or repos __zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --uri "http://path/to/your/ris/dir" - # Drop service by uri, no changes to ohter services or repos + # Drop service by uri, no changes to other services or repos __zypper_service INTERNAL_SLES11_SP3 --state absent --uri "http://path/to/your/ris/dir" From 31b9859e08d685032a4bc15eca0ed6f80cfb9fdd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 23 Apr 2019 17:22:02 +0200 Subject: [PATCH 1139/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index bf106861..c64ca60a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __zypper_service: Fix spelling error in manpage (Dmitry Bogatov) + 4.11.1: 2019-04-22 * Core: Improve explorer error reporting (Darko Poljak) * Type __directory: explorer stat: add support for Solaris (Ander Punnar) From 894311a57200c5bc2094890033d6df0867d52c43 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Wed, 24 Apr 2019 00:08:43 +0300 Subject: [PATCH 1140/1332] __acl: if users/groups check fail, log error and exit in explorer --- cdist/conf/type/__acl/explorer/missing_users_groups | 3 ++- cdist/conf/type/__acl/gencode-remote | 8 -------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/cdist/conf/type/__acl/explorer/missing_users_groups b/cdist/conf/type/__acl/explorer/missing_users_groups index b4af614c..2f3b9e6d 100755 --- a/cdist/conf/type/__acl/explorer/missing_users_groups +++ b/cdist/conf/type/__acl/explorer/missing_users_groups @@ -40,7 +40,8 @@ do if ! getent "$getent_db" "$check" > /dev/null then - echo "missing $parameter '$check'" + echo "missing $parameter '$check'" >&2 + exit 1 fi done \ < "$__object/parameter/$parameter" diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index a0f25a15..c0594497 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -22,14 +22,6 @@ file_is="$( cat "$__object/explorer/file_is" )" [ "$file_is" = 'missing' ] && exit 0 -missing_users_groups="$( cat "$__object/explorer/missing_users_groups" )" - -if [ -n "$missing_users_groups" ] -then - echo "$missing_users_groups" >&2 - exit 1 -fi - os="$( cat "$__global/explorer/os" )" acl_is="$( cat "$__object/explorer/acl_is" )" From d66b6969f31ea2c7690a0b85a41a76d07b7ac3e0 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Wed, 24 Apr 2019 00:09:49 +0300 Subject: [PATCH 1141/1332] __acl: rename missing_users_groups explorer to more generic name for future checks --- cdist/conf/type/__acl/explorer/{missing_users_groups => checks} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cdist/conf/type/__acl/explorer/{missing_users_groups => checks} (100%) diff --git a/cdist/conf/type/__acl/explorer/missing_users_groups b/cdist/conf/type/__acl/explorer/checks similarity index 100% rename from cdist/conf/type/__acl/explorer/missing_users_groups rename to cdist/conf/type/__acl/explorer/checks From f586937614383ebf67e2bcbf061c0ab7b7847620 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Wed, 24 Apr 2019 00:36:53 +0300 Subject: [PATCH 1142/1332] __acl: drop Solaris because POSIX-draft ACL specification is not supported --- cdist/conf/type/__acl/gencode-remote | 44 ++++++++++++---------------- cdist/conf/type/__acl/man.rst | 6 ++-- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index c0594497..61a83c8c 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -74,34 +74,26 @@ fi if [ -f "$__object/parameter/remove" ] then - if echo "$os" | grep -Fq 'solaris' - then - # Solaris setfacl behaves differently. - # We will not support Solaris for now, because no way to test it. - # But adding support should be easy (use -s instead of -m on modify). - echo "$os setfacl do not support -x flag for ACL remove" >&2 - else - echo "$acl_is" | while read -r acl - do - # Skip wanted ACL entries which already exist - # and skip mask and other entries, because we - # can't actually remove them, but only change. - if echo "$acl_should" | grep -Eq "^$acl" \ - || echo "$acl" | grep -Eq '^(default:)?(mask|other)' - then continue - fi + echo "$acl_is" | while read -r acl + do + # Skip wanted ACL entries which already exist + # and skip mask and other entries, because we + # can't actually remove them, but only change. + if echo "$acl_should" | grep -Eq "^$acl" \ + || echo "$acl" | grep -Eq '^(default:)?(mask|other)' + then continue + fi - if echo "$os" | grep -Eq 'macosx|freebsd' - then - remove="$acl" - else - remove="$( echo "$acl" | sed 's/:...$//' )" - fi + if echo "$os" | grep -Eq 'macosx|freebsd' + then + remove="$acl" + else + remove="$( echo "$acl" | sed 's/:...$//' )" + fi - echo "$setfacl_exec -x \"$remove\" \"$acl_path\"" - echo "removed '$remove'" >> "$__messages_out" - done - fi + echo "$setfacl_exec -x \"$remove\" \"$acl_path\"" + echo "removed '$remove'" >> "$__messages_out" + done fi for acl in $acl_should diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst index 092eb555..e6784c87 100644 --- a/cdist/conf/type/__acl/man.rst +++ b/cdist/conf/type/__acl/man.rst @@ -10,11 +10,9 @@ DESCRIPTION ----------- ACL must be defined as 3-symbol combination, using ``r``, ``w``, ``x`` and ``-``. -Fully supported on Linux (tested on Debian and CentOS). +Fully supported and tested on Linux, partial support for FreeBSD. -Partial support for FreeBSD, OSX and Solaris. - -OpenBSD and NetBSD support is not possible. +OpenBSD, NetBSD and Solaris support is not possible. See ``setfacl`` and ``acl`` manpages for more details. From 4c21983698932e17ca9276873e32a908b4235bf7 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Wed, 24 Apr 2019 00:39:54 +0300 Subject: [PATCH 1143/1332] __acl: remove macosx because no way to properly test --- cdist/conf/type/__acl/gencode-remote | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 61a83c8c..ef903816 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -64,7 +64,7 @@ setfacl_exec='setfacl' if [ -f "$__object/parameter/recursive" ] then - if echo "$os" | grep -Eq 'macosx|freebsd' + if echo "$os" | grep -Fq 'freebsd' then echo "$os setfacl do not support recursive operations" >&2 else @@ -84,7 +84,7 @@ then then continue fi - if echo "$os" | grep -Eq 'macosx|freebsd' + if echo "$os" | grep -Fq 'freebsd' then remove="$acl" else @@ -100,7 +100,7 @@ for acl in $acl_should do if ! echo "$acl_is" | grep -Eq "^$acl" then - if echo "$os" | grep -Eq 'macosx|freebsd' \ + if echo "$os" | grep -Fq 'freebsd' \ && echo "$acl" | grep -Eq '^default:' then echo "setting default ACL in $os is currently not supported. sorry :(" >&2 From 510ea220f275caf2667547c55b54f06b55965bf5 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Wed, 24 Apr 2019 11:02:32 +0200 Subject: [PATCH 1144/1332] [type/__block] Quote prefix and suffix correctly Before prefix and suffix were not allowed to contain " (quotes). --- cdist/conf/type/__block/gencode-remote | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__block/gencode-remote b/cdist/conf/type/__block/gencode-remote index f269c785..1f5cc033 100755 --- a/cdist/conf/type/__block/gencode-remote +++ b/cdist/conf/type/__block/gencode-remote @@ -18,6 +18,11 @@ # along with cdist. If not, see . # +# quote function from http://www.etalabs.net/sh_tricks.html +quote() { + printf '%s\n' "$1" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/" +} + file="$(cat "$__object/parameter/file" 2>/dev/null || echo "/$__object_id")" state_should=$(cat "$__object/parameter/state") prefix=$(cat "$__object/parameter/prefix" 2>/dev/null || echo "#cdist:__block/$__object_id") @@ -46,7 +51,7 @@ tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) if [ -f "$file" ]; then cp -p "$file" "\$tmpfile" fi -awk -v prefix="^$prefix\$" -v suffix="^$suffix\$" ' +awk -v prefix=^$(quote "$prefix")\$ -v suffix=^$(quote "$suffix")\$ ' { if (match(\$0,prefix)) { triggered=1 From 6dd5278aded69d62db030a53cfefb4dac1b46023 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Wed, 24 Apr 2019 11:15:44 +0200 Subject: [PATCH 1145/1332] [explorer/init] Add support for OpenBSD --- cdist/conf/explorer/init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/explorer/init b/cdist/conf/explorer/init index 43a66a50..a8a7857e 100755 --- a/cdist/conf/explorer/init +++ b/cdist/conf/explorer/init @@ -29,7 +29,7 @@ case "$uname_s" in Linux) (pgrep -P0 -l | awk '/^1[ \t]/ {print $2;}') || true ;; - FreeBSD) + FreeBSD|OpenBSD) ps -o comm= -p 1 || true ;; *) From f7ace88ec25957a71bf621cfefdc2e91db7d7994 Mon Sep 17 00:00:00 2001 From: Takashi Yoshi Date: Wed, 24 Apr 2019 11:36:57 +0200 Subject: [PATCH 1146/1332] [__postgres_{database,role}] Run psql with --no-password (-w) cdist does not work with interactive processes, so it's better to fail when manual password input is required. --- cdist/conf/type/__postgres_database/explorer/state | 2 +- cdist/conf/type/__postgres_role/explorer/state | 2 +- cdist/conf/type/__postgres_role/gencode-remote | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__postgres_database/explorer/state b/cdist/conf/type/__postgres_database/explorer/state index 652d81e7..d68d4120 100755 --- a/cdist/conf/type/__postgres_database/explorer/state +++ b/cdist/conf/type/__postgres_database/explorer/state @@ -34,7 +34,7 @@ esac name="$__object_id" -if test -n "$(su - "$postgres_user" -c "psql postgres -tAc \"SELECT 1 FROM pg_database WHERE datname='$name'\"")" +if test -n "$(su - "$postgres_user" -c "psql postgres -twAc \"SELECT 1 FROM pg_database WHERE datname='$name'\"")" then echo 'present' else diff --git a/cdist/conf/type/__postgres_role/explorer/state b/cdist/conf/type/__postgres_role/explorer/state index 5cc71477..c8e1fa9d 100755 --- a/cdist/conf/type/__postgres_role/explorer/state +++ b/cdist/conf/type/__postgres_role/explorer/state @@ -34,7 +34,7 @@ esac name="$__object_id" -if test -n "$(su - "$postgres_user" -c "psql postgres -tAc \"SELECT 1 FROM pg_roles WHERE rolname='$name'\"")" +if test -n "$(su - "$postgres_user" -c "psql postgres -twAc \"SELECT 1 FROM pg_roles WHERE rolname='$name'\"")" then echo 'present' else diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index 30d0689c..fd56e85d 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -55,7 +55,7 @@ case "$state_should" in [ -n "$password" ] && password="PASSWORD '$password'" cmd="CREATE ROLE $name WITH $password $booleans" - echo "su - '$postgres_user' -c \"psql postgres -c \\\"$cmd\\\"\"" + echo "su - '$postgres_user' -c \"psql postgres -wc \\\"$cmd\\\"\"" ;; absent) echo "su - '$postgres_user' -c \"dropuser \\\"$name\\\"\"" From 3ca337dfe0878a71ca14e550111d31fffa14b461 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 24 Apr 2019 12:23:37 +0200 Subject: [PATCH 1147/1332] ++changelog --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index c64ca60a..ca66a0f0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,10 @@ Changelog next: * Type __zypper_service: Fix spelling error in manpage (Dmitry Bogatov) + * Explorer init: Add support for OpenBSD (sideeffect42) + * Type __postgres_database: Run psql with -w (no-password) (sideeffect42) + * Type __postgres_role: Run psql with -w (no-password) (sideeffect42) + * Type __block: Quote prefix/suffix - fix when prefix/suffix contains quotes (sideeffect42) 4.11.1: 2019-04-22 * Core: Improve explorer error reporting (Darko Poljak) From 8b93bf0218cf2097976159dab332dcaaff3f5eb4 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 30 Dec 2018 11:59:34 +0100 Subject: [PATCH 1148/1332] Migrate from github to ungleich gitlab --- bin/build-helper | 49 ++++++++---------- bin/build-helper.freebsd | 48 ++++++++---------- cdist/conf/type/__cdist/man.rst | 4 +- .../type/__cdist/parameter/default/source | 2 +- cdist/conf/type/__git/man.rst | 2 +- docs/dev/github-gitlab-migration/release | 50 +++++++++++++++++++ docs/src/cdist-hacker.rst | 20 ++++---- docs/src/cdist-install.rst | 13 ++--- docs/src/cdist-quickstart.rst | 2 +- 9 files changed, 112 insertions(+), 78 deletions(-) create mode 100755 docs/dev/github-gitlab-migration/release diff --git a/bin/build-helper b/bin/build-helper index 963f02f9..72f683b9 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -209,35 +209,30 @@ eof fi gpg --armor --detach-sign "${archivename}" || exit 1 - # make github release - curl -H "Authorization: token ${token}" \ - --request POST \ - --data "{ \"tag_name\":\"${tag}\", \ - \"target_commitish\":\"master\", \ - \"name\": \"${tag}\", \ - \"body\":\"${tag}\", \ - \"draft\":false, \ - \"prerelease\": false}" \ - "https://api.github.com/repos/ungleich/cdist/releases" || exit 1 + project="ungleich-public%2Fcdist" + sed_cmd='s/^.*"markdown":"\([^"]*\)".*$/\1/' - # get release ID - repoid=$(curl "https://api.github.com/repos/ungleich/cdist/releases/tags/${tag}" \ - | python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ + # upload archive + response_archive=$(curl -f -X POST \ + -H "PRIVATE-TOKEN: ${token}" \ + -F "file=@${archivename}" \ + "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ + | sed "${sed_cmd}") || exit 1 + + # upload archive signature + response_archive_sig=$(curl -f -X POST \ + -H "PRIVATE-TOKEN: ${token}" \ + -F "file=@${archivename}.asc" \ + "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ + | sed "${sed_cmd}") || exit 1 + + # make release + curl -f -X POST \ + -H "PRIVATE-TOKEN: ${token}" \ + -F "description=Release ${tag}
${response_archive}
${response_archive_sig}" \ + "https://code.ungleich.ch/api/v4/projects/${project}/repository/tags/${tag}/release" \ || exit 1 - # upload archive and then signature - curl -H "Authorization: token ${token}" \ - -H "Accept: application/vnd.github.manifold-preview" \ - -H "Content-Type: application/x-gtar" \ - --data-binary @${archivename} \ - "https://uploads.github.com/repos/ungleich/cdist/releases/${repoid}/assets?name=${archivename}" \ - || exit 1 - curl -H "Authorization: token ${token}" \ - -H "Accept: application/vnd.github.manifold-preview" \ - -H "Content-Type: application/pgp-signature" \ - --data-binary @${archivename}.asc \ - "https://uploads.github.com/repos/ungleich/cdist/releases/${repoid}/assets?name=${archivename}.asc" \ - || exit 1 # remove generated files (archive and asc) if [ $# -eq 2 ] @@ -314,7 +309,7 @@ eof "$0" release-git-tag # sign git tag - printf "Enter github authentication token: " + printf "Enter upstream repository authentication token: " read token "$0" sign-git-release "${target_version}" "${token}" diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index ea16ef42..cb8e5397 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -244,34 +244,28 @@ eof fi gpg --armor --detach-sign "${archivename}" || exit 1 - # make github release - curl -H "Authorization: token ${token}" \ - --request POST \ - --data "{ \"tag_name\":\"${tag}\", \ - \"target_commitish\":\"master\", \ - \"name\": \"${tag}\", \ - \"body\":\"${tag}\", \ - \"draft\":false, \ - \"prerelease\": false}" \ - "https://api.github.com/repos/ungleich/cdist/releases" || exit 1 + project="ungleich-public%2Fcdist" + sed_cmd='s/^.*"markdown":"\([^"]*\)".*$/\1/' - # get release ID - repoid=$(curl "https://api.github.com/repos/ungleich/cdist/releases/tags/${tag}" \ - | python3 -c 'import json; import sys; print(json.loads(sys.stdin.read())["id"])') \ - || exit 1 + # upload archive + response_archive=$(curl -f -X POST \ + -H "PRIVATE-TOKEN: ${token}" \ + -F "file=@${archivename}" \ + "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ + | sed "${sed_cmd}") || exit 1 - # upload archive and then signature - curl -H "Authorization: token ${token}" \ - -H "Accept: application/vnd.github.manifold-preview" \ - -H "Content-Type: application/x-gtar" \ - --data-binary @${archivename} \ - "https://uploads.github.com/repos/ungleich/cdist/releases/${repoid}/assets?name=${archivename}" \ - || exit 1 - curl -H "Authorization: token ${token}" \ - -H "Accept: application/vnd.github.manifold-preview" \ - -H "Content-Type: application/pgp-signature" \ - --data-binary @${archivename}.asc \ - "https://uploads.github.com/repos/ungleich/cdist/releases/${repoid}/assets?name=${archivename}.asc" \ + # upload archive signature + response_archive_sig=$(curl -f -X POST \ + -H "PRIVATE-TOKEN: ${token}" \ + -F "file=@${archivename}.asc" \ + "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ + | sed "${sed_cmd}") || exit 1 + + # make release + curl -f -X POST \ + -H "PRIVATE-TOKEN: ${token}" \ + -F "description=Release ${tag}
${response_archive}
${response_archive_sig}" \ + "https://code.ungleich.ch/api/v4/projects/${project}/repository/tags/${tag}/release" \ || exit 1 # remove generated files (archive and asc) @@ -349,7 +343,7 @@ eof "$0" release-git-tag # sign git tag - printf "Enter github authentication token: " + printf "Enter upstream repository authentication token: " read token "$0" sign-git-release "${target_version}" "${token}" diff --git a/cdist/conf/type/__cdist/man.rst b/cdist/conf/type/__cdist/man.rst index 9e1c72cb..15c77d7f 100644 --- a/cdist/conf/type/__cdist/man.rst +++ b/cdist/conf/type/__cdist/man.rst @@ -30,7 +30,7 @@ username source Select the source from which to clone cdist from. - Defaults to "git://github.com/ungleich/cdist.git". + Defaults to "git://code.ungleich.ch/ungleich-public/cdist.git". branch @@ -47,7 +47,7 @@ EXAMPLES __cdist /home/cdist/cdist # Use alternative source - __cdist --source "git://github.com/ungleich/cdist" /home/cdist/cdist + __cdist --source "git://code.ungleich.ch/ungleich-public/cdist" /home/cdist/cdist AUTHORS diff --git a/cdist/conf/type/__cdist/parameter/default/source b/cdist/conf/type/__cdist/parameter/default/source index 3f8e31ad..5f44a285 100644 --- a/cdist/conf/type/__cdist/parameter/default/source +++ b/cdist/conf/type/__cdist/parameter/default/source @@ -1 +1 @@ -git://github.com/ungleich/cdist.git +git://code.ungleich.ch/ungleich-public/cdist.git diff --git a/cdist/conf/type/__git/man.rst b/cdist/conf/type/__git/man.rst index 17e9c623..aa704d2b 100644 --- a/cdist/conf/type/__git/man.rst +++ b/cdist/conf/type/__git/man.rst @@ -44,7 +44,7 @@ EXAMPLES __git /home/services/dokuwiki --source git://github.com/splitbrain/dokuwiki.git # Checkout cdist, stay on branch 2.1 - __git /home/nico/cdist --source git://github.com/ungleich/cdist.git --branch 2.1 + __git /home/nico/cdist --source git://code.ungleich.ch/ungleich-public/cdist.git --branch 2.1 AUTHORS diff --git a/docs/dev/github-gitlab-migration/release b/docs/dev/github-gitlab-migration/release new file mode 100755 index 00000000..c973f0f1 --- /dev/null +++ b/docs/dev/github-gitlab-migration/release @@ -0,0 +1,50 @@ +#!/bin/sh -e + +set -x + +printf "Enter tag name: " +read tag +printf "Enter repository authentication token: " +read token + +git tag -d "${tag}" || : + +git tag "${tag}" -m "Release ${tag}" +git push origin "${tag}" + +echo 'foo' > foo +echo 'foo signature' > foo.asc + +archivename="foo" + +project="poljakowski%2Fmy-cdist-testing" +sed_cmd='s/^.*"markdown":"\([^"]*\)".*$/\1/' + +# upload archive +response_archive=$(curl -f -X POST \ + -H "PRIVATE-TOKEN: ${token}" \ + -F "file=@${archivename}" \ + "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ + | sed "${sed_cmd}") || exit 1 + +# upload archive signature +response_archive_sig=$(curl -f -X POST \ + -H "PRIVATE-TOKEN: ${token}" \ + -F "file=@${archivename}.asc" \ + "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ + | sed "${sed_cmd}") || exit 1 + +# make release +curl -f -X POST \ + -H "PRIVATE-TOKEN: ${token}" \ + -F "description=Release ${tag}
${response_archive}
${response_archive_sig}" \ + "https://code.ungleich.ch/api/v4/projects/${project}/repository/tags/${tag}/release" \ + || exit 1 + +# get tag +curl -f -X GET \ + -H "PRIVATE-TOKEN: ${token}" \ + "https://code.ungleich.ch/api/v4/projects/${project}/repository/tags/${tag}" \ + || exit 1 + +rm -f foo foo.asc diff --git a/docs/src/cdist-hacker.rst b/docs/src/cdist-hacker.rst index d65c41a6..e4252e19 100644 --- a/docs/src/cdist-hacker.rst +++ b/docs/src/cdist-hacker.rst @@ -16,7 +16,7 @@ Reporting bugs -------------- If you believe you've found a bug and verified that it is in the latest version, drop a mail to the cdist mailing list, -subject prefixed with "[BUG] " or create an issue on github. +subject prefixed with "[BUG] " or create an issue on code.ungleich.ch. Coding conventions (everywhere) @@ -51,7 +51,7 @@ work nor kill the authors brain: As soon as your work meets these requirements, write a mail for inclusion to the mailinglist **cdist-configuration-management at googlegroups.com** -or open a pull request at http://github.com/ungleich/cdist. +or open a merge request at https://code.ungleich.ch/ungleich-public/cdist. How to submit a new type @@ -76,7 +76,7 @@ The following workflow works fine for most developers .. code-block:: sh # get latest upstream master branch - git clone https://github.com/ungleich/cdist.git + git clone https://code.ungleich.ch/ungleich-public/cdist.git # update if already existing cd cdist; git fetch -v; git merge origin/master @@ -88,22 +88,22 @@ The following workflow works fine for most developers # *hack* *hack* - # clone the cdist repository on github if you haven't done so + # clone the cdist repository on code.ungleich.ch if you haven't done so # configure your repo to know about your clone (only once) - git remote add github git@github.com:YOURUSERNAME/cdist.git + git remote add ungleich git@code.ungleich.ch:YOURUSERNAME/cdist.git - # push the new branch to github - git push github documentation_cleanup + # push the new branch to ungleich gitlab + git push ungleich documentation_cleanup # (or everything) - git push --mirror github + git push --mirror ungleich - # create a pull request at github (use a browser) + # create a merge request at ungleich gitlab (use a browser) # *fixthingsbecausequalityassurancefoundissuesinourpatch* *hack* - # push code to github again + # push code to ungleich gitlab again git push ... # like above # add comment that everything should be green now (use a browser) diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst index afc50016..c05036b0 100644 --- a/docs/src/cdist-install.rst +++ b/docs/src/cdist-install.rst @@ -36,10 +36,13 @@ To install cdist, execute the following commands: .. code-block:: sh - git clone https://github.com/ungleich/cdist.git + git clone https://code.ungleich.ch/ungleich-public/cdist.git cd cdist export PATH=$PATH:$(pwd -P)/bin +From version 4.2.0 cdist tags and releases are signed. +You can get GPG public key used for signing `here <_static/pgp-key-EFD2AE4EC36B6901.asc>`_. + To install cdist with distutils from cloned repository, first you have to create version.py: @@ -74,14 +77,6 @@ So for instance if you want to use and stay with version 4.1, you can use git checkout -b 4.1 origin/4.1 -Git mirrors -^^^^^^^^^^^ - -If the main site is down, you can acquire cdist from one of the following sites: - - * git://github.com/telmich/cdist.git `github `_ - * git://git.code.sf.net/p/cdist/code `sourceforge `_ - Building and using documentation (man and html) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/src/cdist-quickstart.rst b/docs/src/cdist-quickstart.rst index 0020568d..b9220b67 100644 --- a/docs/src/cdist-quickstart.rst +++ b/docs/src/cdist-quickstart.rst @@ -56,7 +56,7 @@ code into your shell to get started and configure localhost:: # Get cdist # Mirrors can be found on # http://www.nico.schottelius.org/software/cdist/install/#index2h4 - git clone git://github.com/ungleich/cdist + git clone git://code.ungleich.ch/ungleich-public/cdist # Create manifest (maps configuration to host(s) cd cdist From 6ad261fdf26466be47d9d49b54f17bc34d6392b7 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 25 Apr 2019 23:04:38 +0200 Subject: [PATCH 1149/1332] ++changelog --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index ca66a0f0..9c87d3f7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,8 @@ next: * Type __postgres_database: Run psql with -w (no-password) (sideeffect42) * Type __postgres_role: Run psql with -w (no-password) (sideeffect42) * Type __block: Quote prefix/suffix - fix when prefix/suffix contains quotes (sideeffect42) + * Build: Update due to migration to code.ungleich.ch (Darko Poljak) + * Documentation: Update due to migration to code.ungleich.ch (Darko Poljak) 4.11.1: 2019-04-22 * Core: Improve explorer error reporting (Darko Poljak) From 2505023387ea670fa12af1e9c69c503ac5681136 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 1 May 2019 12:31:30 +0200 Subject: [PATCH 1150/1332] Append requirement only if already not present --- cdist/emulator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 5103f1a4..3cf82f84 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -319,7 +319,9 @@ class Emulator(object): lastcreatedtype) else: if 'require' in self.env: - self.env['require'] += " " + lastcreatedtype + appendix = " " + lastcreatedtype + if appendix not in self.env['require']: + self.env['require'] += appendix else: self.env['require'] = lastcreatedtype self.log.debug(("Injecting require for " From edfaa65d2b37fcb4a7de2280b61dec30dd3a8c5d Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 1 May 2019 14:18:39 +0200 Subject: [PATCH 1151/1332] Detect dependency cycle as soon as possible --- cdist/config.py | 59 ++++++++++++++++++++++++++++-- cdist/test/config/__init__.py | 68 +++++++++++++++++++++++++++++++++-- 2 files changed, 123 insertions(+), 4 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index fae2ff46..4e226b3a 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -43,6 +43,33 @@ from cdist import core, inventory from cdist.util.remoteutil import inspect_ssh_mux_opts +def graph_check_cycle(graph): + # Start from each node in the graph and check for cycle starting from it. + for node in graph: + # Cycle path. + path = [node] + has_cycle = _graph_dfs_cycle( graph, node, path) + if has_cycle: + return has_cycle, path + return False, None + + +def _graph_dfs_cycle(graph, node, path): + for neighbour in graph.get(node, ()): + # If node is already in path then this is cycle. + if neighbour in path: + path.append(neighbour) + return True + path.append(neighbour) + rv = _graph_dfs_cycle(graph, neighbour, path) + if rv: + return True + # Remove last item from list - neighbour whose DFS path we have have + # just checked. + del path[-1] + return False + + class Config(object): """Cdist main class to hold arbitrary data""" @@ -254,14 +281,14 @@ class Config(object): cls.onehost(host, host_tags, host_base_path, hostdir, args, parallel=False, configuration=configuration) - except cdist.Error as e: + except cdist.Error: failed_hosts.append(host) if args.parallel and len(process_args) == 1: log.debug("Only 1 host for parallel processing, doing it " "sequentially") try: cls.onehost(*process_args[0]) - except cdist.Error as e: + except cdist.Error: failed_hosts.append(host) elif args.parallel: log.trace("Multiprocessing start method is {}".format( @@ -653,6 +680,28 @@ class Config(object): self.__dict__.update(state) self._open_logger() + def _validate_dependencies(self): + ''' + Build dependency graph for unfinished objects and + check for cycles. + ''' + graph = {} + for cdist_object in self.object_list(): + obj_name = cdist_object.name + if obj_name not in graph: + graph[obj_name] = [] + if cdist_object.state == cdist_object.STATE_DONE: + continue + + for requirement in cdist_object.requirements_unfinished( + cdist_object.requirements): + graph[obj_name].append(requirement.name) + + for requirement in cdist_object.requirements_unfinished( + cdist_object.autorequire): + graph[obj_name].append(requirement.name) + return graph_check_cycle(graph) + def iterate_until_finished(self): """ Go through all objects and solve them @@ -662,6 +711,12 @@ class Config(object): objects_changed = True while objects_changed: + # Check for cycles as early as possible. + has_cycle, path = self._validate_dependencies() + if has_cycle: + raise cdist.UnresolvableRequirementsError( + "Cycle detected in object dependencies:\n{}!".format( + " -> ".join(path))) objects_changed = self.iterate_once() # Check whether all objects have been finished diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index 2b0d8b5f..499593e3 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -23,7 +23,6 @@ import os import shutil -import tempfile from cdist import test from cdist import core @@ -212,7 +211,7 @@ class ConfigRunTestCase(test.CdistTestCase): dryrun.run() # if we are here, dryrun works like expected - def test_desp_resolver(self): + def test_deps_resolver(self): """Test to show dependency resolver warning message.""" local = cdist.exec.local.Local( target_host=self.target_host, @@ -229,6 +228,71 @@ class ConfigRunTestCase(test.CdistTestCase): config = cdist.config.Config(local, self.remote, dry_run=True) config.run() + def test_graph_check_cycle_empty(self): + graph = {} + has_cycle, path = cdist.config.graph_check_cycle(graph) + self.assertFalse(has_cycle) + + def test_graph_check_cycle_1(self): + # + # a -> b -> c + # | + # +--> d -> e + graph = { + 'a': ['b', ], + 'b': ['c', 'd', ], + 'd': ['e', ], + } + has_cycle, path = cdist.config.graph_check_cycle(graph) + self.assertFalse(has_cycle) + + def test_graph_check_cycle_2(self): + # + # a -> b -> c + # /\ | + # \ | + # +-------+ + graph = { + 'a': ['b', ], + 'b': ['c', ], + 'c': ['a', ], + } + has_cycle, path = cdist.config.graph_check_cycle(graph) + self.assertTrue(has_cycle) + self.assertGreater(path.count(path[-1]), 1) + + def test_graph_check_cycle_3(self): + # + # a -> b -> c + # \ \ + # \ +--> g + # \ /\ + # \ /| + # +-> d -> e | + # \ | + # + --> f + # + # h -> i --> j + # | /\ | + # \/ | \/ + # n m <- k + graph = { + 'a': ['b', 'd', ], + 'b': ['c', ], + 'c': ['g', ], + 'd': ['e', 'f', ], + 'e': ['g', ], + 'f': ['g', ], + 'h': ['i', 'n', ], + 'i': ['j', ], + 'j': ['k', ], + 'k': ['m', ], + 'm': ['i', ], + } + has_cycle, path = cdist.config.graph_check_cycle(graph) + self.assertTrue(has_cycle) + self.assertGreater(path.count(path[-1]), 1) + # Currently the resolving code will simply detect that this object does # not exist. It should probably check if the type is a singleton as well From 2a0a24ecccaf555591a560af934843e57f3689a2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 3 May 2019 14:38:48 +0200 Subject: [PATCH 1152/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 9c87d3f7..d367ed47 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Type __block: Quote prefix/suffix - fix when prefix/suffix contains quotes (sideeffect42) * Build: Update due to migration to code.ungleich.ch (Darko Poljak) * Documentation: Update due to migration to code.ungleich.ch (Darko Poljak) + * Core: Detect and report dependency cycle as soon as possible (Darko Poljak) 4.11.1: 2019-04-22 * Core: Improve explorer error reporting (Darko Poljak) From 6258e397ed7ee64d394372dc2dd2953a236e04fe Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 3 May 2019 21:39:25 +0200 Subject: [PATCH 1153/1332] Include changelog in gitlab release --- bin/build-helper | 7 ++++++- bin/build-helper.freebsd | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 72f683b9..d72c6cab 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -227,9 +227,14 @@ eof | sed "${sed_cmd}") || exit 1 # make release + changelog=$("$0" changelog-changes "$1" | sed 's/^[[:space:]]*//') + release_notes=$( + printf "Release %s\n\n%s\n\n%s\n\n**Changelog**\n\n%s\n" \ + "${tag}" "${response_archive}" "${response_archive_sig}" "${changelog}" + ) curl -f -X POST \ -H "PRIVATE-TOKEN: ${token}" \ - -F "description=Release ${tag}
${response_archive}
${response_archive_sig}" \ + -F "description=${release_notes}" \ "https://code.ungleich.ch/api/v4/projects/${project}/repository/tags/${tag}/release" \ || exit 1 diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index cb8e5397..4f393cb0 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -262,9 +262,14 @@ eof | sed "${sed_cmd}") || exit 1 # make release + changelog=$("$0" changelog-changes "$1" | sed 's/^[[:space:]]*//') + release_notes=$( + printf "Release %s\n\n%s\n\n%s\n\n**Changelog**\n\n%s\n" \ + "${tag}" "${response_archive}" "${response_archive_sig}" "${changelog}" + ) curl -f -X POST \ -H "PRIVATE-TOKEN: ${token}" \ - -F "description=Release ${tag}
${response_archive}
${response_archive_sig}" \ + -F "description=${release_notes}" \ "https://code.ungleich.ch/api/v4/projects/${project}/repository/tags/${tag}/release" \ || exit 1 From fe833fdfcb466ab460a76123b078a0e778cf924c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 3 May 2019 21:46:17 +0200 Subject: [PATCH 1154/1332] Sign git tag as one of the last steps If it fails then the whole release should not fail, signing git tag can be tried again. --- bin/build-helper | 10 +++++----- bin/build-helper.freebsd | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index d72c6cab..53dbf5da 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -313,11 +313,6 @@ eof # Tag the current commit "$0" release-git-tag - # sign git tag - printf "Enter upstream repository authentication token: " - read token - "$0" sign-git-release "${target_version}" "${token}" - # Also merge back the version branch if [ "$masterbranch" = yes ]; then git checkout master @@ -343,6 +338,11 @@ eof # Archlinux release is based on pypi make archlinux-release + # sign git tag + printf "Enter upstream repository authentication token: " + read token + "$0" sign-git-release "${target_version}" "${token}" + # Announce change on ML make ml-release diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 4f393cb0..f3d1fca1 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -347,11 +347,6 @@ eof # Tag the current commit "$0" release-git-tag - # sign git tag - printf "Enter upstream repository authentication token: " - read token - "$0" sign-git-release "${target_version}" "${token}" - # Also merge back the version branch if [ "$masterbranch" = yes ]; then git checkout master @@ -393,6 +388,11 @@ eof ;; esac + # sign git tag + printf "Enter upstream repository authentication token: " + read token + "$0" sign-git-release "${target_version}" "${token}" + # Announce change on ML make helper=${helper} WEBDIR=${WEBDIR} ml-release ;; From 71945ef956a227d9abe33d0e415e2670fa6c0060 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 3 May 2019 21:55:27 +0200 Subject: [PATCH 1155/1332] Fix copy-paste thing --- bin/build-helper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-helper b/bin/build-helper index 53dbf5da..b5898ae3 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -400,7 +400,7 @@ eof ;; shellcheck) - make helper=${helper} WEBDIR=${WEBDIR} shellcheck + make shellcheck printf "\\nPlease review shellcheck report.\\n" while true do From bd9884fac4c46c29d4313cadd40020bf8cf542be Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 3 May 2019 22:16:51 +0200 Subject: [PATCH 1156/1332] Tell curl to use HTTP version 1.1 By default, was getting the following error: curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1) --- bin/build-helper | 2 ++ bin/build-helper.freebsd | 2 ++ 2 files changed, 4 insertions(+) diff --git a/bin/build-helper b/bin/build-helper index b5898ae3..0fea5071 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -214,6 +214,7 @@ eof # upload archive response_archive=$(curl -f -X POST \ + --http1.1 \ -H "PRIVATE-TOKEN: ${token}" \ -F "file=@${archivename}" \ "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ @@ -221,6 +222,7 @@ eof # upload archive signature response_archive_sig=$(curl -f -X POST \ + --http1.1 \ -H "PRIVATE-TOKEN: ${token}" \ -F "file=@${archivename}.asc" \ "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index f3d1fca1..9823dab5 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -249,6 +249,7 @@ eof # upload archive response_archive=$(curl -f -X POST \ + --http1.1 \ -H "PRIVATE-TOKEN: ${token}" \ -F "file=@${archivename}" \ "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ @@ -256,6 +257,7 @@ eof # upload archive signature response_archive_sig=$(curl -f -X POST \ + --http1.1 \ -H "PRIVATE-TOKEN: ${token}" \ -F "file=@${archivename}.asc" \ "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ From 0ab43e24055e00324e18852356f8e2b85637df94 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 13 Apr 2019 21:18:27 +0200 Subject: [PATCH 1157/1332] Release -j/--jobs option, i.e. make it non-beta --- cdist/argparse.py | 5 ++--- docs/src/cdist-parallelization.rst | 7 +++---- docs/src/man1/cdist.rst | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cdist/argparse.py b/cdist/argparse.py index 72fc0d0f..3ebdc138 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -11,7 +11,7 @@ import cdist.configuration BETA_COMMANDS = set(('install', 'inventory', )) # set of beta arguments for sub-commands BETA_ARGS = { - 'config': set(('jobs', 'tag', 'all_tagged_hosts', 'use_archiving', )), + 'config': set(('tag', 'all_tagged_hosts', 'use_archiving', )), } EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/" # Parser others can reuse @@ -191,8 +191,7 @@ def get_parsers(): name="positive int"), help=('Operate in parallel in specified maximum number of jobs. ' 'Global explorers, object prepare and object run are ' - 'supported. Without argument CPU count is used by default. ' - 'Currently in beta.'), + 'supported. Without argument CPU count is used by default. '), action='store', dest='jobs', const=multiprocessing.cpu_count()) parser['config_main'].add_argument( diff --git a/docs/src/cdist-parallelization.rst b/docs/src/cdist-parallelization.rst index ed3afae9..d458a128 100644 --- a/docs/src/cdist-parallelization.rst +++ b/docs/src/cdist-parallelization.rst @@ -12,8 +12,7 @@ The other way is to operate in parallel within one host where you specify the number of jobs. This is enabled with :strong:`-j/--jobs` option where you can specify the number of parallel jobs. By default, :strong:`multiprocessing.cpu_count()` is used. For this mode global explorers, -object preparation and object run are supported and this option is still in -:strong:`beta`. +object preparation and object run are supported. You can, of course, use those two options together. This means that each host will be processed by its own process. Within each process cdist will operate @@ -32,11 +31,11 @@ Examples # Configure hosts read from file hosts.file sequentially but using default # number of parallel jobs - $ cdist config -b -j -f hosts.file + $ cdist config -j -f hosts.file # Configure hosts read from file hosts.file in parallel using 16 # parallel jobs - $ cdist config -b -j 16 -p -f hosts.file + $ cdist config -j 16 -p -f hosts.file Caveats diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst index 2eb0ce00..30832f2f 100644 --- a/docs/src/man1/cdist.rst +++ b/docs/src/man1/cdist.rst @@ -165,7 +165,7 @@ Install command is currently in beta. Operate in parallel in specified maximum number of jobs. Global explorers, object prepare and object run are supported. Without argument CPU count is used by - default. Currently in beta. + default. **-n, --dry-run** Do not execute code. From 249ac917d3ed0620be768e27c4baa34e02e962a1 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 23 Apr 2019 22:39:41 +0200 Subject: [PATCH 1158/1332] Changes due to new website --- .gitignore | 1 + Makefile | 61 +------ README | 3 +- bin/build-helper | 35 +--- bin/build-helper.freebsd | 99 +++-------- docs/src/_static/cdist-logo.jpeg | Bin 0 -> 12560 bytes docs/src/{ => _static}/cdist-logo.png | Bin .../_static}/pgp-key-EFD2AE4EC36B6901.asc | 0 docs/src/cdist-intro.rst | 15 -- docs/src/cdist-os.rst | 23 +-- docs/src/cdist-support.rst | 10 +- .../{cdist-update.rst => cdist-upgrade.rst} | 4 +- docs/src/conf.py | 5 +- docs/src/index.rst | 17 +- docs/web/cdist.mdwn | 21 --- docs/web/cdist/cdist-logo.png | Bin 1542 -> 0 bytes docs/web/cdist/documentation.mdwn | 12 -- docs/web/cdist/features.mdwn | 26 --- docs/web/cdist/install.mdwn | 103 ------------ docs/web/cdist/os.mdwn | 18 -- docs/web/cdist/support.mdwn | 28 ---- docs/web/cdist/update.mdwn | 158 ------------------ docs/web/cdist/update/2.0-to-2.1.mdwn | 118 ------------- docs/web/cdist/why.mdwn | 69 -------- 24 files changed, 62 insertions(+), 764 deletions(-) create mode 100644 docs/src/_static/cdist-logo.jpeg rename docs/src/{ => _static}/cdist-logo.png (100%) rename docs/{web/cdist => src/_static}/pgp-key-EFD2AE4EC36B6901.asc (100%) delete mode 100644 docs/src/cdist-intro.rst rename docs/src/{cdist-update.rst => cdist-upgrade.rst} (99%) delete mode 100644 docs/web/cdist.mdwn delete mode 100644 docs/web/cdist/cdist-logo.png delete mode 100644 docs/web/cdist/documentation.mdwn delete mode 100644 docs/web/cdist/features.mdwn delete mode 100644 docs/web/cdist/install.mdwn delete mode 100644 docs/web/cdist/os.mdwn delete mode 100644 docs/web/cdist/support.mdwn delete mode 100644 docs/web/cdist/update.mdwn delete mode 100644 docs/web/cdist/update/2.0-to-2.1.mdwn delete mode 100644 docs/web/cdist/why.mdwn diff --git a/.gitignore b/.gitignore index 460bbf28..4b80b425 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ Session.vim # Temporary .netrwhist *~ +*.tmp # Auto-generated tag files tags # Persistent undo diff --git a/Makefile b/Makefile index 5f03997a..099812e2 100644 --- a/Makefile +++ b/Makefile @@ -24,13 +24,6 @@ DOCS_SRC_DIR=docs/src SPEECHDIR=docs/speeches TYPEDIR=cdist/conf/type -WEBSRCDIR=docs/web - -WEBDIR=$$HOME/vcs/www.nico.schottelius.org -WEBBLOG=$(WEBDIR)/blog -WEBBASE=$(WEBDIR)/software/cdist -WEBPAGE=$(WEBBASE).mdwn - CHANGELOG_VERSION=$(shell $(helper) changelog-version) CHANGELOG_FILE=docs/changelog @@ -47,7 +40,6 @@ SHELLCHECK_SKIP=grep -v ': __.*is referenced but not assigned.*\[SC2154\]' ################################################################################ # Manpages # -MAN1DSTDIR=$(DOCS_SRC_DIR)/man1 MAN7DSTDIR=$(DOCS_SRC_DIR)/man7 # Manpages #1: Types @@ -81,24 +73,6 @@ docs: man html docs-clean: $(SPHINXC) -# Manpages #5: release part -MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) -HTMLBUILDDIR=docs/dist/html - -docs-dist: html - rm -rf "${MANWEBDIR}" - mkdir -p "${MANWEBDIR}" - # mkdir -p "${MANWEBDIR}/man1" "${MANWEBDIR}/man7" - # cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${MANWEBDIR}/man1 - # cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${MANWEBDIR}/man7 - cp -R ${HTMLBUILDDIR}/* ${MANWEBDIR} - cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" || true - -man-latest-link: web-pub - # Fix ikiwiki, which does not like symlinks for pseudo security - ssh staticweb.ungleich.ch \ - "cd /home/services/www/nico/nico.schottelius.org/www/software/cdist/man/ && rm -f latest && ln -sf "$(CHANGELOG_VERSION)" latest" - # Manpages: .cdist Types DOT_CDIST_PATH=${HOME}/.cdist DOTMAN7DSTDIR=$(MAN7DSTDIR) @@ -111,7 +85,6 @@ DOTMANTYPES=$(subst /man.rst,.rst,$(DOTMANTYPEPREFIX)) $(DOTMAN7DSTDIR)/cdist-type%.rst: $(DOTTYPEDIR)/%/man.rst ln -sf "$^" $@ -# Manpages #3: generic part dotman: $(DOTMANTYPES) $(SPHINXM) @@ -120,7 +93,6 @@ dotman: $(DOTMANTYPES) # SPEECHESOURCES=$(SPEECHDIR)/*.tex SPEECHES=$(SPEECHESOURCES:.tex=.pdf) -SPEECHESWEBDIR=$(WEBBASE)/speeches # Create speeches and ensure Toc is up-to-date $(SPEECHDIR)/%.pdf: $(SPEECHDIR)/%.tex @@ -130,36 +102,6 @@ $(SPEECHDIR)/%.pdf: $(SPEECHDIR)/%.tex speeches: $(SPEECHES) -speeches-dist: speeches - rm -rf "${SPEECHESWEBDIR}" - mkdir -p "${SPEECHESWEBDIR}" - cp ${SPEECHES} "${SPEECHESWEBDIR}" - cd ${SPEECHESWEBDIR} && git add . && git commit -m "cdist speeches updated" || true - -################################################################################ -# Website -# - -BLOGFILE=$(WEBBLOG)/cdist-$(CHANGELOG_VERSION)-released.mdwn - -$(BLOGFILE): $(CHANGELOG_FILE) - $(helper) blog $(CHANGELOG_VERSION) $(BLOGFILE) - -web-blog: $(BLOGFILE) - -web-doc: - # Go to top level, because of cdist.mdwn - rsync -av "$(WEBSRCDIR)/" "${WEBBASE}/.." - cd "${WEBBASE}/.." && git add cdist* && git commit -m "cdist doc update" cdist* || true - -web-dist: web-blog web-doc - -web-pub: web-dist docs-dist speeches-dist - cd "${WEBDIR}" && make pub - -web-release-all: man-latest-link -web-release-all-no-latest: web-pub - ################################################################################ # Release: Mailinglist # @@ -239,6 +181,9 @@ clean: rm -f cdist-*.tar.gz rm -f cdist-*.tar.gz.asc + # Temp files + rm -f *.tmp + distclean: clean rm -f cdist/version.py diff --git a/README b/README index a67e25e3..caf2dac8 100644 --- a/README +++ b/README @@ -3,4 +3,5 @@ cdist cdist is a usable configuration management system. -For the web documentation have a look at docs/web/. +For the web documentation have a look at https://www.cdi.st/ +or at docs/src for reStructuredText manual. diff --git a/bin/build-helper b/bin/build-helper index 0fea5071..04b7621b 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -76,33 +76,6 @@ case "$option" in "$0" test ;; - blog) - version=$1; shift - blogfile=$1; shift - dir=${blogfile%/*} - file=${blogfile##*/} - - - cat << eof > "$blogfile" -[[!meta title="Cdist $version released"]] - -Here's a short overview about the changes found in version ${version}: - -eof - - $0 changelog-changes "$version" >> "$blogfile" - - cat << eof >> "$blogfile" -For more information visit the [[cdist homepage|software/cdist]]. - -[[!tag cdist config unix]] -eof - cd "$dir" - git add "$file" - # Allow git commit to fail if there are no changes - git commit -m "cdist blog update: $version" "$blogfile" || true - ;; - ml-release) if [ $# -ne 1 ]; then echo "$0 ml-release version" >&2 @@ -324,13 +297,6 @@ eof # Publish git changes make pub - # publish man, speeches, website - if [ "$masterbranch" = yes ]; then - make web-release-all - else - make web-release-all-no-latest - fi - # Ensure that pypi release has the right version "$0" version @@ -351,6 +317,7 @@ eof cat << eof Manual steps post release: + - cdist-web - linkedin - hackernews - reddit diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index 9823dab5..c292280c 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -31,30 +31,13 @@ basedir=${0%/*}/../ # .freebsd - run as freebsd basename=${0##*/} run_as=${basename#*.} -case "$run_as" in - freebsd) - to_a=cdist-configuration-management - to_d=googlegroups.com - from_a=darko.poljak - from_d=gmail.com - ml_name="Darko Poljak" - ml_sig_name="Darko" - # vars for make - WEBDIR=../vcs/www.nico.schottelius.org - ;; - *) - to_a=cdist - to_d=l.schottelius.org - from_a=nico-cdist - from_d=schottelius.org - ml_name="Nico -telmich- Schottelius" - ml_sig_name="Nico" - - # vars for make - WEBDIR=$$HOME/vcs/www.nico.schottelius.org - ;; -esac +to_a=cdist-configuration-management +to_d=googlegroups.com +from_a=darko.poljak +from_d=gmail.com +ml_name="Darko Poljak" +ml_sig_name="Darko" # Change to checkout directory cd "$basedir" @@ -66,7 +49,6 @@ option=$1; shift case "$option" in print-make-vars) printf "helper: ${helper}\n" - printf "WEBDIR: ${WEBDIR}\n" ;; print-runas) printf "run_as: $run_as\n" @@ -117,33 +99,6 @@ case "$option" in "$0" test ;; - blog) - version=$1; shift - blogfile=$1; shift - dir=${blogfile%/*} - file=${blogfile##*/} - - - cat << eof > "$blogfile" -[[!meta title="Cdist $version released"]] - -Here's a short overview about the changes found in version ${version}: - -eof - - $0 changelog-changes "$version" >> "$blogfile" - - cat << eof >> "$blogfile" -For more information visit the [[cdist homepage|software/cdist]]. - -[[!tag cdist config unix]] -eof - cd "$dir" - git add "$file" - # Allow git commit to fail if there are no changes - git commit -m "cdist blog update: $version" "$blogfile" || true - ;; - ml-release) if [ $# -ne 1 ]; then echo "$0 ml-release version" >&2 @@ -159,7 +114,7 @@ eof cat << eof From: ${ml_name} <$from> To: cdist mailing list <$to> -Subject: cdist $version released +Subject: cdist $version has been released Hello .*, @@ -177,7 +132,7 @@ ${ml_sig_name} -- Automatisation at its best level. With cdist. eof - ) | /usr/sbin/sendmail -f "$from" "$to" + ) > mailinglist.tmp ;; release-git-tag) @@ -337,11 +292,11 @@ eof # Generate documentation (man and html) # First, clean old generated docs - make helper=${helper} WEBDIR=${WEBDIR} docs-clean - make helper=${helper} WEBDIR=${WEBDIR} docs + make helper=${helper} docs-clean + make helper=${helper} docs # Generate speeches (indirect check if they build) - make helper=${helper} WEBDIR=${WEBDIR} speeches + make helper=${helper} speeches ############################################################# # Everything green, let's do the release @@ -364,7 +319,7 @@ eof git push -u origin "${target_branch}" ;; *) - make helper=${helper} WEBDIR=${WEBDIR} pub + make helper=${helper} pub ;; esac @@ -372,23 +327,7 @@ eof "$0" version # Create and publish package for pypi - make helper=${helper} WEBDIR=${WEBDIR} pypi-release - - # publish man, speeches, website - if [ "$masterbranch" = yes ]; then - make helper=${helper} WEBDIR=${WEBDIR} web-release-all - else - make helper=${helper} WEBDIR=${WEBDIR} web-release-all-no-latest - fi - - case "$run_as" in - freebsd) - ;; - *) - # Archlinux release is based on pypi - make archlinux-release - ;; - esac + make helper=${helper} pypi-release # sign git tag printf "Enter upstream repository authentication token: " @@ -396,7 +335,15 @@ eof "$0" sign-git-release "${target_version}" "${token}" # Announce change on ML - make helper=${helper} WEBDIR=${WEBDIR} ml-release + make helper=${helper} ml-release + + cat << eof +Manual steps post release: + + - cdist-web + - twitter + +eof ;; test) @@ -441,7 +388,7 @@ eof ;; shellcheck) - make helper=${helper} WEBDIR=${WEBDIR} shellcheck + make helper=${helper} shellcheck printf "\\nPlease review shellcheck report.\\n" while true do diff --git a/docs/src/_static/cdist-logo.jpeg b/docs/src/_static/cdist-logo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9bfa25298bb427d56cece5b630beb2447b618c31 GIT binary patch literal 12560 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 literal 0 HcmV?d00001 diff --git a/docs/src/cdist-logo.png b/docs/src/_static/cdist-logo.png similarity index 100% rename from docs/src/cdist-logo.png rename to docs/src/_static/cdist-logo.png diff --git a/docs/web/cdist/pgp-key-EFD2AE4EC36B6901.asc b/docs/src/_static/pgp-key-EFD2AE4EC36B6901.asc similarity index 100% rename from docs/web/cdist/pgp-key-EFD2AE4EC36B6901.asc rename to docs/src/_static/pgp-key-EFD2AE4EC36B6901.asc diff --git a/docs/src/cdist-intro.rst b/docs/src/cdist-intro.rst deleted file mode 100644 index fad40fe5..00000000 --- a/docs/src/cdist-intro.rst +++ /dev/null @@ -1,15 +0,0 @@ -cdist - usable configuration management -======================================= - -.. image:: cdist-logo.png - :alt: cdist-logo - -cdist is a usable configuration management system. -It adheres to the KISS principle and -is being used in small up to enterprise grade environments. -cdist is an alternative to other configuration management systems like - -* `bcfg2 `_ -* `chef `_ -* `cfengine `_ -* `puppet `_. diff --git a/docs/src/cdist-os.rst b/docs/src/cdist-os.rst index 4f6b4820..a8e31226 100644 --- a/docs/src/cdist-os.rst +++ b/docs/src/cdist-os.rst @@ -1,16 +1,19 @@ -Supported Operating Systems +Supported operating systems =========================== cdist was tested or is know to run on at least -* `Archlinux `_ -* `Debian `_ -* `CentOS `_ -* `Fedora `_ +* `Alpine Linux `_ +* `Archlinux `_ +* `CentOS `_ +* `Debian `_ +* `Devuan `_ +* `Fedora `_ * `FreeBSD `_ -* `Gentoo `_ -* `Mac OS X `_ +* `Gentoo `_ +* `Mac OS X `_ +* `NetBSD `_ * `OpenBSD `_ -* `Redhat `_ -* `Ubuntu `_ -* `XenServer `_ +* `Redhat `_ +* `Ubuntu `_ +* `XenServer `_ diff --git a/docs/src/cdist-support.rst b/docs/src/cdist-support.rst index 2343500e..19afde2f 100644 --- a/docs/src/cdist-support.rst +++ b/docs/src/cdist-support.rst @@ -1,11 +1,9 @@ Support ------- -IRC -~~~ - -You can join the development ***IRC channel*** -`#cstar on irc.freenode.net `_. +Chat +~~~~ +Chat with us: `ungleich chat `_. Mailing list ~~~~~~~~~~~~ @@ -25,4 +23,4 @@ Commercial support ~~~~~~~~~~~~~~~~~~ You can request commercial support for cdist from -`my company `_. +`ungleich `_. diff --git a/docs/src/cdist-update.rst b/docs/src/cdist-upgrade.rst similarity index 99% rename from docs/src/cdist-update.rst rename to docs/src/cdist-upgrade.rst index e810d6e9..e57ed63c 100644 --- a/docs/src/cdist-update.rst +++ b/docs/src/cdist-upgrade.rst @@ -1,5 +1,5 @@ -How to update cdist -=================== +How to upgrade cdist +==================== Update the git installation --------------------------- diff --git a/docs/src/conf.py b/docs/src/conf.py index 8ed48324..78f9842c 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 = '2016, Darko Poljak' +copyright = 'ungleich GmbH 2019' # author = 'Darko Poljak' # The version info for the project you're documenting, acts as replacement for @@ -138,7 +138,7 @@ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The name of an image file (relative to this directory) to place at the top # of the sidebar. -# html_logo = None +html_logo = '_static/cdist-logo.jpeg' # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) @@ -150,6 +150,7 @@ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". # html_static_path = ['_static'] +html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied diff --git a/docs/src/index.rst b/docs/src/index.rst index af303f5b..95e44d52 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -1,20 +1,23 @@ -Welcome to cdist documentation -============================== +cdist - usable configuration management +======================================= + +cdist is a usable configuration management system. +It adheres to the KISS principle and +is being used in small up to enterprise grade environments. -Contents: .. toctree:: - :maxdepth: 2 + :maxdepth: 3 :glob: :numbered: + :hidden: - cdist-intro cdist-why + cdist-features cdist-os cdist-install - cdist-update + cdist-upgrade cdist-support - cdist-features cdist-quickstart cdist-real-world man1/cdist diff --git a/docs/web/cdist.mdwn b/docs/web/cdist.mdwn deleted file mode 100644 index 90af20cb..00000000 --- a/docs/web/cdist.mdwn +++ /dev/null @@ -1,21 +0,0 @@ -[[!meta title="cdist - usable configuration management"]] - -![cdist-logo](cdist-logo.png "cdist logo") - -cdist is a usable configuration management system. -It adheres to the KISS principle and -is being used in small up to enterprise grade environments. -cdist is an alternative to other configuration management systems like -[bcfg2](http://bcfg2.org/), -[chef](https://www.chef.sh/), -[cfengine](https://cfengine.com/) -and [puppet](https://puppet.com/). - - * [[Why should I use cdist?|why]] - * [[Documentation|documentation]] - * [[Supported Operating Systems|os]] - * [[Installation|install]] - * [[Update|update]] - * [[Support|support]] - -[[!tag cdist unix]] diff --git a/docs/web/cdist/cdist-logo.png b/docs/web/cdist/cdist-logo.png deleted file mode 100644 index 13c2792728d20511f18ae60df8524d68b8a35cbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1542 zcmV+h2Ko7kP)Px#22e~?MF0Q*|NsA`*`M72000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipS@ z0U8oZ%R(#w00o9gL_t(o!|j;OOC(1Wz^mIa(<@6fGKU5*AnRX5Vhb0Zp zl-0j^^}hPms}|z_>pi<{At%Dr`U@U4gF4RoGSKpzdV%|9@IftRZLXV9@rE>N@N!C~ zGe!OUp&qdMyVA_e*UFQ*nQ6FwG6UDY#;;ZQdr1m53*5jARMf$*1#sLK#5utjPU&db zU785>|Q;`jcYt&fW8y13Dv?GjzEFS5zgd^L_8Dcpp*UC7%Q|3g| zeW!0Xc2ln5Rr4S=Vw`9rom{QR%eaLoD99VfwGKs%e!wYXuc>Ro!YNg8JEj$j^K%vMI*!X+fZJ61zup&| z_&2@o@#j2c4Ow58Hv--l{9E;X!t)PThohc&SqQ&#?tli zeQ~q`w_7_Q4-|PvJ%@O73;v3uexPskGwxuUxYYml(wYAUI%ek9r9qEY?};s1j`9Ns zws+2%V_kFL`}_%&3B=6YnssgO7v^UEE^rn<`DuRG-WhWykyiNA+NRs7e#(n=#)dSo zC4b`2WX@hcQKUGP1Q;~i_~10#_Lg>}wnLWcfIX@<+++6!>FOsE(lNYg;o!>kuYLrZ zgn0Pmn(d&{8hK&l4S+j!SA~?-kZ(d{hS{KtRyo7mHqy$s_JuIA?hdVknB7 zLmcRLeo>TXD!t|!#KppS^(U1G?uTqIrW6TN&L%q)1U|fh!8$5_6|fyo5;wJD>?Nn8 z7@(SuyO_)`(2ft;4l8l7-_6;9W~(mlmj~#Vqtq{l($Q`rzu?yO%mX=fdC=B&2+U{e4Ydo2tmeVMoEvfXx48|#$#HqW zTvw#rm^=`@-JY`kV#Va)&A7P1?!T;r((*!4!$HtGcXKPzc`S^6g>{Se%ENDB0rpaV z5LWU)8vnI-KXJt}pCil*k@~kQ_nrqXYSH9EMl)|%efJ-1(-zZu5F_WnM!-h{74^xT z;0|clXTjlN%3T{{fFAO-|Ift!@>@-G2m|qxhyoK=0!BZA|iCn43h9NNJLMXkOv16dzyd&)Y5*|k+R=&8w!jnSNv6LK39 saY9X~U}r+kn~+= 3.2 - * SSH client - * Asciidoc and xsltproc (for building the manpages) - -### Target Hosts - - * /bin/sh: A posix like shell (for instance bash, dash, zsh) - * SSH server - -## Install cdist - -You can install cdist either from git or as a python package. - -### From git - -Cloning cdist from git gives you the advantage of having -a version control in place for development of your own stuff -immediately. - -To install cdist, execute the following commands: - - git clone https://github.com/ungleich/cdist.git - cd cdist - export PATH=$PATH:$(pwd -P)/bin - -From version 4.2.0 cdist tags and github releases are signed. -You can get GPG public key used for signing [here](/software/cdist/pgp-key-EFD2AE4EC36B6901.asc). - -#### Available versions in git - - * The active development takes place in the **master** branch - * The current stable version can be found in the **2.0** branch - * The upcoming stable version can be found in the **2.1** branch - -Other branches may be available for features or bugfixes, but they -may vanish at any point. To select a specific branch use - - # Generic code - git checkout -b origin/ - -So for instance if you want to use and stay with version 2.0, you can use - - git checkout -b 2.0 origin/2.0 - -#### Git Mirrors - -If the main site is down, you can acquire cdist from one of the following sites: - - * git://github.com/telmich/cdist.git ([github](https://github.com/telmich/cdist)) - * git://git.code.sf.net/p/cdist/code ([sourceforge](https://sourceforge.net/p/cdist/code)) - -#### Building and using documentation (man and html) - -If you want to build and use the documentation, run: - - make docs - -Documentation comes in two formats, man pages and full HTML -documentation. Documentation is built into distribution's -docs/dist directory. man pages are in docs/dist/man and -HTML documentation in docs/dist/html. - -If you want to use man pages, run: - - export MANPATH=$MANPATH:$(pwd -P)/docs/dist/man - -Or you can move manpages from docs/dist/man directory to some -other directory and add it to MANPATH. - -Full HTML documentation can be accessed at docs/dist/html/index.html. - -You can also build manpages for types in your ~/.cdist directory: - - make dotman - -Built manpages are now in docs/dist/man directory. If you have -some other custom .cdist directory, e.g. /opt/cdist then use: - - DOT_CDIST_PATH=/opt/cdist make dotman - - -### Python Package - -Cdist is available as a python package at -[PyPi](http://pypi.python.org/pypi/cdist/). You can install it using - - pip install cdist - -## Use cdist - -[[Dig into the documentation|documentation]] to get started with cdist! - -[[!tag cdist unix]] diff --git a/docs/web/cdist/os.mdwn b/docs/web/cdist/os.mdwn deleted file mode 100644 index 3677f52c..00000000 --- a/docs/web/cdist/os.mdwn +++ /dev/null @@ -1,18 +0,0 @@ -[[!meta title="Supported Operating Systems"]] - -cdist was tested or is know to run on at least - - * [Archlinux](http://www.archlinux.org/) - * [Debian](http://www.debian.org/) - * [CentOS](http://www.centos.org/) - * [Scientific](https://www.scientificlinux.org/) - * [Fedora](http://fedoraproject.org/) - * [FreeBSD](http://www.freebsd.org) - * [Gentoo](http://www.gentoo.org/) - * [Mac OS X](http://www.apple.com/macosx/) - * [OpenBSD](http://www.openbsd.org) - * [Redhat](http://www.redhat.com/) - * [Ubuntu](http://www.ubuntu.com/) - * [XenServer](http://www.citrix.com/xenserver/) - -[[!tag cdist unix]] diff --git a/docs/web/cdist/support.mdwn b/docs/web/cdist/support.mdwn deleted file mode 100644 index 4f92853b..00000000 --- a/docs/web/cdist/support.mdwn +++ /dev/null @@ -1,28 +0,0 @@ -## Support - -### IRC - -You can join the development ***IRC channel*** -[#cstar on irc.freenode.net](irc://irc.freenode.org/#cstar). - -### Mailing list - -Bug reports, questions, patches, etc. should be send to the -[cdist mailing list](https://groups.google.com/forum/#!forum/cdist-configuration-management). - -### Linkedin - -If you have an account -at [Linked in](http://www.linkedin.com/), -you can join the -[cdist group](http://www.linkedin.com/groups/cdist-configuration-management-3952797). - -### Chat -Chat with us: [ungleich chat](https://chat.ungleich.ch/channel/cdist). - -### Commercial support - -You can request commercial support for cdist from -[my company](http://www.ungleich.ch/english/). - -[[!tag cdist unix]] diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn deleted file mode 100644 index df4617bb..00000000 --- a/docs/web/cdist/update.mdwn +++ /dev/null @@ -1,158 +0,0 @@ -[[!meta title="How to update cdist"]] - -## Update The Git Installation - -To upgrade cdist in the current branch use - - git pull - - # Also update the manpages - ./build man - export MANPATH=$MANPATH:$(pwd -P)/doc/man - -If you stay on a version branche (i.e. 1.0, 1.1., ...), nothing should break. -The master branch on the other hand is the development branch and may not be -working, break your setup or eat the tree in your garden. - -### Safely upgrading to new versions - -To upgrade to **any** further cdist version, you can take the -following procedure to do a safe upgrade: - - # Create new branch to try out the update - git checkout -b upgrade_cdist - - # Get latest cdist version in git database - git fetch -v - - # see what will happen on merge - replace - # master with the branch you plan to merge - git diff upgrade_cdist..origin/master - - # Merge the new version - git merge origin/master - -Now you can ensure all custom types work with the new version. -Assume that you need to go back to an older version during -the migration/update, you can do so as follows: - - # commit changes - git commit -m ... - - # go back to original branch - git checkout master - -After that, you can go back and continue the upgrade: - - # git checkout upgrade_cdist - - -## Update The Python Package - -To upgrade to the lastet version do - - pip install --upgrade cdist - -## General Update Instructions - -### Updating from 3.0 to 3.1 - -The type **\_\_ssh_authorized_keys** now also manages existing keys, -not only the ones added by cdist. - -### Updating from 2.3 to 3.0 - -The **changed** attribute of objects has been removed. -Use [messaging](/software/cdist/man/3.0.0/man7/cdist-messaging.html) instead. - -### Updating from 2.2 to 2.3 - -No incompatibilities. - -### Updating from 2.1 to 2.2 - -Starting with 2.2, the syntax for requiring a singleton type changed: -Old format: - - require="__singleton_type/singleton" ... - -New format: - - require="__singleton_type" ... - -Internally the "singleton" object id was dropped to make life more easy. -You can probably fix your configuration by running the following code -snippet (currently untested, please report back if it works for you): - - find ~/.cdist/* -type f -exec sed -i 's,/singleton,,' {} \; - -### Updating from 2.0 to 2.1 - -Have a look at the update guide for [[2.0 to 2.1|2.0-to-2.1]]. - - * Type **\_\_package* and \_\_process** use --state **present** or **absent**. - The states **removed/installed** and **stopped/running** have been removed. - Support for the new states is already present in 2.0. - * Type **\_\_directory**: Parameter --parents and --recursive are now boolean - The old "yes/no" values need to be removed. - * Type **\_\_rvm_ruby**: Parameter --default is now boolean - The old "yes/no" values need to be removed. - * Type **\_\_rvm_gemset**: Parameter --default is now boolean - The old "yes/no" values need to be removed. - * Type **\_\_addifnosuchline** and **\_\_removeline** have been replaced by **\_\_line** - * The **conf** directory is now located at **cdist/conf**. - You need to migrate your types, explorers and manifests - manually to the new location. - * Replace the variable **\_\_self** by **\_\_object_name** - Support for the variable **\_\_object_name** is already present in 2.0. - * The types **\_\_autofs**, **\_\_autofs_map** and **\_\_autofs_reload** have been removed - (no maintainer, no users) - * Type **\_\_user**: Parameter --groups removed (use the new \_\_user_groups type) - * Type **\_\_ssh_authorized_key** has been replaced by more flexible type - **\_\_ssh_authorized_keys** - -### Updating from 1.7 to 2.0 - -* Ensure python (>= 3.2) is installed on the source host -* Use "cdist config host" instead of "cdist-deploy-to host" -* Use "cdist config -p host1 host2" instead of "cdist-mass-deploy" -* Use "cdist banner" for fun -* Use **\_\_object_name** instead of **\_\_self** in manifests - -### Updating from 1.6 to 1.7 - -* If you used the global explorer **hardware_type**, you need to change - your code to use **machine** instead. - -### Updating from 1.5 to 1.6 - -* If you used **\_\_package_apt --preseed**, you need to use the new - type **\_\_debconf_set_selections** instead. -* The **\_\_package** types accepted either --state deinstalled or - --state uninstaaled. Starting with 1.6, it was made consistently - to --state removed. - -### Updating from 1.3 to 1.5 - -No incompatibilities. - -### Updating from 1.2 to 1.3 - -Rename **gencode** of every type to **gencode-remote**. - -### Updating from 1.1 to 1.2 - -No incompatibilities. - -### Updating from 1.0 to 1.1 - -In 1.1 the type **\_\_file** was split into **\_\_directory**, **\_\_file** and -**\_\_link**. The parameter **--type** was removed from **\_\_file**. Thus you -need to replace **\_\_file** calls in your manifests: - - * Remove --type from all \_\_file calls - * If type was symlink, use \_\_link and --type symbolic - * If type was directory, use \_\_directory - - -[[!tag cdist unix]] diff --git a/docs/web/cdist/update/2.0-to-2.1.mdwn b/docs/web/cdist/update/2.0-to-2.1.mdwn deleted file mode 100644 index 3b5f5dc4..00000000 --- a/docs/web/cdist/update/2.0-to-2.1.mdwn +++ /dev/null @@ -1,118 +0,0 @@ -[[!meta title="Update Guide for 2.0 to 2.1"]] - -## Introduction - -When changing your installation from 2.0 to 2.1, there are -a lot of changes coming up. 2.1 is mainly a cleanup release, -which removes long time deprecated behaviour, but also makes -a lot of things more consistent and allows you to split off your types, -explorers and manifest to custom directories. - -This document will guide you to a successful update. - -## Preparation - -As for every software and system you use in production, you should first of -all make a backup of your data. To prevent any breakage, it is -recommended to create a new git branch to do the update on: - - % git checkout -b update_to_2.1 - -This also ensure that whenever you need to do a change in your -2.0 based tree, you can simply go back to that branch, apply the change -and configure your systems - independently of your update progress! - -Next fetch the latest upstream changes, I assume that -origin refers to one of the upstream mirrors (change origin if you use -another remote name for upstream cdist): - - % git fetch -v origin - -## Merge the changes - -Now try to merge upstream into the new branch. - - % git merge origin/2.1 - -Fix any conflicts that may have been occurred due to local changes -and then **git add** and *git commit** those changes. This should seldom -occur and if, it's mostly for people hacking on the cdist core. - -## Move "conf" directory - -One of the biggest changes in cdist 2.1 is that you can have multiple -**conf** directories: Indeed, the new default behaviour of cdist is to -search for conf directories - - * below the python module (cdist/conf in the source tree or in the installed location) - * at ~/.cdist/ (on conf suffix there) - -So you can now choose, where to store your types. - -### Integrate your conf/ back into the tree - -If you choose to store your types together with the upstream types, -you can just move all your stuff below **cdist/conf**: - - % git mv conf/type/* cdist/conf/type - % git mv conf/manifest/* cdist/conf/manifest - % git mv conf/explorer/* cdist/conf/explorer - % git commit -m "Re-Integrate my conf directory into cdist 2.1 tree" - -### Move your conf/ directory to ~/.cdist - -If you want to store your site specific -configuration outside of the cdist tree, you -can move your conf/ directory to your homedirectory ($HOME) under ~/.cdist: - - % mv conf ~/.cdist - % git rm -r conf - % git commit -m "Move my conf directory to ~/.cdist" - -It it still recommended to use a version control system like git in it: - - % cd ~/.cdist - % git init - % git add . - % git commit -m "Create new git repository containing my cdist configuration" - -## Test the migration - -Some of the types shipped with upstream were changed, so you may want to test -the result by running cdist on one of your staging target hosts: - - % ./bin/cdist config -v staging-host - -All incompatibilities are listed on the [[cdist update page|software/cdist/update]], -so you can browse through the list and update your configuration. - -## Final Cleanups - -When everything is tested, there are some cleanups to be done to finalise the update. - -### When continuing to keep conf/ in the tree - -You can then merge back your changes into the master tree and continue to work -as normal. - -### When using ~/.cdist - -If you decided to move your site specific code to ~/.cdist, you can now switch your -**master** branch or version branch to upstream directly. Assumnig you are in the -cdist directory, having your previous branch checked out, you can create a clean -state using the following commands: - - % upstream_branch=2.1 - % current_branch=$(git rev-parse --abbrev-ref HEAD) - % git checkout -b archive_my_own_tree - % git branch -D "$current_branch" - % git checkout -b "$current_branch" "origin/$upstream_branch" - -Afther these commands, your previous main branch is accessible at -**archive_my_own_tree** and your branch is now tracking upstream. - -## Questions? Critics? Hints? - -If you think this manual helped or misses some information, do not -hesitate to contact us on any of the usual ways (irc, mailinglist, -github issue tracker, ...). diff --git a/docs/web/cdist/why.mdwn b/docs/web/cdist/why.mdwn deleted file mode 100644 index f571555c..00000000 --- a/docs/web/cdist/why.mdwn +++ /dev/null @@ -1,69 +0,0 @@ -[[!meta title="Why should I use cdist?"]] - -[[!toc]] - -There are several motivations to use cdist, these -are probably the most popular ones. - -## Known language - -Cdist is being configured in -[shell script](https://en.wikipedia.org/wiki/Shell_script). -Shell script is used by UNIX system engineers for decades. -So when cdist is introduced, your staff does not need to learn a new -[DSL](https://en.wikipedia.org/wiki/Domain-specific_language) -or programming language. - -## Powerful language - -Not only is shell scripting widely known by system engineers, -but it is also a very powerful language. Here are some features -which make daily work easy: - - * Configuration can react dynamicly on explored values - * High level string manipulation (using sed, awk, grep) - * Conditional support (**if, case**) - * Loop support (**for, while**) - * Support for dependencies between cdist types - -## More than shell scripting - -If you compare regular shell scripting with cdist, there is one major -difference: When using cdist types, -the results are -[idempotent](https://en.wikipedia.org/wiki/Idempotence). -In practise that means it does not matter in which order you -call cdist types, the result is always the same. - -## Zero dependency configuration management - -Cdist requires very litte on a target system. Even better, -in almost all cases all dependencies are usually fulfilled. -Cdist does not require an agent or a high level programming -languages on the target host: it will run on any host that -has a **ssh server running** and a posix compatible shell -(**/bin/sh**). Compared to other configuration management systems, -it does not require to open up an additional port. - -## Push based distribution - -Cdist uses the push based model for configuration. In this -scenario, one (or more) computers connect the target hosts -and apply the configuration. That way the source host has -very little requirements: Cdist can even run on a sysadmin -notebook that is loosely connected to the network and has -limited amount of resources. - -Furthermore, from a security point of view, only one machine -needs access to the target hosts. No target hosts will ever -need to connect back to the source host, which contains the -full configuration. - -## Highly scalable - -If at some point you manage more hosts than can be handled from -a single source host, you can simply add more resources: Either -add more cores to one host or add hosts. -Cdist will utilise the given resources in parallel. - -[[!tag cdist unix]] From 2f93320627a996756a0375b2e9178f360ccea73c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 2 May 2019 19:37:01 +0200 Subject: [PATCH 1159/1332] Generating speeches is not part of cdist release Speeches should be generated on demand when needed and the cdist website should be updated. --- bin/build-helper | 3 --- bin/build-helper.freebsd | 3 --- 2 files changed, 6 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 04b7621b..bb5956b8 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -279,9 +279,6 @@ eof make docs-clean make docs - # Generate speeches (indirect check if they build) - make speeches - ############################################################# # Everything green, let's do the release diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd index c292280c..2a71a899 100755 --- a/bin/build-helper.freebsd +++ b/bin/build-helper.freebsd @@ -295,9 +295,6 @@ eof make helper=${helper} docs-clean make helper=${helper} docs - # Generate speeches (indirect check if they build) - make helper=${helper} speeches - ############################################################# # Everything green, let's do the release From d242f1e7588912364c5c5dd6d1595202d24bc42f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 4 May 2019 00:31:33 +0200 Subject: [PATCH 1160/1332] Unify build-helper scripts --- bin/build-helper | 89 +++++--- bin/build-helper.darko | 1 + bin/build-helper.freebsd | 427 --------------------------------------- 3 files changed, 63 insertions(+), 454 deletions(-) create mode 120000 bin/build-helper.darko delete mode 100755 bin/build-helper.freebsd diff --git a/bin/build-helper b/bin/build-helper index bb5956b8..0b2d5282 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2016-2019 Darko Poljak (darko.poljak at gmail.com) # # This file is part of cdist. # @@ -18,10 +19,36 @@ # along with cdist. If not, see . # # -# This file contains the heavy lifting found usually in the Makefile +# This file contains the heavy lifting found usually in the Makefile. # +# vars for make +helper=$0 + basedir=${0%/*}/../ +# run_as is used to check how the script is called (by $0 value) +# currently supported sufixes for $0 are: +# .darko - run as darko +basename=${0##*/} +run_as=${basename#*.} + +to_a=cdist-configuration-management +to_d=googlegroups.com +case "$run_as" in + darko) + from_a=darko.poljak + from_d=gmail.com + ml_name="Darko Poljak" + ml_sig_name="Darko" + ;; + *) + from_a=nico.schottelius + from_d=ungleich.ch + ml_name="Nico Schottelius" + ml_sig_name="Nico" + ;; +esac + # Change to checkout directory cd "$basedir" @@ -30,6 +57,12 @@ version=$(git describe) option=$1; shift case "$option" in + print-make-vars) + printf "helper: ${helper}\n" + ;; + print-runas) + printf "run_as: $run_as\n" + ;; changelog-changes) if [ "$#" -eq 1 ]; then start=$1 @@ -84,19 +117,14 @@ case "$option" in version=$1; shift - to_a=cdist - to_d=l.schottelius.org to=${to_a}@${to_d} - - from_a=nico-cdist - from_d=schottelius.org from=${from_a}@${from_d} ( cat << eof -From: Nico -telmich- Schottelius <$from> +From: ${ml_name} <$from> To: cdist mailing list <$to> -Subject: cdist $version released +Subject: cdist $version has been released Hello .*, @@ -108,15 +136,18 @@ eof cat << eof Cheers, - -Nico +${ml_sig_name} -- Automatisation at its best level. With cdist. eof - ) | /usr/sbin/sendmail -f "$from" "$to" - ;; + ) > mailinglist.tmp + if [ "$run_as" = "build-helper" ] + then + /usr/sbin/sendmail -f "$from" "$to" < mailinglist.tmp && rm -f mailinglist.tmp + fi + ;; release-git-tag) target_version=$($0 changelog-version) @@ -213,7 +244,6 @@ eof "https://code.ungleich.ch/api/v4/projects/${project}/repository/tags/${tag}/release" \ || exit 1 - # remove generated files (archive and asc) if [ $# -eq 2 ] then @@ -276,8 +306,8 @@ eof # Generate documentation (man and html) # First, clean old generated docs - make docs-clean - make docs + make helper=${helper} docs-clean + make helper=${helper} docs ############################################################# # Everything green, let's do the release @@ -292,16 +322,27 @@ eof fi # Publish git changes - make pub + if [ "$run_as" = "build-helper" ] + then + make helper=${helper} pub + else + # if we are not Nico :) then just push, no mirror + git push + # push also new branch and set up tracking + git push -u origin "${target_branch}" + fi # Ensure that pypi release has the right version "$0" version # Create and publish package for pypi - make pypi-release + make helper=${helper} pypi-release - # Archlinux release is based on pypi - make archlinux-release + if [ "$run_as" = "build-helper" ] + then + # Archlinux release is based on pypi + make helper=${helper} archlinux-release + fi # sign git tag printf "Enter upstream repository authentication token: " @@ -309,19 +350,13 @@ eof "$0" sign-git-release "${target_version}" "${token}" # Announce change on ML - make ml-release + make helper=${helper} ml-release cat << eof Manual steps post release: - - cdist-web - - linkedin - - hackernews - - reddit - twitter - eof - ;; test) @@ -366,7 +401,7 @@ eof ;; shellcheck) - make shellcheck + make helper=${helper} shellcheck printf "\\nPlease review shellcheck report.\\n" while true do diff --git a/bin/build-helper.darko b/bin/build-helper.darko new file mode 120000 index 00000000..1f3e3384 --- /dev/null +++ b/bin/build-helper.darko @@ -0,0 +1 @@ +build-helper \ No newline at end of file diff --git a/bin/build-helper.freebsd b/bin/build-helper.freebsd deleted file mode 100755 index 2a71a899..00000000 --- a/bin/build-helper.freebsd +++ /dev/null @@ -1,427 +0,0 @@ -#!/bin/sh -# -# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) -# 2016 Darko Poljak (darko.poljak 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 . -# -# -# This file contains the heavy lifting found usually in the Makefile -# - -# vars for make -helper=$0 - -basedir=${0%/*}/../ -# run_as is used to check how the script is called (by $0 value) -# currently supported sufixes for $0 are: -# .freebsd - run as freebsd -basename=${0##*/} -run_as=${basename#*.} - -to_a=cdist-configuration-management -to_d=googlegroups.com -from_a=darko.poljak -from_d=gmail.com -ml_name="Darko Poljak" -ml_sig_name="Darko" - -# Change to checkout directory -cd "$basedir" - -version=$(git describe) - -option=$1; shift - -case "$option" in - print-make-vars) - printf "helper: ${helper}\n" - ;; - print-runas) - printf "run_as: $run_as\n" - ;; - changelog-changes) - if [ "$#" -eq 1 ]; then - start=$1 - else - start="[[:digit:]]" - fi - - end="[[:digit:]]" - - awk -F: "BEGIN { start=0 } - { - if(start == 0) { - if (\$0 ~ /^$start/) { - start = 1 - } - } else { - if (\$0 ~ /^$end/) { - exit - } else { - print \$0 - } - } - }" "$basedir/docs/changelog" - ;; - - changelog-version) - # get version from changelog - grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/:.*//' - ;; - - check-date) - # verify date in changelog is today - date_today="$(date +%Y-%m-%d)" - date_changelog=$(grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/.*: //') - - if [ "$date_today" != "$date_changelog" ]; then - echo "Date in changelog is not today" - echo "Changelog: $date_changelog" - exit 1 - fi - ;; - - check-unittest) - "$0" test - ;; - - ml-release) - if [ $# -ne 1 ]; then - echo "$0 ml-release version" >&2 - exit 1 - fi - - version=$1; shift - - to=${to_a}@${to_d} - from=${from_a}@${from_d} - - ( - cat << eof -From: ${ml_name} <$from> -To: cdist mailing list <$to> -Subject: cdist $version has been released - -Hello .*, - -cdist $version has been released with the following changes: - -eof - - "$0" changelog-changes "$version" - cat << eof - -Cheers, - -${ml_sig_name} - --- -Automatisation at its best level. With cdist. -eof - ) > mailinglist.tmp - ;; - - release-git-tag) - target_version=$($0 changelog-version) - if git rev-parse --verify refs/tags/$target_version 2>/dev/null; then - echo "Tag for $target_version exists, aborting" - exit 1 - fi - printf "Enter tag description for ${target_version}: " - read tagmessage - - # setup for signed tags: - # gpg --fulL-gen-key - # gpg --list-secret-keys --keyid-format LONG - # git config --local user.signingkey - # for exporting pub key: - # gpg --armor --export > pubkey.asc - # gpg --output pubkey.gpg --export - # show tag with signature - # git show - # verify tag signature - # git tag -v - # - # gpg verify signature - # gpg --verify - # gpg --no-default-keyring --keyring --verify - # Ensure gpg-agent is running. - export GPG_TTY=$(tty) - gpg-agent - - git tag -s "$target_version" -m "$tagmessage" - git push --tags - ;; - - sign-git-release) - if [ $# -lt 2 ] - then - printf "usage: $0 sign-git-release TAG TOKEN [ARCHIVE]\n" - printf " if ARCHIVE is not specified then it is created\n" - exit 1 - fi - tag="$1" - if ! git rev-parse -q --verify "${tag}" >/dev/null 2>&1 - then - printf "Tag \"${tag}\" not found.\n" - exit 1 - fi - token="$2" - if [ $# -gt 2 ] - then - archivename="$3" - else - archivename="cdist-${tag}.tar" - git archive --prefix="cdist-${tag}/" -o "${archivename}" "${tag}" \ - || exit 1 - # make sure target version is generated - "$0" target-version - tar -x -f "${archivename}" || exit 1 - cp cdist/version.py "cdist-${tag}/cdist/version.py" || exit 1 - tar -c -f "${archivename}" "cdist-${tag}/" || exit 1 - rm -r -f "cdist-${tag}/" - gzip "${archivename}" || exit 1 - archivename="${archivename}.gz" - fi - gpg --armor --detach-sign "${archivename}" || exit 1 - - project="ungleich-public%2Fcdist" - sed_cmd='s/^.*"markdown":"\([^"]*\)".*$/\1/' - - # upload archive - response_archive=$(curl -f -X POST \ - --http1.1 \ - -H "PRIVATE-TOKEN: ${token}" \ - -F "file=@${archivename}" \ - "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ - | sed "${sed_cmd}") || exit 1 - - # upload archive signature - response_archive_sig=$(curl -f -X POST \ - --http1.1 \ - -H "PRIVATE-TOKEN: ${token}" \ - -F "file=@${archivename}.asc" \ - "https://code.ungleich.ch/api/v4/projects/${project}/uploads" \ - | sed "${sed_cmd}") || exit 1 - - # make release - changelog=$("$0" changelog-changes "$1" | sed 's/^[[:space:]]*//') - release_notes=$( - printf "Release %s\n\n%s\n\n%s\n\n**Changelog**\n\n%s\n" \ - "${tag}" "${response_archive}" "${response_archive_sig}" "${changelog}" - ) - curl -f -X POST \ - -H "PRIVATE-TOKEN: ${token}" \ - -F "description=${release_notes}" \ - "https://code.ungleich.ch/api/v4/projects/${project}/repository/tags/${tag}/release" \ - || exit 1 - - # remove generated files (archive and asc) - if [ $# -eq 2 ] - then - rm -f "${archivename}" - fi - rm -f "${archivename}.asc" - ;; - - release) - set -e - target_version=$($0 changelog-version) - target_branch=$($0 version-branch) - - echo "Beginning release process for $target_version" - - # First check everything is sane - "$0" check-date - "$0" check-unittest - "$0" check-pycodestyle - "$0" shellcheck - - # Generate version file to be included in packaging - "$0" target-version - - # Ensure the git status is clean, else abort - if ! git diff-index --name-only --exit-code HEAD ; then - echo "Unclean tree, see files above, aborting" - exit 1 - fi - - # Ensure we are on the master branch - masterbranch=yes - if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ]; then - echo "Releases are happening from the master branch, aborting" - - echo "Enter the magic word to release anyway" - read magicword - - if [ "$magicword" = "iknowwhatido" ]; then - masterbranch=no - else - exit 1 - fi - fi - - if [ "$masterbranch" = yes ]; then - # Ensure version branch exists - if ! git rev-parse --verify refs/heads/$target_branch 2>/dev/null; then - git branch "$target_branch" - fi - - # Merge master branch into version branch - git checkout "$target_branch" - git merge master - fi - - # Verify that after the merge everything works - "$0" check-date - "$0" check-unittest - - # Generate documentation (man and html) - # First, clean old generated docs - make helper=${helper} docs-clean - make helper=${helper} docs - - ############################################################# - # Everything green, let's do the release - - # Tag the current commit - "$0" release-git-tag - - # Also merge back the version branch - if [ "$masterbranch" = yes ]; then - git checkout master - git merge "$target_branch" - fi - - # Publish git changes - case "$run_as" in - freebsd) - # if we are not Nico :) then just push, no mirror - git push - # push also new branch and set up tracking - git push -u origin "${target_branch}" - ;; - *) - make helper=${helper} pub - ;; - esac - - # Ensure that pypi release has the right version - "$0" version - - # Create and publish package for pypi - make helper=${helper} pypi-release - - # sign git tag - printf "Enter upstream repository authentication token: " - read token - "$0" sign-git-release "${target_version}" "${token}" - - # Announce change on ML - make helper=${helper} ml-release - - cat << eof -Manual steps post release: - - - cdist-web - - twitter - -eof - ;; - - test) - export PYTHONPATH="$(pwd -P)" - - if [ $# -lt 1 ]; then - python3 -m cdist.test - else - python3 -m unittest "$@" - fi - ;; - - test-remote) - export PYTHONPATH="$(pwd -P)" - python3 -m cdist.test.exec.remote - ;; - - pycodestyle|pep8) - pycodestyle "${basedir}" "${basedir}/scripts/cdist" | less - ;; - - check-pycodestyle) - "$0" pycodestyle - printf "\\nPlease review pycodestyle report.\\n" - while true - do - echo "Continue (yes/no)?" - any= - read any - case "$any" in - yes) - break - ;; - no) - exit 1 - ;; - *) - echo "Please answer with 'yes' or 'no' explicitly." - ;; - esac - done - ;; - - shellcheck) - make helper=${helper} shellcheck - printf "\\nPlease review shellcheck report.\\n" - while true - do - echo "Continue (yes/no)?" - any= - read any - case "$any" in - yes) - break - ;; - no) - exit 1 - ;; - *) - echo "Please answer with 'yes' or 'no' explicitly." - ;; - esac - done - ;; - - version-branch) - "$0" changelog-version | cut -d. -f '1,2' - ;; - - version) - echo "VERSION = \"$(git describe)\"" > cdist/version.py - ;; - - target-version) - target_version=$($0 changelog-version) - echo "VERSION = \"${target_version}\"" > cdist/version.py - ;; - - *) - echo "Unknown helper target $@ - aborting" - exit 1 - ;; - -esac From 513fde1cc1fcc612514cefaf18fd0822095c92e9 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 4 May 2019 10:51:10 +0200 Subject: [PATCH 1161/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index d367ed47..2e1df3d5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,9 @@ next: * Build: Update due to migration to code.ungleich.ch (Darko Poljak) * Documentation: Update due to migration to code.ungleich.ch (Darko Poljak) * Core: Detect and report dependency cycle as soon as possible (Darko Poljak) + * Core, documentation: Release -j/--jobs option, i.e. make it non-beta (Darko Poljak) + * Documentation: Update due to new cdist website (Darko Poljak) + * Build: Update due to new cdist website (Darko Poljak) 4.11.1: 2019-04-22 * Core: Improve explorer error reporting (Darko Poljak) From 10a29ca9e6173b5843aab6b45143b4f7c343d401 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 5 May 2019 00:02:51 +0200 Subject: [PATCH 1162/1332] Fix pycodestyle issue --- cdist/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index 4e226b3a..bc05a28c 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -48,7 +48,7 @@ def graph_check_cycle(graph): for node in graph: # Cycle path. path = [node] - has_cycle = _graph_dfs_cycle( graph, node, path) + has_cycle = _graph_dfs_cycle(graph, node, path) if has_cycle: return has_cycle, path return False, None From aad6c341780669c0c6ce26aae99259669f9f839b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 4 May 2019 23:30:50 +0200 Subject: [PATCH 1163/1332] Release 5.0.0 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 2e1df3d5..d6251523 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +5.0.0: 2019-05-05 * Type __zypper_service: Fix spelling error in manpage (Dmitry Bogatov) * Explorer init: Add support for OpenBSD (sideeffect42) * Type __postgres_database: Run psql with -w (no-password) (sideeffect42) From 4d75a05e3595e2bcfa96c461d8025cc92babf7f3 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 5 May 2019 10:31:23 +0200 Subject: [PATCH 1164/1332] Rm redundant tag description from rel notes --- bin/build-helper | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 0b2d5282..009e96ff 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -235,8 +235,8 @@ eof # make release changelog=$("$0" changelog-changes "$1" | sed 's/^[[:space:]]*//') release_notes=$( - printf "Release %s\n\n%s\n\n%s\n\n**Changelog**\n\n%s\n" \ - "${tag}" "${response_archive}" "${response_archive_sig}" "${changelog}" + printf "%s\n\n%s\n\n**Changelog**\n\n%s\n" \ + "${response_archive}" "${response_archive_sig}" "${changelog}" ) curl -f -X POST \ -H "PRIVATE-TOKEN: ${token}" \ From 735f57b3a032fad842c9d4306080b5d7a4c53a38 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 5 May 2019 17:55:02 +0200 Subject: [PATCH 1165/1332] Add 'Perils of CDIST_ORDER_DEPENDENCY' sub-section --- docs/src/cdist-best-practice.rst | 92 ++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/docs/src/cdist-best-practice.rst b/docs/src/cdist-best-practice.rst index a99ba88e..7a1255d6 100644 --- a/docs/src/cdist-best-practice.rst +++ b/docs/src/cdist-best-practice.rst @@ -224,3 +224,95 @@ in the repository for such content: It allows you to easily distinguish what is used by cdist and what is not and also to store all important files in one repository. + + +Perils of CDIST_ORDER_DEPENDENCY +-------------------------------- +With CDIST_ORDER_DEPENDENCY all types are executed in the order in which they +are created in the manifest. The current created object automatically depends +on the previously created object. + +It essentially helps you to build up blocks of code that build upon each other +(like first creating the directory xyz than the file below the directory). + +This can be helpful, but it can also be the source of *evil*. + +Let's see an example. Suppose you have special init manifest where among other +things you are assuring that remote host has packages `sudo` and `curl` +installed. + +**init1** + +.. code-block:: sh + + CDIST_ORDER_DEPENDENCY=1 + export CDIST_ORDER_DEPENDENCY + + for p in sudo curl + do + __package "${p}" + done + +Then you have some other special init manifest where among other things you are +assuring `sudo` package is installed. + +**init2** + +.. code-block:: sh + + CDIST_ORDER_DEPENDENCY=1 + export CDIST_ORDER_DEPENDENCY + + __package sudo + +Then you have third init manifest where you combine those two init manifests, +by including them: + +**init** + +.. code-block:: sh + + sh -e "$__manifest/init1" + sh -e "$__manifest/init2" + +The resulting init manifest is then equal to: + +.. code-block:: sh + + CDIST_ORDER_DEPENDENCY=1 + export CDIST_ORDER_DEPENDENCY + + for p in sudo curl + do + __package "${p}" + done + + CDIST_ORDER_DEPENDENCY=1 + export CDIST_ORDER_DEPENDENCY + + __package sudo + +In the end you get the following dependencies: + +* `__package/curl` depends on `__package/sudo` +* `__package/sudo` depends on `__package/curl` + +And here you have a circular dependency! + +In the real world manifest can be quite complex, dependencies can become +complicated and circual dependencies are not so obvious. Resolving it can +become cumbersome. + +**Practical solution?** + +Instead of managing complex init manifests you can write custom types. +Each custom type can do one thing, it has well defined dependencies that will +not leak into init manifest. In custom type you can also add special explorers +and gencode. + +Then, in init manifest you combine your complex types. It is: + +* cleaner +* easier to follow +* easier to maintain +* easier to debug. From 28082c710aa02a1861a4396513469ecfa7ef2d4f Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 6 May 2019 11:11:10 +0200 Subject: [PATCH 1166/1332] Add refs to perils of CDIST_ORDER_DEPENDENCY --- docs/src/cdist-manifest.rst | 2 ++ docs/src/cdist-reference.rst.sh | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/src/cdist-manifest.rst b/docs/src/cdist-manifest.rst index 0e266943..4dd3e74b 100644 --- a/docs/src/cdist-manifest.rst +++ b/docs/src/cdist-manifest.rst @@ -163,6 +163,8 @@ automatically depends on the previously created object. It essentially helps you to build up blocks of code that build upon each other (like first creating the directory xyz than the file below the directory). +Read also about `perils of CDIST_ORDER_DEPENDENCY `_. + Overrides --------- diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index 59ce018b..2c9c7b40 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -323,6 +323,7 @@ CDIST_OVERRIDE CDIST_ORDER_DEPENDENCY Create dependencies based on the execution order (see \`cdist manifest \`_). + Read also about \`perils of CDIST_ORDER_DEPENDENCY \`_. CDIST_REMOTE_EXEC Use this command for remote execution (should behave like ssh). From 02eb6c75a7979eb2fa1ec2b4921ab9fafe582edd Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 6 May 2019 17:11:23 +0200 Subject: [PATCH 1167/1332] Add 'CDIST_ORDER_DEPENDENCY kills parallelization' --- docs/src/cdist-best-practice.rst | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/docs/src/cdist-best-practice.rst b/docs/src/cdist-best-practice.rst index 7a1255d6..a91f2cc0 100644 --- a/docs/src/cdist-best-practice.rst +++ b/docs/src/cdist-best-practice.rst @@ -237,6 +237,10 @@ It essentially helps you to build up blocks of code that build upon each other This can be helpful, but it can also be the source of *evil*. + +CDIST_ORDER_DEPENDENCY easily causes unobvious dependency cycles +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Let's see an example. Suppose you have special init manifest where among other things you are assuring that remote host has packages `sudo` and `curl` installed. @@ -316,3 +320,44 @@ Then, in init manifest you combine your complex types. It is: * easier to follow * easier to maintain * easier to debug. + + +CDIST_ORDER_DEPENDENCY kills parallelization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Suppose you have defined CDIST_ORDER_DEPENDENCY and then, among other things, +you specify creation of three, by nature independent, files. + +**init** + +.. code-block:: sh + + CDIST_ORDER_DEPENDENCY=1 + export CDIST_ORDER_DEPENDENCY + + ... + __file /tmp/file1 + __file /tmp/file2 + __file /tmp/file3 + ... + +Due to defined CDIST_ORDER_DEPENDENCY cdist will execute them in specified order. +It is better to use CDIST_ORDER_DEPENDENCY in well defined blocks: + +**init** + +.. code-block:: sh + + CDIST_ORDER_DEPENDENCY=1 + export CDIST_ORDER_DEPENDENCY + ... + unset CDIST_ORDER_DEPENDENCY + + __file /tmp/file1 + __file /tmp/file2 + __file /tmp/file3 + + CDIST_ORDER_DEPENDENCY=1 + export CDIST_ORDER_DEPENDENCY + ... + unset CDIST_ORDER_DEPENDENCY From d696a55879b74eac091e338c95dbe5b144c8054c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 6 May 2019 17:13:36 +0200 Subject: [PATCH 1168/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index d6251523..40cb1f83 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Documentation: Add 'Perils of CDIST_ORDER_DEPENDENCY' sub-section (Darko Poljak) + 5.0.0: 2019-05-05 * Type __zypper_service: Fix spelling error in manpage (Dmitry Bogatov) * Explorer init: Add support for OpenBSD (sideeffect42) From 4f40c6ac656413cb6664809c299e1021430d13d0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 7 May 2019 18:16:54 +0200 Subject: [PATCH 1169/1332] Re-arrange Makefile and build-helper script Maintainers should use build-helper script. End users should use Makefile, which contains targets that can be run on pure source (without git repository). --- .gitattributes | 2 + Makefile | 158 ++++--------------- README-maintainers | 4 + bin/build-helper | 311 +++++++++++++++++++++++++++++-------- bin/build-helper.darko | 1 - docs/changelog | 1 + docs/src/cdist-install.rst | 19 ++- 7 files changed, 296 insertions(+), 200 deletions(-) create mode 100644 README-maintainers delete mode 120000 bin/build-helper.darko diff --git a/.gitattributes b/.gitattributes index aeaab8b9..45c10d7b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,5 @@ docs/speeches export-ignore docs/video export-ignore docs/src/man7 export-ignore +bin/build-helper export-ignore +README-maintainers export-ignore diff --git a/Makefile b/Makefile index 099812e2..b739ab1f 100644 --- a/Makefile +++ b/Makefile @@ -18,25 +18,27 @@ # # -helper=./bin/build-helper +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo "man build only man user documentation" + @echo "html build only html user documentation" + @echo "docs build both man and html user documentation" + @echo "dotman build man pages for types in your ~/.cdist directory" + @echo "speeches build speeches pdf files" + @echo "install install in the system site-packages directory" + @echo "install-user install in the user site-packages directory" + @echo "docs-clean clean documentation" + @echo "clean clean" DOCS_SRC_DIR=docs/src SPEECHDIR=docs/speeches TYPEDIR=cdist/conf/type -CHANGELOG_VERSION=$(shell $(helper) changelog-version) -CHANGELOG_FILE=docs/changelog - -PYTHON_VERSION=cdist/version.py - SPHINXM=make -C $(DOCS_SRC_DIR) man SPHINXH=make -C $(DOCS_SRC_DIR) html SPHINXC=make -C $(DOCS_SRC_DIR) clean -SHELLCHECKCMD=shellcheck -s sh -f gcc -x -# Skip SC2154 for variables starting with __ since such variables are cdist -# environment variables. -SHELLCHECK_SKIP=grep -v ': __.*is referenced but not assigned.*\[SC2154\]' ################################################################################ # Manpages # @@ -61,11 +63,16 @@ DOCSREFSH=$(DOCS_SRC_DIR)/cdist-reference.rst.sh $(DOCSREF): $(DOCSREFSH) $(DOCSREFSH) +version: + @[ -f "cdist/version.py" ] || { \ + printf "Missing 'cdist/version.py', please generate it first.\n" && exit 1; \ + } + # Manpages #3: generic part -man: $(MANTYPES) $(DOCSREF) $(PYTHON_VERSION) +man: version $(MANTYPES) $(DOCSREF) $(SPHINXM) -html: $(MANTYPES) $(DOCSREF) $(PYTHON_VERSION) +html: version $(MANTYPES) $(DOCSREF) $(SPHINXH) docs: man html @@ -85,7 +92,7 @@ DOTMANTYPES=$(subst /man.rst,.rst,$(DOTMANTYPEPREFIX)) $(DOTMAN7DSTDIR)/cdist-type%.rst: $(DOTTYPEDIR)/%/man.rst ln -sf "$^" $@ -dotman: $(DOTMANTYPES) +dotman: version $(DOTMANTYPES) $(SPHINXM) ################################################################################ @@ -103,132 +110,25 @@ $(SPEECHDIR)/%.pdf: $(SPEECHDIR)/%.tex speeches: $(SPEECHES) ################################################################################ -# Release: Mailinglist +# Misc # -ML_FILE=.lock-ml - -# Only send mail once - lock until new changelog things happened -$(ML_FILE): $(CHANGELOG_FILE) - $(helper) ml-release $(CHANGELOG_VERSION) - touch $@ - -ml-release: $(ML_FILE) - - -################################################################################ -# pypi -# -PYPI_FILE=.pypi-release -$(PYPI_FILE): man $(PYTHON_VERSION) - python3 setup.py sdist upload - touch $@ - -pypi-release: $(PYPI_FILE) -################################################################################ -# archlinux -# -ARCHLINUX_FILE=.lock-archlinux -ARCHLINUXTAR=cdist-$(CHANGELOG_VERSION)-1.src.tar.gz - -$(ARCHLINUXTAR): PKGBUILD - umask 022; mkaurball - -PKGBUILD: PKGBUILD.in $(PYTHON_VERSION) - ./PKGBUILD.in $(CHANGELOG_VERSION) - -$(ARCHLINUX_FILE): $(ARCHLINUXTAR) $(PYTHON_VERSION) - burp -c system $(ARCHLINUXTAR) - touch $@ - -archlinux-release: $(ARCHLINUX_FILE) - -################################################################################ -# Release -# - -$(PYTHON_VERSION) version: .git/refs/heads/master - $(helper) version - -# Code that is better handled in a shell script -check-%: - $(helper) $@ - -release: - $(helper) $@ - -################################################################################ -# Cleanup -# - -clean: +clean: docs-clean rm -f $(DOCS_SRC_DIR)/cdist-reference.rst find "$(DOCS_SRC_DIR)" -mindepth 2 -type l \ | xargs rm -f - make -C $(DOCS_SRC_DIR) clean - find * -name __pycache__ | xargs rm -rf - # Archlinux - rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz - rm -rf pkg/ src/ - - rm -f MANIFEST PKGBUILD - rm -rf dist/ - - # Signed release - rm -f cdist-*.tar.gz - rm -f cdist-*.tar.gz.asc - - # Temp files - rm -f *.tmp - -distclean: clean - rm -f cdist/version.py + # distutils + rm -rf ./build ################################################################################ -# Misc +# install # -# The pub is Nico's "push to all git remotes" way ("make pub") -pub: - git push --mirror +install: + python3 setup.py install -test: - $(helper) $@ - -test-remote: - $(helper) $@ - -pycodestyle pep8: - $(helper) $@ - -shellcheck-global-explorers: - @find cdist/conf/explorer -type f -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 - -shellcheck-type-explorers: - @find cdist/conf/type -type f -path "*/explorer/*" -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 - -shellcheck-manifests: - @find cdist/conf/type -type f -name manifest -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 - -shellcheck-local-gencodes: - @find cdist/conf/type -type f -name gencode-local -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 - -shellcheck-remote-gencodes: - @find cdist/conf/type -type f -name gencode-remote -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 - -shellcheck-scripts: - @$(SHELLCHECKCMD) scripts/cdist-dump || exit 0 - -shellcheck-gencodes: shellcheck-local-gencodes shellcheck-remote-gencodes - -shellcheck-types: shellcheck-type-explorers shellcheck-manifests shellcheck-gencodes - -shellcheck: shellcheck-global-explorers shellcheck-types shellcheck-scripts - -shellcheck-type-files: - @find cdist/conf/type -type f -path "*/files/*" -exec $(SHELLCHECKCMD) {} + | $(SHELLCHECK_SKIP) || exit 0 - -shellcheck-with-files: shellcheck shellcheck-type-files +install-user: + python3 setup.py install --user diff --git a/README-maintainers b/README-maintainers new file mode 100644 index 00000000..af57f475 --- /dev/null +++ b/README-maintainers @@ -0,0 +1,4 @@ +Maintainers should use ./bin/build-helper script. + +Makefile is intended for end users. It can be used for non-maintaining +targets that can be run from pure source (without git repository). diff --git a/bin/build-helper b/bin/build-helper index 009e96ff..bba44ded 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -22,47 +22,101 @@ # This file contains the heavy lifting found usually in the Makefile. # -# vars for make -helper=$0 +usage() { + printf "usage: %s TARGET [RUN-AS] + Available targets: + print-runas + changelog-changes + changelog-version + check-date + check-unittest + ml-release + archlinux-release + pypi-release + release-git-tag + sign-git-release + release + test + test-remote + pycodestyle + pep8 + check-pycodestyle + shellcheck-global-explorers + shellcheck-type-explorers + shellcheck-manifests + shellcheck-local-gencodes + shellcheck-remote-gencodes + shellcheck-scripts + shellcheck-gencodes + shellcheck-types + shellcheck + shellcheck-type-files + shellcheck-with-files + shellcheck-build-helper + check-shellcheck + version-branch + version + target-version + clean + distclean + Run as: + nico + darko - default, if not specified\n" "$1" +} -basedir=${0%/*}/../ -# run_as is used to check how the script is called (by $0 value) -# currently supported sufixes for $0 are: -# .darko - run as darko -basename=${0##*/} -run_as=${basename#*.} +basename="${0##*/}" + +if [ $# -lt 1 ] +then + usage "${basename}" + exit 1 +fi + +option=$1; shift +if [ $# -ge 1 ] +then + run_as="$1" +else + run_as="darko" +fi -to_a=cdist-configuration-management -to_d=googlegroups.com case "$run_as" in - darko) + nico) + from_a=nico.schottelius + from_d=ungleich.ch + ml_name="Nico Schottelius" + ml_sig_name="Nico" + ;; + darko|'') from_a=darko.poljak from_d=gmail.com ml_name="Darko Poljak" ml_sig_name="Darko" ;; *) - from_a=nico.schottelius - from_d=ungleich.ch - ml_name="Nico Schottelius" - ml_sig_name="Nico" + printf "Unsupported RUN-AS value: '%s'.\n" "${run_as}" >&2 + usage "${basename}" + exit 1 ;; esac +SHELLCHECKCMD="shellcheck -s sh -f gcc -x" +# Skip SC2154 for variables starting with __ since such variables are cdist +# environment variables. +SHELLCHECK_SKIP=': __.*is referenced but not assigned.*\[SC2154\]' + +to_a="cdist-configuration-management" +to_d="googlegroups.com" + # Change to checkout directory +basedir="${0%/*}/../" cd "$basedir" -version=$(git describe) - -option=$1; shift - case "$option" in - print-make-vars) - printf "helper: ${helper}\n" - ;; print-runas) - printf "run_as: $run_as\n" + printf "run_as: '%s'\n" "$run_as" ;; + changelog-changes) if [ "$#" -eq 1 ]; then start=$1 @@ -99,8 +153,8 @@ case "$option" in date_changelog=$(grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/.*: //') if [ "$date_today" != "$date_changelog" ]; then - echo "Date in changelog is not today" - echo "Changelog: $date_changelog" + printf "Date in changelog is not today\n" + printf "Changelog date: %s\n" "${date_changelog}" exit 1 fi ;; @@ -111,10 +165,15 @@ case "$option" in ml-release) if [ $# -ne 1 ]; then - echo "$0 ml-release version" >&2 + printf "%s ml-release version\n" "$0" >&2 exit 1 fi + # Send mail only once - lock until new changelog things happened. + [ ! -f .lock-ml ] && touch .lock-ml + x=$(find 'docs' -name changelog -type f -newer .lock-ml) + [ -z "${x}" ] && exit 0 + version=$1; shift to=${to_a}@${to_d} @@ -143,20 +202,45 @@ Automatisation at its best level. With cdist. eof ) > mailinglist.tmp - if [ "$run_as" = "build-helper" ] + if [ "$run_as" = "nico" ] then /usr/sbin/sendmail -f "$from" "$to" < mailinglist.tmp && rm -f mailinglist.tmp fi + + touch .lock-ml + ;; + + archlinux-release) + if [ $# -ne 1 ]; then + printf "%s archlinux-release version\n" "$0" >&2 + exit 1 + fi + version=$1; shift + + ARCHLINUXTAR="cdist-${version}-1.src.tar.gz" + ./PKGBUILD.in "${version}" + umask 022 + mkaurball + burp -c system "${ARCHLINUXTAR}" + ;; + + pypi-release) + # Ensure that pypi release has the right version + "$0" version + + make docs-clean + make docs + python3 setup.py sdist upload ;; release-git-tag) target_version=$($0 changelog-version) - if git rev-parse --verify refs/tags/$target_version 2>/dev/null; then - echo "Tag for $target_version exists, aborting" + if git rev-parse --verify "refs/tags/${target_version}" 2>/dev/null; then + printf "Tag for %s exists, aborting\n" "${target_version}" exit 1 fi - printf "Enter tag description for ${target_version}: " - read tagmessage + printf "Enter tag description for %s: " "${target_version}" + read -r tagmessage # setup for signed tags: # gpg --fulL-gen-key @@ -174,7 +258,8 @@ eof # gpg --verify # gpg --no-default-keyring --keyring --verify # Ensure gpg-agent is running. - export GPG_TTY=$(tty) + GPG_TTY=$(tty) + export GPG_TTY gpg-agent git tag -s "$target_version" -m "$tagmessage" @@ -184,14 +269,14 @@ eof sign-git-release) if [ $# -lt 2 ] then - printf "usage: $0 sign-git-release TAG TOKEN [ARCHIVE]\n" + printf "usage: %s sign-git-release TAG TOKEN [ARCHIVE]\n" "$0" printf " if ARCHIVE is not specified then it is created\n" exit 1 fi tag="$1" if ! git rev-parse -q --verify "${tag}" >/dev/null 2>&1 then - printf "Tag \"${tag}\" not found.\n" + printf "Tag \"%s\" not found.\n" "${tag}" exit 1 fi token="$2" @@ -257,30 +342,30 @@ eof target_version=$($0 changelog-version) target_branch=$($0 version-branch) - echo "Beginning release process for $target_version" + printf "Beginning release process for %s\n" "${target_version}" # First check everything is sane "$0" check-date "$0" check-unittest "$0" check-pycodestyle - "$0" shellcheck + "$0" check-shellcheck # Generate version file to be included in packaging "$0" target-version # Ensure the git status is clean, else abort if ! git diff-index --name-only --exit-code HEAD ; then - echo "Unclean tree, see files above, aborting" + printf "Unclean tree, see files above, aborting.\n" exit 1 fi # Ensure we are on the master branch masterbranch=yes if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ]; then - echo "Releases are happening from the master branch, aborting" + printf "Releases are happening from the master branch, aborting.\n" - echo "Enter the magic word to release anyway" - read magicword + printf "Enter the magic word to release anyway:" + read -r magicword if [ "$magicword" = "iknowwhatido" ]; then masterbranch=no @@ -291,7 +376,7 @@ eof if [ "$masterbranch" = yes ]; then # Ensure version branch exists - if ! git rev-parse --verify refs/heads/$target_branch 2>/dev/null; then + if ! git rev-parse --verify "refs/heads/${target_branch}" 2>/dev/null; then git branch "$target_branch" fi @@ -306,8 +391,8 @@ eof # Generate documentation (man and html) # First, clean old generated docs - make helper=${helper} docs-clean - make helper=${helper} docs + make docs-clean + make docs ############################################################# # Everything green, let's do the release @@ -322,35 +407,33 @@ eof fi # Publish git changes - if [ "$run_as" = "build-helper" ] - then - make helper=${helper} pub - else + # if you want to have mirror locally then uncomment this support + # if [ "$run_as" = "nico" ] + # then + # git push --mirror + # else # if we are not Nico :) then just push, no mirror git push # push also new branch and set up tracking git push -u origin "${target_branch}" - fi - - # Ensure that pypi release has the right version - "$0" version + # fi # Create and publish package for pypi - make helper=${helper} pypi-release + "$0" pypi-release - if [ "$run_as" = "build-helper" ] + if [ "$run_as" = "nico" ] then # Archlinux release is based on pypi - make helper=${helper} archlinux-release + "$0" archlinux-release fi # sign git tag printf "Enter upstream repository authentication token: " - read token + read -r token "$0" sign-git-release "${target_version}" "${token}" # Announce change on ML - make helper=${helper} ml-release + "$0" ml-release "${target_version}" cat << eof Manual steps post release: @@ -360,7 +443,14 @@ eof ;; test) - export PYTHONPATH="$(pwd -P)" + if [ ! -f "cdist/version.py" ] + then + printf "cdist/version.py is missing, generate it first.\n" + exit 1 + fi + + PYTHONPATH="$(pwd -P)" + export PYTHONPATH if [ $# -lt 1 ]; then python3 -m cdist.test @@ -370,7 +460,15 @@ eof ;; test-remote) - export PYTHONPATH="$(pwd -P)" + if [ ! -f "cdist/version.py" ] + then + printf "cdist/version.py is missing, generate it first.\n" + exit 1 + fi + + PYTHONPATH="$(pwd -P)" + export PYTHONPATH + python3 -m cdist.test.exec.remote ;; @@ -383,9 +481,9 @@ eof printf "\\nPlease review pycodestyle report.\\n" while true do - echo "Continue (yes/no)?" + printf "Continue (yes/no)?\n" any= - read any + read -r any case "$any" in yes) break @@ -394,20 +492,74 @@ eof exit 1 ;; *) - echo "Please answer with 'yes' or 'no' explicitly." + printf "Please answer with 'yes' or 'no' explicitly.\n" ;; esac done ;; + shellcheck-global-explorers) + find cdist/conf/explorer -type f -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0 + ;; + + shellcheck-type-explorers) + find cdist/conf/type -type f -path "*/explorer/*" -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0 + ;; + + shellcheck-manifests) + find cdist/conf/type -type f -name manifest -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0 + ;; + + shellcheck-local-gencodes) + find cdist/conf/type -type f -name gencode-local -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0 + ;; + + shellcheck-remote-gencodes) + find cdist/conf/type -type f -name gencode-remote -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0 + ;; + + shellcheck-scripts) + ${SHELLCHECKCMD} scripts/cdist-dump || exit 0 + ;; + + shellcheck-gencodes) + "$0" shellcheck-local-gencodes + "$0" shellcheck-remote-gencodes + ;; + + shellcheck-types) + "$0" shellcheck-type-explorers + "$0" shellcheck-manifests + "$0" shellcheck-gencodes + ;; + shellcheck) - make helper=${helper} shellcheck + "$0" shellcheck-global-explorers + "$0" shellcheck-types + "$0" shellcheck-scripts + ;; + + shellcheck-type-files) + find cdist/conf/type -type f -path "*/files/*" -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0 + ;; + + shellcheck-with-files) + "$0" shellcheck + "$0" shellcheck-type-files + ;; + + shellcheck-build-helper) + ${SHELLCHECKCMD} ./bin/build-helper + ;; + + check-shellcheck) + "$0" shellcheck printf "\\nPlease review shellcheck report.\\n" while true do - echo "Continue (yes/no)?" + printf "Continue (yes/no)?\n" any= - read any + read -r any case "$any" in yes) break @@ -416,7 +568,7 @@ eof exit 1 ;; *) - echo "Please answer with 'yes' or 'no' explicitly." + printf "Please answer with 'yes' or 'no' explicitly.\n" ;; esac done @@ -427,16 +579,39 @@ eof ;; version) - echo "VERSION = \"$(git describe)\"" > cdist/version.py + printf "VERSION = \"%s\"\n" "$(git describe)" > cdist/version.py ;; target-version) target_version=$($0 changelog-version) - echo "VERSION = \"${target_version}\"" > cdist/version.py + printf "VERSION = \"%s\"\n" "${target_version}" > cdist/version.py ;; + clean) + make clean + + # Archlinux + rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz + rm -rf pkg/ src/ + + rm -f MANIFEST PKGBUILD + rm -rf dist/ + + # Signed release + rm -f cdist-*.tar.gz + rm -f cdist-*.tar.gz.asc + + # Temp files + rm -f ./*.tmp + ;; + + distclean) + "$0" clean + rm -f cdist/version.py + ;; *) - echo "Unknown helper target $@ - aborting" + printf "Unknown target: '%s'.\n" "${option}" >&2 + usage "${basename}" exit 1 ;; diff --git a/bin/build-helper.darko b/bin/build-helper.darko deleted file mode 120000 index 1f3e3384..00000000 --- a/bin/build-helper.darko +++ /dev/null @@ -1 +0,0 @@ -build-helper \ No newline at end of file diff --git a/docs/changelog b/docs/changelog index 40cb1f83..38c59047 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Documentation: Add 'Perils of CDIST_ORDER_DEPENDENCY' sub-section (Darko Poljak) + * Build: Clean and separate end user targets into Makefile and maintainer targets into build-helper (Darko Poljak) 5.0.0: 2019-05-05 * Type __zypper_service: Fix spelling error in manpage (Dmitry Bogatov) diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst index c05036b0..4d3df8f8 100644 --- a/docs/src/cdist-install.rst +++ b/docs/src/cdist-install.rst @@ -48,14 +48,29 @@ create version.py: .. code-block:: sh - make version + ./bin/build-helper version -Then, as usual, you execute the following command: +Then you install it with: + +.. code-block:: sh + + make install + +or with: + +.. code-block:: sh + + make install-user + +to install it into user *site-packages* directory. +Or directly with distutils: .. code-block:: sh python setup.py install +Note that `bin/build-helper` script is intended for cdist maintainers. + Available versions in git ^^^^^^^^^^^^^^^^^^^^^^^^^ From 73fd1ffbc142c57d652750aac143fe07a2e58135 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 8 May 2019 23:38:43 +0200 Subject: [PATCH 1170/1332] Update homepage --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d76bbd4b..5f14a2f4 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ setup( description="A Usable Configuration Management System", author="Nico Schottelius", author_email="nico-cdist-pypi@schottelius.org", - url="http://www.nico.schottelius.org/software/cdist/", + url="https://www.cdi.st/", classifiers=[ "Development Status :: 6 - Mature", "Environment :: Console", From 15f01149f96205d17711cbe8abdcabfd37f1087c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 9 May 2019 08:26:42 +0200 Subject: [PATCH 1171/1332] Update old homepage residual refs and non working git protocol --- PKGBUILD.in | 2 +- cdist/argparse.py | 2 +- cdist/conf/type/__cdist/man.rst | 4 ++-- cdist/conf/type/__cdist/parameter/default/source | 2 +- cdist/conf/type/__git/man.rst | 2 +- docs/changelog | 3 +++ docs/src/cdist-install.rst | 2 ++ docs/src/cdist-quickstart.rst | 4 +--- 8 files changed, 12 insertions(+), 9 deletions(-) diff --git a/PKGBUILD.in b/PKGBUILD.in index c967249d..c0188e68 100755 --- a/PKGBUILD.in +++ b/PKGBUILD.in @@ -9,7 +9,7 @@ pkgver=$version pkgrel=1 pkgdesc='A Usable Configuration Management System"' arch=('any') -url='http://www.nico.schottelius.org/software/cdist/' +url='https://www.cdi.st/' license=('GPL3') depends=('python>=3.2.0') source=("http://pypi.python.org/packages/source/c/cdist/cdist-\${pkgver}.tar.gz") diff --git a/cdist/argparse.py b/cdist/argparse.py index 3ebdc138..421d1b54 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -13,7 +13,7 @@ BETA_COMMANDS = set(('install', 'inventory', )) BETA_ARGS = { 'config': set(('tag', 'all_tagged_hosts', 'use_archiving', )), } -EPILOG = "Get cdist at http://www.nico.schottelius.org/software/cdist/" +EPILOG = "Get cdist at https://code.ungleich.ch/ungleich-public/cdist" # Parser others can reuse parser = None diff --git a/cdist/conf/type/__cdist/man.rst b/cdist/conf/type/__cdist/man.rst index 15c77d7f..be082781 100644 --- a/cdist/conf/type/__cdist/man.rst +++ b/cdist/conf/type/__cdist/man.rst @@ -30,7 +30,7 @@ username source Select the source from which to clone cdist from. - Defaults to "git://code.ungleich.ch/ungleich-public/cdist.git". + Defaults to "git@code.ungleich.ch:ungleich-public/cdist.git". branch @@ -47,7 +47,7 @@ EXAMPLES __cdist /home/cdist/cdist # Use alternative source - __cdist --source "git://code.ungleich.ch/ungleich-public/cdist" /home/cdist/cdist + __cdist --source "git@code.ungleich.ch:ungleich-public/cdist.git" /home/cdist/cdist AUTHORS diff --git a/cdist/conf/type/__cdist/parameter/default/source b/cdist/conf/type/__cdist/parameter/default/source index 5f44a285..1ad3a250 100644 --- a/cdist/conf/type/__cdist/parameter/default/source +++ b/cdist/conf/type/__cdist/parameter/default/source @@ -1 +1 @@ -git://code.ungleich.ch/ungleich-public/cdist.git +git@code.ungleich.ch:ungleich-public/cdist.git diff --git a/cdist/conf/type/__git/man.rst b/cdist/conf/type/__git/man.rst index aa704d2b..130925c8 100644 --- a/cdist/conf/type/__git/man.rst +++ b/cdist/conf/type/__git/man.rst @@ -44,7 +44,7 @@ EXAMPLES __git /home/services/dokuwiki --source git://github.com/splitbrain/dokuwiki.git # Checkout cdist, stay on branch 2.1 - __git /home/nico/cdist --source git://code.ungleich.ch/ungleich-public/cdist.git --branch 2.1 + __git /home/nico/cdist --source git@code.ungleich.ch:ungleich-public/cdist.git --branch 2.1 AUTHORS diff --git a/docs/changelog b/docs/changelog index 38c59047..e3fd9368 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog next: * Documentation: Add 'Perils of CDIST_ORDER_DEPENDENCY' sub-section (Darko Poljak) * Build: Clean and separate end user targets into Makefile and maintainer targets into build-helper (Darko Poljak) + * Core: Update residual references to old cdist homepage (Darko Poljak) + * Documentation: Update residual references to old cdist homepage and git source (Darko Poljak) + * Type __cdist: Fix non working 'git://' protocol source (Darko Poljak) 5.0.0: 2019-05-05 * Type __zypper_service: Fix spelling error in manpage (Dmitry Bogatov) diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst index 4d3df8f8..a9b7d6b5 100644 --- a/docs/src/cdist-install.rst +++ b/docs/src/cdist-install.rst @@ -43,6 +43,8 @@ To install cdist, execute the following commands: From version 4.2.0 cdist tags and releases are signed. You can get GPG public key used for signing `here <_static/pgp-key-EFD2AE4EC36B6901.asc>`_. +You can also get cdist from `github mirror `_. + To install cdist with distutils from cloned repository, first you have to create version.py: diff --git a/docs/src/cdist-quickstart.rst b/docs/src/cdist-quickstart.rst index b9220b67..99af869f 100644 --- a/docs/src/cdist-quickstart.rst +++ b/docs/src/cdist-quickstart.rst @@ -54,9 +54,7 @@ we can use cdist to configure it. You can copy and paste the following code into your shell to get started and configure localhost:: # Get cdist - # Mirrors can be found on - # http://www.nico.schottelius.org/software/cdist/install/#index2h4 - git clone git://code.ungleich.ch/ungleich-public/cdist + git clone git@code.ungleich.ch:ungleich-public/cdist.git # Create manifest (maps configuration to host(s) cd cdist From a8ee4356efbd15517c90763ea92e59c0faec2a23 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 9 May 2019 19:11:09 +0200 Subject: [PATCH 1172/1332] Release 5.0.1 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index e3fd9368..cd66c649 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +5.0.1: 2019-05-09 * Documentation: Add 'Perils of CDIST_ORDER_DEPENDENCY' sub-section (Darko Poljak) * Build: Clean and separate end user targets into Makefile and maintainer targets into build-helper (Darko Poljak) * Core: Update residual references to old cdist homepage (Darko Poljak) From afa00a90943d69704aa9aa4c616992bada09c13c Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 9 May 2019 19:35:52 +0200 Subject: [PATCH 1173/1332] Fix build-helper script --- bin/build-helper | 87 ++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index bba44ded..00fe4ec7 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -23,7 +23,7 @@ # usage() { - printf "usage: %s TARGET [RUN-AS] + printf "usage: %s TARGET RUN-AS Available targets: print-runas changelog-changes @@ -61,24 +61,19 @@ usage() { distclean Run as: nico - darko - default, if not specified\n" "$1" + darko - default, if empty string specified\n" "$1" } basename="${0##*/}" -if [ $# -lt 1 ] +if [ $# -lt 2 ] then usage "${basename}" exit 1 fi option=$1; shift -if [ $# -ge 1 ] -then - run_as="$1" -else - run_as="darko" -fi +run_as="$1"; shift case "$run_as" in nico) @@ -92,6 +87,10 @@ case "$run_as" in from_d=gmail.com ml_name="Darko Poljak" ml_sig_name="Darko" + if [ -z "${run_as}" ] + then + run_as="darko" + fi ;; *) printf "Unsupported RUN-AS value: '%s'.\n" "${run_as}" >&2 @@ -160,7 +159,7 @@ case "$option" in ;; check-unittest) - "$0" test + "$0" test "${run_as}" ;; ml-release) @@ -191,7 +190,7 @@ cdist $version has been released with the following changes: eof - "$0" changelog-changes "$version" + "$0" changelog-changes "${run_as}" "$version" cat << eof Cheers, @@ -226,7 +225,7 @@ eof pypi-release) # Ensure that pypi release has the right version - "$0" version + "$0" version "${run_as}" make docs-clean make docs @@ -234,7 +233,7 @@ eof ;; release-git-tag) - target_version=$($0 changelog-version) + target_version=$($0 changelog-version "${run_as}") if git rev-parse --verify "refs/tags/${target_version}" 2>/dev/null; then printf "Tag for %s exists, aborting\n" "${target_version}" exit 1 @@ -288,7 +287,7 @@ eof git archive --prefix="cdist-${tag}/" -o "${archivename}" "${tag}" \ || exit 1 # make sure target version is generated - "$0" target-version + "$0" target-version "${run_as}" tar -x -f "${archivename}" || exit 1 cp cdist/version.py "cdist-${tag}/cdist/version.py" || exit 1 tar -c -f "${archivename}" "cdist-${tag}/" || exit 1 @@ -318,7 +317,7 @@ eof | sed "${sed_cmd}") || exit 1 # make release - changelog=$("$0" changelog-changes "$1" | sed 's/^[[:space:]]*//') + changelog=$("$0" changelog-changes "${run_as}" "$1" | sed 's/^[[:space:]]*//') release_notes=$( printf "%s\n\n%s\n\n**Changelog**\n\n%s\n" \ "${response_archive}" "${response_archive_sig}" "${changelog}" @@ -339,19 +338,19 @@ eof release) set -e - target_version=$($0 changelog-version) - target_branch=$($0 version-branch) + target_version=$($0 changelog-version "${run_as}") + target_branch=$($0 version-branch "${run_as}") printf "Beginning release process for %s\n" "${target_version}" # First check everything is sane - "$0" check-date - "$0" check-unittest - "$0" check-pycodestyle - "$0" check-shellcheck + "$0" check-date "${run_as}" + "$0" check-unittest "${run_as}" + "$0" check-pycodestyle "${run_as}" + "$0" check-shellcheck "${run_as}" # Generate version file to be included in packaging - "$0" target-version + "$0" target-version "${run_as}" # Ensure the git status is clean, else abort if ! git diff-index --name-only --exit-code HEAD ; then @@ -386,8 +385,8 @@ eof fi # Verify that after the merge everything works - "$0" check-date - "$0" check-unittest + "$0" check-date "${run_as}" + "$0" check-unittest "${run_as}" # Generate documentation (man and html) # First, clean old generated docs @@ -398,7 +397,7 @@ eof # Everything green, let's do the release # Tag the current commit - "$0" release-git-tag + "$0" release-git-tag "${run_as}" # Also merge back the version branch if [ "$masterbranch" = yes ]; then @@ -419,21 +418,21 @@ eof # fi # Create and publish package for pypi - "$0" pypi-release + "$0" pypi-release "${run_as}" if [ "$run_as" = "nico" ] then # Archlinux release is based on pypi - "$0" archlinux-release + "$0" archlinux-release "${run_as}" fi # sign git tag printf "Enter upstream repository authentication token: " read -r token - "$0" sign-git-release "${target_version}" "${token}" + "$0" sign-git-release "${run_as}" "${target_version}" "${token}" # Announce change on ML - "$0" ml-release "${target_version}" + "$0" ml-release "${run_as}" "${target_version}" cat << eof Manual steps post release: @@ -477,7 +476,7 @@ eof ;; check-pycodestyle) - "$0" pycodestyle + "$0" pycodestyle "${run_as}" printf "\\nPlease review pycodestyle report.\\n" while true do @@ -523,20 +522,20 @@ eof ;; shellcheck-gencodes) - "$0" shellcheck-local-gencodes - "$0" shellcheck-remote-gencodes + "$0" shellcheck-local-gencodes "${run_as}" + "$0" shellcheck-remote-gencodes "${run_as}" ;; shellcheck-types) - "$0" shellcheck-type-explorers - "$0" shellcheck-manifests - "$0" shellcheck-gencodes + "$0" shellcheck-type-explorers "${run_as}" + "$0" shellcheck-manifests "${run_as}" + "$0" shellcheck-gencodes "${run_as}" ;; shellcheck) - "$0" shellcheck-global-explorers - "$0" shellcheck-types - "$0" shellcheck-scripts + "$0" shellcheck-global-explorers "${run_as}" + "$0" shellcheck-types "${run_as}" + "$0" shellcheck-scripts "${run_as}" ;; shellcheck-type-files) @@ -544,8 +543,8 @@ eof ;; shellcheck-with-files) - "$0" shellcheck - "$0" shellcheck-type-files + "$0" shellcheck "${run_as}" + "$0" shellcheck-type-files "${run_as}" ;; shellcheck-build-helper) @@ -553,7 +552,7 @@ eof ;; check-shellcheck) - "$0" shellcheck + "$0" shellcheck "${run_as}" printf "\\nPlease review shellcheck report.\\n" while true do @@ -575,7 +574,7 @@ eof ;; version-branch) - "$0" changelog-version | cut -d. -f '1,2' + "$0" changelog-version "${run_as}" | cut -d. -f '1,2' ;; version) @@ -583,7 +582,7 @@ eof ;; target-version) - target_version=$($0 changelog-version) + target_version=$($0 changelog-version "${run_as}") printf "VERSION = \"%s\"\n" "${target_version}" > cdist/version.py ;; @@ -606,7 +605,7 @@ eof ;; distclean) - "$0" clean + "$0" clean "${run_as}" rm -f cdist/version.py ;; *) From 66cdbc5233407d5f926e1db3e4031ffe6ef3a8b2 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 9 May 2019 21:05:33 +0200 Subject: [PATCH 1174/1332] Simplify maintainer's helper script --- bin/build-helper | 145 +++++++++++++---------------------------------- 1 file changed, 39 insertions(+), 106 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 00fe4ec7..1698a678 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -23,9 +23,8 @@ # usage() { - printf "usage: %s TARGET RUN-AS + printf "usage: %s TARGET [TARGET-ARGS...] Available targets: - print-runas changelog-changes changelog-version check-date @@ -58,64 +57,29 @@ usage() { version target-version clean - distclean - Run as: - nico - darko - default, if empty string specified\n" "$1" + distclean\n" "$1" } basename="${0##*/}" -if [ $# -lt 2 ] +if [ $# -lt 1 ] then usage "${basename}" exit 1 fi option=$1; shift -run_as="$1"; shift - -case "$run_as" in - nico) - from_a=nico.schottelius - from_d=ungleich.ch - ml_name="Nico Schottelius" - ml_sig_name="Nico" - ;; - darko|'') - from_a=darko.poljak - from_d=gmail.com - ml_name="Darko Poljak" - ml_sig_name="Darko" - if [ -z "${run_as}" ] - then - run_as="darko" - fi - ;; - *) - printf "Unsupported RUN-AS value: '%s'.\n" "${run_as}" >&2 - usage "${basename}" - exit 1 - ;; -esac SHELLCHECKCMD="shellcheck -s sh -f gcc -x" # Skip SC2154 for variables starting with __ since such variables are cdist # environment variables. SHELLCHECK_SKIP=': __.*is referenced but not assigned.*\[SC2154\]' -to_a="cdist-configuration-management" -to_d="googlegroups.com" - # Change to checkout directory basedir="${0%/*}/../" cd "$basedir" case "$option" in - print-runas) - printf "run_as: '%s'\n" "$run_as" - ;; - changelog-changes) if [ "$#" -eq 1 ]; then start=$1 @@ -159,7 +123,7 @@ case "$option" in ;; check-unittest) - "$0" test "${run_as}" + "$0" test ;; ml-release) @@ -168,20 +132,10 @@ case "$option" in exit 1 fi - # Send mail only once - lock until new changelog things happened. - [ ! -f .lock-ml ] && touch .lock-ml - x=$(find 'docs' -name changelog -type f -newer .lock-ml) - [ -z "${x}" ] && exit 0 - version=$1; shift - to=${to_a}@${to_d} - from=${from_a}@${from_d} - ( cat << eof -From: ${ml_name} <$from> -To: cdist mailing list <$to> Subject: cdist $version has been released Hello .*, @@ -190,23 +144,11 @@ cdist $version has been released with the following changes: eof - "$0" changelog-changes "${run_as}" "$version" + "$0" changelog-changes "$version" cat << eof -Cheers, -${ml_sig_name} - --- -Automatisation at its best level. With cdist. eof ) > mailinglist.tmp - - if [ "$run_as" = "nico" ] - then - /usr/sbin/sendmail -f "$from" "$to" < mailinglist.tmp && rm -f mailinglist.tmp - fi - - touch .lock-ml ;; archlinux-release) @@ -225,7 +167,7 @@ eof pypi-release) # Ensure that pypi release has the right version - "$0" version "${run_as}" + "$0" version make docs-clean make docs @@ -233,7 +175,7 @@ eof ;; release-git-tag) - target_version=$($0 changelog-version "${run_as}") + target_version=$($0 changelog-version) if git rev-parse --verify "refs/tags/${target_version}" 2>/dev/null; then printf "Tag for %s exists, aborting\n" "${target_version}" exit 1 @@ -287,7 +229,7 @@ eof git archive --prefix="cdist-${tag}/" -o "${archivename}" "${tag}" \ || exit 1 # make sure target version is generated - "$0" target-version "${run_as}" + "$0" target-version tar -x -f "${archivename}" || exit 1 cp cdist/version.py "cdist-${tag}/cdist/version.py" || exit 1 tar -c -f "${archivename}" "cdist-${tag}/" || exit 1 @@ -317,7 +259,7 @@ eof | sed "${sed_cmd}") || exit 1 # make release - changelog=$("$0" changelog-changes "${run_as}" "$1" | sed 's/^[[:space:]]*//') + changelog=$("$0" changelog-changes "$1" | sed 's/^[[:space:]]*//') release_notes=$( printf "%s\n\n%s\n\n**Changelog**\n\n%s\n" \ "${response_archive}" "${response_archive_sig}" "${changelog}" @@ -338,19 +280,19 @@ eof release) set -e - target_version=$($0 changelog-version "${run_as}") - target_branch=$($0 version-branch "${run_as}") + target_version=$($0 changelog-version) + target_branch=$($0 version-branch) printf "Beginning release process for %s\n" "${target_version}" # First check everything is sane - "$0" check-date "${run_as}" - "$0" check-unittest "${run_as}" - "$0" check-pycodestyle "${run_as}" - "$0" check-shellcheck "${run_as}" + "$0" check-date + "$0" check-unittest + "$0" check-pycodestyle + "$0" check-shellcheck # Generate version file to be included in packaging - "$0" target-version "${run_as}" + "$0" target-version # Ensure the git status is clean, else abort if ! git diff-index --name-only --exit-code HEAD ; then @@ -385,8 +327,8 @@ eof fi # Verify that after the merge everything works - "$0" check-date "${run_as}" - "$0" check-unittest "${run_as}" + "$0" check-date + "$0" check-unittest # Generate documentation (man and html) # First, clean old generated docs @@ -397,7 +339,7 @@ eof # Everything green, let's do the release # Tag the current commit - "$0" release-git-tag "${run_as}" + "$0" release-git-tag # Also merge back the version branch if [ "$masterbranch" = yes ]; then @@ -406,37 +348,28 @@ eof fi # Publish git changes - # if you want to have mirror locally then uncomment this support - # if [ "$run_as" = "nico" ] - # then + # if you want to have mirror locally then uncomment this and comment below # git push --mirror - # else - # if we are not Nico :) then just push, no mirror git push # push also new branch and set up tracking git push -u origin "${target_branch}" # fi # Create and publish package for pypi - "$0" pypi-release "${run_as}" - - if [ "$run_as" = "nico" ] - then - # Archlinux release is based on pypi - "$0" archlinux-release "${run_as}" - fi + "$0" pypi-release # sign git tag printf "Enter upstream repository authentication token: " read -r token - "$0" sign-git-release "${run_as}" "${target_version}" "${token}" + "$0" sign-git-release "${target_version}" "${token}" # Announce change on ML - "$0" ml-release "${run_as}" "${target_version}" + "$0" ml-release "${target_version}" cat << eof Manual steps post release: - cdist-web + - send mail body generated in mailinglist.tmp and inform Dmitry for deb - twitter eof ;; @@ -476,7 +409,7 @@ eof ;; check-pycodestyle) - "$0" pycodestyle "${run_as}" + "$0" pycodestyle printf "\\nPlease review pycodestyle report.\\n" while true do @@ -522,20 +455,20 @@ eof ;; shellcheck-gencodes) - "$0" shellcheck-local-gencodes "${run_as}" - "$0" shellcheck-remote-gencodes "${run_as}" + "$0" shellcheck-local-gencodes + "$0" shellcheck-remote-gencodes ;; shellcheck-types) - "$0" shellcheck-type-explorers "${run_as}" - "$0" shellcheck-manifests "${run_as}" - "$0" shellcheck-gencodes "${run_as}" + "$0" shellcheck-type-explorers + "$0" shellcheck-manifests + "$0" shellcheck-gencodes ;; shellcheck) - "$0" shellcheck-global-explorers "${run_as}" - "$0" shellcheck-types "${run_as}" - "$0" shellcheck-scripts "${run_as}" + "$0" shellcheck-global-explorers + "$0" shellcheck-types + "$0" shellcheck-scripts ;; shellcheck-type-files) @@ -543,8 +476,8 @@ eof ;; shellcheck-with-files) - "$0" shellcheck "${run_as}" - "$0" shellcheck-type-files "${run_as}" + "$0" shellcheck + "$0" shellcheck-type-files ;; shellcheck-build-helper) @@ -552,7 +485,7 @@ eof ;; check-shellcheck) - "$0" shellcheck "${run_as}" + "$0" shellcheck printf "\\nPlease review shellcheck report.\\n" while true do @@ -574,7 +507,7 @@ eof ;; version-branch) - "$0" changelog-version "${run_as}" | cut -d. -f '1,2' + "$0" changelog-version | cut -d. -f '1,2' ;; version) @@ -582,7 +515,7 @@ eof ;; target-version) - target_version=$($0 changelog-version "${run_as}") + target_version=$($0 changelog-version) printf "VERSION = \"%s\"\n" "${target_version}" > cdist/version.py ;; @@ -605,7 +538,7 @@ eof ;; distclean) - "$0" clean "${run_as}" + "$0" clean rm -f cdist/version.py ;; *) From 569ae29955961cd2901ef6307efff152daa87473 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 May 2019 11:47:15 +0200 Subject: [PATCH 1175/1332] [__package_apk] fix / add support for @yrepo syntax --- cdist/conf/type/__package_apk/explorer/state | 4 ++++ docs/changelog | 3 +++ 2 files changed, 7 insertions(+) diff --git a/cdist/conf/type/__package_apk/explorer/state b/cdist/conf/type/__package_apk/explorer/state index 29ccf3a5..b477ca7c 100755 --- a/cdist/conf/type/__package_apk/explorer/state +++ b/cdist/conf/type/__package_apk/explorer/state @@ -27,6 +27,10 @@ else name="$__object_id" fi +# Remove the @.. repo tag for finding out whether it is installed +# f.i. pass@testing => pass +name="$(echo "$name" | sed 's/@.*//')" + if [ "$(apk list -I "$name")" ]; then echo present else diff --git a/docs/changelog b/docs/changelog index cd66c649..af8fef8f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __package_apk: Fix @repo handling in explorer (Nico Schottelius) + 5.0.1: 2019-05-09 * Documentation: Add 'Perils of CDIST_ORDER_DEPENDENCY' sub-section (Darko Poljak) * Build: Clean and separate end user targets into Makefile and maintainer targets into build-helper (Darko Poljak) From ca8bc959ed931734570b2c47d2d99c5b35c754a3 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 14 May 2019 13:27:43 +0300 Subject: [PATCH 1176/1332] __acl: add todo note --- cdist/conf/type/__acl/explorer/checks | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__acl/explorer/checks b/cdist/conf/type/__acl/explorer/checks index 2f3b9e6d..2aae13f6 100755 --- a/cdist/conf/type/__acl/explorer/checks +++ b/cdist/conf/type/__acl/explorer/checks @@ -18,6 +18,8 @@ # along with cdist. If not, see . # +# TODO check if filesystem has ACL turned on etc + [ ! -e "/$__object_id" ] && exit 0 for parameter in user group From 7dfc5bc4736b00e8622555169c65800bb7bf4600 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 14 May 2019 13:41:32 +0300 Subject: [PATCH 1177/1332] __acl: we do not have to check here if file exist --- cdist/conf/type/__acl/explorer/checks | 2 -- 1 file changed, 2 deletions(-) diff --git a/cdist/conf/type/__acl/explorer/checks b/cdist/conf/type/__acl/explorer/checks index 2aae13f6..a2fcf44d 100755 --- a/cdist/conf/type/__acl/explorer/checks +++ b/cdist/conf/type/__acl/explorer/checks @@ -20,8 +20,6 @@ # TODO check if filesystem has ACL turned on etc -[ ! -e "/$__object_id" ] && exit 0 - for parameter in user group do if [ ! -f "$__object/parameter/$parameter" ] From 7a25ec00edb8458c8a11de3971024a9f99d1ba47 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Tue, 14 May 2019 13:42:56 +0300 Subject: [PATCH 1178/1332] __acl: add TODO note about dry-run --- cdist/conf/type/__acl/gencode-remote | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index ef903816..d47469c1 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -20,6 +20,7 @@ file_is="$( cat "$__object/explorer/file_is" )" +# TODO this check is not needed with dry-run [ "$file_is" = 'missing' ] && exit 0 os="$( cat "$__global/explorer/os" )" From 5f462d638017c22548176aeb7594098d009af21e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 May 2019 16:49:33 +0200 Subject: [PATCH 1179/1332] ++alpine support --- cdist/conf/type/__postfix/manifest | 3 ++- cdist/conf/type/__postfix_postconf/explorer/value | 2 +- cdist/conf/type/__postfix_postconf/gencode-remote | 3 ++- docs/changelog | 2 ++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__postfix/manifest b/cdist/conf/type/__postfix/manifest index 1aea53a1..f3616979 100755 --- a/cdist/conf/type/__postfix/manifest +++ b/cdist/conf/type/__postfix/manifest @@ -1,6 +1,7 @@ #!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2019 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -22,7 +23,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|suse|scientific|centos|devuan) + alpine|ubuntu|debian|archlinux|suse|scientific|centos|devuan) __package postfix --state present ;; *) diff --git a/cdist/conf/type/__postfix_postconf/explorer/value b/cdist/conf/type/__postfix_postconf/explorer/value index 17126c94..67dacad8 100755 --- a/cdist/conf/type/__postfix_postconf/explorer/value +++ b/cdist/conf/type/__postfix_postconf/explorer/value @@ -22,7 +22,7 @@ os=$("$__explorer/os") case "$os" in - ubuntu|debian|archlinux|suse|scientific|centos|devuan) + alpine|ubuntu|debian|archlinux|suse|scientific|centos|devuan) : ;; *) diff --git a/cdist/conf/type/__postfix_postconf/gencode-remote b/cdist/conf/type/__postfix_postconf/gencode-remote index 6df0da7f..279dddd4 100755 --- a/cdist/conf/type/__postfix_postconf/gencode-remote +++ b/cdist/conf/type/__postfix_postconf/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh -e # # 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2019 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -21,7 +22,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - ubuntu|debian|archlinux|suse|scientific|centos|devuan) + alpine|archlinux|centos|debian|devuan|suse|scientific|ubuntu) : ;; *) diff --git a/docs/changelog b/docs/changelog index af8fef8f..556fd42f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,8 @@ Changelog next: * Type __package_apk: Fix @repo handling in explorer (Nico Schottelius) + * Type __postfix: Add alpine support (Nico Schottelius) + * Type __postfix_postconf: Add alpine support (Nico Schottelius) 5.0.1: 2019-05-09 * Documentation: Add 'Perils of CDIST_ORDER_DEPENDENCY' sub-section (Darko Poljak) From ce52203ba3a84297599f9b0eeb66ae83f967859e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 May 2019 17:10:26 +0200 Subject: [PATCH 1180/1332] __user add alpine support --- cdist/conf/type/__user/manifest | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 cdist/conf/type/__user/manifest diff --git a/cdist/conf/type/__user/manifest b/cdist/conf/type/__user/manifest new file mode 100644 index 00000000..8f10b38c --- /dev/null +++ b/cdist/conf/type/__user/manifest @@ -0,0 +1,32 @@ +#!/bin/sh -e +# +# 2019 Nico Schottelius (nico-cdist at schottelius.org) +# +# 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 . +# +# +# Manage users. + +os=$(cat "$__global/explorer/os") + +case "$os" in + alpine) + __package shadow + ;; + *) + : + ;; +esac From fe643b9092a61f5616624e10ebd0abdf0749823a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 May 2019 17:10:46 +0200 Subject: [PATCH 1181/1332] ++doc --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 556fd42f..41b0088f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __package_apk: Fix @repo handling in explorer (Nico Schottelius) * Type __postfix: Add alpine support (Nico Schottelius) * Type __postfix_postconf: Add alpine support (Nico Schottelius) + * Type __user: Add alpine support (Nico Schottelius) 5.0.1: 2019-05-09 * Documentation: Add 'Perils of CDIST_ORDER_DEPENDENCY' sub-section (Darko Poljak) From 69622b0fa5f0d29eaf6d4357a0e84f8a6f6b101b Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Thu, 16 May 2019 21:58:47 +0200 Subject: [PATCH 1182/1332] set __cdist_dry_run env var if dry-run --- cdist/config.py | 9 ++++++--- cdist/core/code.py | 5 ++++- cdist/core/explorer.py | 6 +++++- cdist/core/manifest.py | 5 ++++- docs/src/cdist-reference.rst.sh | 4 ++++ docs/src/cdist-type.rst | 9 +++++++++ 6 files changed, 32 insertions(+), 6 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index bc05a28c..30117382 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -104,9 +104,12 @@ class Config(object): self.remove_remote_files_dirs = remove_remote_files_dirs self.explorer = core.Explorer(self.local.target_host, self.local, - self.remote, jobs=self.jobs) - self.manifest = core.Manifest(self.local.target_host, self.local) - self.code = core.Code(self.local.target_host, self.local, self.remote) + self.remote, jobs=self.jobs, + dry_run=self.dry_run) + self.manifest = core.Manifest(self.local.target_host, self.local, + dry_run=self.dry_run) + self.code = core.Code(self.local.target_host, self.local, self.remote, + dry_run=self.dry_run) def _init_files_dirs(self): """Prepare files and directories for the run""" diff --git a/cdist/core/code.py b/cdist/core/code.py index 670029ed..1550880a 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -97,7 +97,7 @@ class Code(object): """ # target_host is tuple (target_host, target_hostname, target_fqdn) - def __init__(self, target_host, local, remote): + def __init__(self, target_host, local, remote, dry_run=False): self.target_host = target_host self.local = local self.remote = remote @@ -113,6 +113,9 @@ class Code(object): local.log), } + if dry_run: + self.env['__cdist_dry_run'] = '1' + def _run_gencode(self, cdist_object, which): cdist_type = cdist_object.cdist_type script = os.path.join(self.local.type_path, diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index acceacac..353d7681 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -67,7 +67,7 @@ class Explorer(object): """Executes cdist explorers. """ - def __init__(self, target_host, local, remote, jobs=None): + def __init__(self, target_host, local, remote, jobs=None, dry_run=False): self.target_host = target_host self._open_logger() @@ -84,6 +84,10 @@ class Explorer(object): '__cdist_log_level_name': util.log_level_name_env_var_val( self.log), } + + if dry_run: + self.env['__cdist_dry_run'] = '1' + self._type_explorers_transferred = [] self.jobs = jobs diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 938ad8b8..07af0ef8 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -96,7 +96,7 @@ class Manifest(object): """Executes cdist manifests. """ - def __init__(self, target_host, local): + def __init__(self, target_host, local, dry_run=False): self.target_host = target_host self.local = local @@ -117,6 +117,9 @@ class Manifest(object): self.log), } + if dry_run: + self.env['__cdist_dry_run'] = '1' + def _open_logger(self): self.log = logging.getLogger(self.target_host[0]) diff --git a/docs/src/cdist-reference.rst.sh b/docs/src/cdist-reference.rst.sh index 2c9c7b40..f4a37816 100755 --- a/docs/src/cdist-reference.rst.sh +++ b/docs/src/cdist-reference.rst.sh @@ -219,6 +219,10 @@ __cdist_log_level, __cdist_log_level_name | TRACE | 5 | +----------------+-----------------+ + Available for: initial manifest, explorer, type manifest, type explorer, + type gencode. +__cdist_dry_run + Is set only when doing dry run (``-n`` flag). Available for: initial manifest, explorer, type manifest, type explorer, type gencode. __explorer diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 7c0dab8d..7e5e39ef 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -371,6 +371,15 @@ It is available for initial manifest, explorer, type manifest, type explorer, type gencode. +Detecting dry run +----------------- + +If ``$__cdist_dry_run`` environment variable is set, then it's dry run. + +It is available for initial manifest, explorer, type manifest, +type explorer, type gencode. + + Hints for typewriters ---------------------- It must be assumed that the target is pretty dumb and thus does not have high From 7195b594f302be7742eaa84e1daa0bdc71bbc012 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 16 May 2019 21:59:30 +0200 Subject: [PATCH 1183/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 41b0088f..47b4b14b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Type __postfix: Add alpine support (Nico Schottelius) * Type __postfix_postconf: Add alpine support (Nico Schottelius) * Type __user: Add alpine support (Nico Schottelius) + * Core: Set __cdist_dry_run env var (Ander Punnar) 5.0.1: 2019-05-09 * Documentation: Add 'Perils of CDIST_ORDER_DEPENDENCY' sub-section (Darko Poljak) From d604a9db7a080c1cc3782f6e488a2ed6a508fd02 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 17 May 2019 13:03:46 +0200 Subject: [PATCH 1184/1332] Fix pycodestyle --- cdist/inventory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/inventory.py b/cdist/inventory.py index 7da306fa..138a2034 100644 --- a/cdist/inventory.py +++ b/cdist/inventory.py @@ -315,7 +315,7 @@ class InventoryHost(Inventory): hostpath = self._host_path(host) self.log.trace("hostpath: {}".format(hostpath)) if self.action == "add" and not os.path.exists(hostpath): - self._new_hostpath(hostpath) + self._new_hostpath(hostpath) else: if not os.path.isfile(hostpath): raise cdist.Error(("Host path \'{}\' is" From 4a5425a95e8b5fce1d2e49064301a4e173f8d003 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 17 May 2019 13:02:05 +0200 Subject: [PATCH 1185/1332] Release 5.0.2 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 47b4b14b..515f7b69 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +5.0.2: 2019-05-17 * Type __package_apk: Fix @repo handling in explorer (Nico Schottelius) * Type __postfix: Add alpine support (Nico Schottelius) * Type __postfix_postconf: Add alpine support (Nico Schottelius) From 21a16f5584a08b8f155c01d2cbb78a003fc5725b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 18 May 2019 23:46:09 +0200 Subject: [PATCH 1186/1332] consul, changelog, consul agent => alpine --- .../type/__consul/files/versions/1.5.0/cksum | 1 + .../type/__consul/files/versions/1.5.0/source | 1 + cdist/conf/type/__consul/gencode-remote | 2 +- cdist/conf/type/__consul/manifest | 3 +- .../__consul_agent/files/consul.sys-openrc | 38 +++++++++++++++ cdist/conf/type/__consul_agent/manifest | 47 +++++++++---------- docs/changelog | 5 ++ 7 files changed, 71 insertions(+), 26 deletions(-) create mode 100644 cdist/conf/type/__consul/files/versions/1.5.0/cksum create mode 100644 cdist/conf/type/__consul/files/versions/1.5.0/source create mode 100644 cdist/conf/type/__consul_agent/files/consul.sys-openrc diff --git a/cdist/conf/type/__consul/files/versions/1.5.0/cksum b/cdist/conf/type/__consul/files/versions/1.5.0/cksum new file mode 100644 index 00000000..efca9caa --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/1.5.0/cksum @@ -0,0 +1 @@ +886614099 103959898 consul diff --git a/cdist/conf/type/__consul/files/versions/1.5.0/source b/cdist/conf/type/__consul/files/versions/1.5.0/source new file mode 100644 index 00000000..cafa9248 --- /dev/null +++ b/cdist/conf/type/__consul/files/versions/1.5.0/source @@ -0,0 +1 @@ +https://releases.hashicorp.com/consul/1.5.0/consul_1.5.0_linux_amd64.zip diff --git a/cdist/conf/type/__consul/gencode-remote b/cdist/conf/type/__consul/gencode-remote index 1d2244ea..2a21054f 100755 --- a/cdist/conf/type/__consul/gencode-remote +++ b/cdist/conf/type/__consul/gencode-remote @@ -42,7 +42,7 @@ source_file_name="${source##*/}" cksum_should=$(cut -d' ' -f1,2 "$version_dir/cksum") cat << eof - tmpdir=\$(mktemp -d --tmpdir="/tmp" "${__type##*/}.XXXXXXXXXX") + tmpdir=\$(mktemp -d -p /tmp "${__type##*/}.XXXXXXXXXX") curl -s -L "$source" > "\$tmpdir/$source_file_name" unzip -p "\$tmpdir/$source_file_name" > "${destination}.tmp" rm -rf "\$tmpdir" diff --git a/cdist/conf/type/__consul/manifest b/cdist/conf/type/__consul/manifest index 0dd50f53..156eb667 100755 --- a/cdist/conf/type/__consul/manifest +++ b/cdist/conf/type/__consul/manifest @@ -24,7 +24,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - scientific|centos|redhat|ubuntu|debian|devuan|archlinux|gentoo) + alpine|scientific|centos|redhat|ubuntu|debian|devuan|archlinux|gentoo) # any linux should work : ;; @@ -47,6 +47,7 @@ fi if [ -f "$__object/parameter/direct" ]; then __package unzip + __package curl else __staged_file /usr/local/bin/consul \ --source "$(cat "$version_dir/source")" \ diff --git a/cdist/conf/type/__consul_agent/files/consul.sys-openrc b/cdist/conf/type/__consul_agent/files/consul.sys-openrc new file mode 100644 index 00000000..1dbe9375 --- /dev/null +++ b/cdist/conf/type/__consul_agent/files/consul.sys-openrc @@ -0,0 +1,38 @@ +#!/sbin/openrc-run +# 2019 Nico Schottelius (nico-cdist at schottelius.org) + +description="consul agent" + +pidfile="${CONSUL_PIDFILE:-"/var/run/$RC_SVCNAME/pidfile"}" +command="${CONSUL_BINARY:-"/usr/local/bin/consul"}" + + +checkconfig() { + if [ ! -d /var/run/consul ] ; then + mkdir -p /var/run/consul || return 1 + chown consul:consul /var/run/$NAME || return 1 + chmod 2770 /var/run/$NAME || return 1 + fi +} + +start() { + need net + + start-stop-daemon --start --quiet --oknodo \ + --pidfile "$pidfile" --background \ + --exec $command -- agent -pid-file="$pidfile" -config-dir /etc/consul/conf.d +} +start_pre() { + checkconfig +} + +stop() { + if [ "${RC_CMD}" = "restart" ] ; then + checkconfig || return 1 + fi + + ebegin "Stopping $RC_SVCNAME" + start-stop-daemon --stop --exec "$command" \ + --pidfile "$pidfile" --quiet + eend $? +} diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest index c48bfe85..a88d26ed 100755 --- a/cdist/conf/type/__consul_agent/manifest +++ b/cdist/conf/type/__consul_agent/manifest @@ -1,7 +1,7 @@ #!/bin/sh -e # # 2015 Steven Armstrong (steven-cdist at armstrong.cc) -# 2015 Nico Schottelius (nico-cdist at schottelius.org) +# 2015-2019 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -23,7 +23,7 @@ os=$(cat "$__global/explorer/os") case "$os" in - scientific|centos|debian|devuan|redhat|ubuntu) + alpine|scientific|centos|debian|devuan|redhat|ubuntu) # whitelist safeguard : ;; @@ -181,22 +181,25 @@ init_upstart() # Install init script to start on boot case "$os" in - centos|redhat) - os_version="$(sed 's/[^0-9.]//g' "$__global/explorer/os_version")" - major_version="${os_version%%.*}" - case "$major_version" in - [456]) - init_sysvinit redhat - ;; - 7) - init_systemd - ;; - *) - echo "Unsupported CentOS/Redhat version: $os_version" >&2 - exit 1 - ;; - esac - ;; + alpine|devuan) + init_sysvinit debian + ;; + centos|redhat) + os_version="$(sed 's/[^0-9.]//g' "$__global/explorer/os_version")" + major_version="${os_version%%.*}" + case "$major_version" in + [456]) + init_sysvinit redhat + ;; + 7) + init_systemd + ;; + *) + echo "Unsupported CentOS/Redhat version: $os_version" >&2 + exit 1 + ;; + esac + ;; debian) os_version=$(cat "$__global/explorer/os_version") @@ -214,13 +217,9 @@ case "$os" in exit 1 ;; esac - ;; - - devuan) - init_sysvinit debian - ;; + ;; ubuntu) init_upstart - ;; + ;; esac diff --git a/docs/changelog b/docs/changelog index 515f7b69..b8071ffe 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,11 @@ Changelog --------- +next: + * Type __consul: Add alpine support (Nico Schottelius) + * Type __consul: Add version 1.5.0 (Nico Schottelius) + * Type __consul_agent: Add alpine support (Nico Schottelius) + 5.0.2: 2019-05-17 * Type __package_apk: Fix @repo handling in explorer (Nico Schottelius) * Type __postfix: Add alpine support (Nico Schottelius) From 03f8c3aaed3d106792a05e9e24e14b86f7e0414c Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sun, 19 May 2019 23:22:02 +0300 Subject: [PATCH 1187/1332] __acl: don't exit on missing file when dry run --- cdist/conf/type/__acl/gencode-remote | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index d47469c1..36eca3f8 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -20,8 +20,7 @@ file_is="$( cat "$__object/explorer/file_is" )" -# TODO this check is not needed with dry-run -[ "$file_is" = 'missing' ] && exit 0 +[ "$file_is" = 'missing' ] && [ -z "$__cdist_dry_run" ] && exit 0 os="$( cat "$__global/explorer/os" )" From 02e10b1ffd1d1fa28586caf234f5e007dfe7e606 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sun, 19 May 2019 23:27:58 +0300 Subject: [PATCH 1188/1332] __acl: fix SC1117 --- cdist/conf/type/__acl/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 36eca3f8..f5b0474f 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -48,7 +48,7 @@ do then [ "$file_is" = 'directory' ] && rep=x || rep=- - acl="$( echo "$acl" | sed "s/\(.*\)X/\1$rep/" )" + acl="$( echo "$acl" | sed "s/\\(.*\\)X/\\1$rep/" )" fi echo "$parameter" | grep -Eq '(mask|other)' && sep=:: || sep=: From e30d76014accf5e1f0860f504c287c5ed025da9c Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sun, 19 May 2019 23:44:20 +0300 Subject: [PATCH 1189/1332] __acl: update man --- cdist/conf/type/__acl/man.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst index e6784c87..d066aae5 100644 --- a/cdist/conf/type/__acl/man.rst +++ b/cdist/conf/type/__acl/man.rst @@ -10,9 +10,7 @@ DESCRIPTION ----------- ACL must be defined as 3-symbol combination, using ``r``, ``w``, ``x`` and ``-``. -Fully supported and tested on Linux, partial support for FreeBSD. - -OpenBSD, NetBSD and Solaris support is not possible. +Fully supported and tested on Linux (ext4 filesystem), partial support for FreeBSD. See ``setfacl`` and ``acl`` manpages for more details. From 34eec3c214b1fbd95246e9243196173b55aee41a Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 19 May 2019 13:40:24 +0200 Subject: [PATCH 1190/1332] Add cdist-new-type helper scrpt --- bin/build-helper | 2 +- docs/changelog | 1 + docs/src/cdist-troubleshooting.rst | 3 +- docs/src/cdist-type.rst | 3 + docs/src/index.rst | 1 + docs/src/man1/cdist-new-type.rst | 74 ++++++++++++++ scripts/cdist-new-type | 159 +++++++++++++++++++++++++++++ setup.py | 2 +- 8 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 docs/src/man1/cdist-new-type.rst create mode 100755 scripts/cdist-new-type diff --git a/bin/build-helper b/bin/build-helper index 1698a678..9a776491 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -451,7 +451,7 @@ eof ;; shellcheck-scripts) - ${SHELLCHECKCMD} scripts/cdist-dump || exit 0 + ${SHELLCHECKCMD} scripts/cdist-dump scripts/cdist-new-type || exit 0 ;; shellcheck-gencodes) diff --git a/docs/changelog b/docs/changelog index b8071ffe..acf462f2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Type __consul: Add alpine support (Nico Schottelius) * Type __consul: Add version 1.5.0 (Nico Schottelius) * Type __consul_agent: Add alpine support (Nico Schottelius) + * New helper script: cdist-new-type (Steven Armstrong, Darko Poljak) 5.0.2: 2019-05-17 * Type __package_apk: Fix @repo handling in explorer (Nico Schottelius) diff --git a/docs/src/cdist-troubleshooting.rst b/docs/src/cdist-troubleshooting.rst index 6b7fb4af..e639aafd 100644 --- a/docs/src/cdist-troubleshooting.rst +++ b/docs/src/cdist-troubleshooting.rst @@ -47,7 +47,8 @@ you write to use the -e flag: Using debug dump helper script ------------------------------ Since cdist stores data to local cache that can be used for debugging there -is a helper script that dumps data from local cache. +is a helper script that dumps data from local cache, +`cdist-dump `_. For more info see: diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 7e5e39ef..880df819 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -93,6 +93,9 @@ they are written in shell so they are executed using '/bin/sh -e' or 'CDIST_LOCA For executable shell code it is suggested that shebang is '#!/bin/sh -e'. +For creating type skeleton you can use helper script +`cdist-new-type `_. + Defining parameters ------------------- diff --git a/docs/src/index.rst b/docs/src/index.rst index 95e44d52..6cbd938a 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -22,6 +22,7 @@ is being used in small up to enterprise grade environments. cdist-real-world man1/cdist man1/cdist-dump + man1/cdist-new-type cdist-bootstrap cdist-configuration cdist-manifest diff --git a/docs/src/man1/cdist-new-type.rst b/docs/src/man1/cdist-new-type.rst new file mode 100644 index 00000000..f1a8b992 --- /dev/null +++ b/docs/src/man1/cdist-new-type.rst @@ -0,0 +1,74 @@ +cdist-new-type(1) +================= + +NAME +---- +cdist-new-type - Create new type skeleton + + +SYNOPSIS +-------- + +:: + + cdist-new-type TYPE-NAME AUTHOR-NAME AUTHOR-EMAIL [TYPE-BASE-PATH] + + + +DESCRIPTION +----------- +cdist-new-type is a helper script that creates new type skeleton. +It is then up to the type author to finish the type. + +It creates skeletons for the following files: + +* man.rst +* manifest +* gencode-remote. + +Upon creation it prints the path to the newly created type directory. + + +ARGUMENTS +--------- +**TYPE-NAME** + Name of the new type. + +**AUTHOR-NAME** + Type author's full name. + +**AUTHOR-NAME** + Type author's email. + +**TYPE-BASE-PATH** + Path to the base directory of the type. If not set it defaults + to '$PWD/type'. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Create new type __foo in ~/.cdist directory. + $ cd ~/.cdist + $ cdist-new-type '__foo' 'Foo Bar' 'foo.bar at foobar.org' + /home/foo/.cdist/type/__foo + + +SEE ALSO +-------- +:strong:`cdist`\ (1) + + +AUTHORS +------- + +| Steven Armstrong +| Darko Poljak + + +COPYING +------- +Copyright \(C) 2019 Steven Armstrong, Darko Poljak. Free use of this software is +granted under the terms of the GNU General Public License v3 or later (GPLv3+). diff --git a/scripts/cdist-new-type b/scripts/cdist-new-type new file mode 100755 index 00000000..79dcfd90 --- /dev/null +++ b/scripts/cdist-new-type @@ -0,0 +1,159 @@ +#!/bin/sh + +basename="${0##*/}" + +if [ $# -lt 3 ] +then + printf "usage: %s TYPE-NAME AUTHOR-NAME AUTHOR-EMAIL [TYPE-BASE-PATH] + TYPE-NAME Name of the type. + AUTHOR-NAME Type author's full name. + AUTHOR-EMAIL Type author's email. + TYPE-BASE-PATH Path to the base directory of the type. If not set it defaults + to '\$PWD/type'.\n" "${basename}" + exit 1 +fi + +type_name="$1" +shift +author_name="$1" +shift +author_email="$1" +shift + +if [ $# -ge 1 ] +then + type_base_path="$1" + shift +else + #type_base_path=~/.cdist/type + type_base_path="$PWD/type" +fi + +error() { + printf "%s\n" "$*" >&2 +} + +die() { + error "$@" + exit 1 +} + +cd "$type_base_path" || die "Could not change to type directory: $type_base_path. +You have to specify type base path or run me from within a cdist conf directory, +e.g. ~/.cdist." + +year=$(date +%Y) +copyright="# $year $author_name ($author_email)" + +license="# 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 . +# +" + +set -e + +mkdir "$type_name" +cd "$type_name" + +### man page +header="cdist-type${type_name}(7)" +header_length="${#header}" +cat >> man.rst << DONE +$header +$(while [ "${header_length}" -gt 0 ]; do printf "="; header_length=$((header_length - 1)); done; printf "\n";) + +NAME +---- +cdist-type${type_name} - TODO + + +DESCRIPTION +----------- +This space intentionally left blank. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +BOOLEAN PARAMETERS +------------------ +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + # TODO + ${type_name} + + +SEE ALSO +-------- +:strong:\`TODO\`\\ (7) + + +AUTHORS +------- +$author_name <$author_email> + + +COPYING +------- +Copyright \(C) $year $author_name. 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. +DONE + +### manifest +cat >> manifest << DONE +#!/bin/sh -e +# +${copyright} +# +${license} + +os=\$(cat "\$__global/explorer/os") + +case "\$os" in + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "\$os" "\${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac +DONE +chmod +x manifest + +# gencode-remote +cat >> gencode-remote << DONE +#!/bin/sh -e +# +${copyright} +# +${license} +DONE +chmod +x gencode-remote + +printf "%s/%s\n" "$type_base_path" "$type_name" diff --git a/setup.py b/setup.py index 5f14a2f4..ae651125 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ setup( name="cdist", packages=["cdist", "cdist.core", "cdist.exec", "cdist.util", ], package_data={'cdist': package_data}, - scripts=["scripts/cdist", "scripts/cdist-dump"], + scripts=["scripts/cdist", "scripts/cdist-dump", "scripts/cdist-new-type"], version=cdist.version.VERSION, description="A Usable Configuration Management System", author="Nico Schottelius", From 4949af894e917ac57fb5365c7ea482770bb1c3ba Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Mon, 20 May 2019 18:50:25 +0200 Subject: [PATCH 1191/1332] Add type deprecation support. --- cdist/config.py | 11 ++++++++ cdist/core/cdist_type.py | 11 ++++++++ cdist/test/cdist_type/__init__.py | 10 ++++++++ .../fixtures/__deprecated/deprecated | 0 docs/changelog | 1 + docs/src/cdist-type.rst | 25 +++++++++++++++++++ 6 files changed, 58 insertions(+) create mode 100644 cdist/test/cdist_type/fixtures/__deprecated/deprecated diff --git a/cdist/config.py b/cdist/config.py index 30117382..1a0ab4d5 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -758,8 +758,19 @@ class Config(object): ("The requirements of the following objects could not be " "resolved:\n%s") % ("\n".join(info_string))) + def _handle_deprecation(self, cdist_object): + cdist_type = cdist_object.cdist_type + deprecated = cdist_type.deprecated + if deprecated is not None: + if deprecated: + self.log.warning("Type %s is deprecated: %s", cdist_type.name, + deprecated) + else: + self.log.warning("Type %s is deprecated.", cdist_type.name) + def object_prepare(self, cdist_object, transfer_type_explorers=True): """Prepare object: Run type explorer + manifest""" + self._handle_deprecation(cdist_object) self.log.verbose("Preparing object {}".format(cdist_object.name)) self.log.verbose( "Running manifest and explorers for " + cdist_object.name) diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 99e40e70..7cabd72f 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -133,6 +133,17 @@ class CdistType(object): cannot run in parallel.""" return os.path.isfile(os.path.join(self.absolute_path, "nonparallel")) + @property + def deprecated(self): + """Get type deprecation message. If message is None then type + is not deprecated.""" + deprecated_path = os.path.join(self.absolute_path, "deprecated") + try: + with open(deprecated_path, 'r') as f: + return f.read() + except FileNotFoundError: + return None + @property def explorers(self): """Return a list of available explorers""" diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index ca961170..ac84d874 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -123,6 +123,16 @@ class TypeTestCase(test.CdistTestCase): cdist_type = core.CdistType(base_path, '__not_nonparallel') self.assertFalse(cdist_type.is_nonparallel) + def test_deprecated(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, '__deprecated') + self.assertIsNotNone(cdist_type.deprecated) + + def test_not_deprecated(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, '__not_deprecated') + self.assertIsNone(cdist_type.deprecated) + def test_install_is_install(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__install') diff --git a/cdist/test/cdist_type/fixtures/__deprecated/deprecated b/cdist/test/cdist_type/fixtures/__deprecated/deprecated new file mode 100644 index 00000000..e69de29b diff --git a/docs/changelog b/docs/changelog index acf462f2..ba092840 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ next: * Type __consul: Add version 1.5.0 (Nico Schottelius) * Type __consul_agent: Add alpine support (Nico Schottelius) * New helper script: cdist-new-type (Steven Armstrong, Darko Poljak) + * Core: Add support for deprecated type marker (Darko Poljak) 5.0.2: 2019-05-17 * Type __package_apk: Fix @repo handling in explorer (Nico Schottelius) diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 880df819..dfad6fa0 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -71,6 +71,31 @@ when using -j option. Example of such a type is __package_dpkg type where dpkg i prevents to be run in more than one instance. +Deprecated types +----------------- +If a type is flagged with 'deprecated' marker then it is considered deprecated. +Upon it's usage cdist writes warning line. If 'deprecated' marker has content +then this content is printed as a deprecation messages, e.g.: + +.. code-block:: sh + + $ ls -l deprecated + -rw-r--r-- 1 darko darko 71 May 20 18:30 deprecated + $ cat deprecated + This type is deprecated. It will be removed in the next minor release. + $ echo '__foo foo' | ./bin/cdist config -i - 185.203.112.26 + WARNING: 185.203.112.26: Type __foo is deprecated: This type is deprecated. It will be removed in the next minor release. + +If 'deprecated' marker has no content then general message is printed, e.g.: + +.. code-block:: sh + + $ ls -l deprecated + -rw-r--r-- 1 darko darko 0 May 20 18:36 deprecated + $ echo '__bar foo' | ./bin/cdist config -i - 185.203.112.26 + WARNING: 185.203.112.26: Type __bar is deprecated. + + How to write a new type ----------------------- A type consists of From c58ae44409b7170ee44187eb3622612baf91ac51 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 22 May 2019 18:34:31 +0200 Subject: [PATCH 1192/1332] Release 5.1.0 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index ba092840..86ac6c9e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +5.1.0: 2019-05-22 * Type __consul: Add alpine support (Nico Schottelius) * Type __consul: Add version 1.5.0 (Nico Schottelius) * Type __consul_agent: Add alpine support (Nico Schottelius) From 1d57305d359fd773a540adcec8116d785f51e9db Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sat, 25 May 2019 15:58:39 +0200 Subject: [PATCH 1193/1332] Use gpg key, fallback to deprecated apt-key Fixes #762 --- cdist/conf/type/__apt_key/explorer/state | 18 ++++- cdist/conf/type/__apt_key/gencode-remote | 76 ++++++++++++++++++- cdist/conf/type/__apt_key/man.rst | 17 ++++- cdist/conf/type/__apt_key/manifest | 8 ++ .../type/__apt_key/parameter/default/keydir | 1 + cdist/conf/type/__apt_key/parameter/optional | 2 + 6 files changed, 114 insertions(+), 8 deletions(-) create mode 100755 cdist/conf/type/__apt_key/manifest create mode 100644 cdist/conf/type/__apt_key/parameter/default/keydir diff --git a/cdist/conf/type/__apt_key/explorer/state b/cdist/conf/type/__apt_key/explorer/state index f7940741..38f1bd3c 100755 --- a/cdist/conf/type/__apt_key/explorer/state +++ b/cdist/conf/type/__apt_key/explorer/state @@ -27,6 +27,18 @@ else keyid="$__object_id" fi -apt-key export "$keyid" | head -n 1 | grep -Fqe "BEGIN PGP PUBLIC KEY BLOCK" \ - && echo present \ - || echo absent +keydir="$(cat "$__object/parameter/keydir")" +keyfile="$keydir/$__object_id.gpg" + +if [ -d "$keydir" ] +then + if [ -f "$keyfile" ] + then echo present + else echo absent + fi +else + # fallback to deprecated apt-key + apt-key export "$keyid" | head -n 1 | grep -Fqe "BEGIN PGP PUBLIC KEY BLOCK" \ + && echo present \ + || echo absent +fi diff --git a/cdist/conf/type/__apt_key/gencode-remote b/cdist/conf/type/__apt_key/gencode-remote index 9c4fa00c..47c8bb49 100755 --- a/cdist/conf/type/__apt_key/gencode-remote +++ b/cdist/conf/type/__apt_key/gencode-remote @@ -31,12 +31,84 @@ if [ "$state_should" = "$state_is" ]; then exit 0 fi +keydir="$(cat "$__object/parameter/keydir")" +keyfile="$keydir/$__object_id.gpg" + case "$state_should" in present) keyserver="$(cat "$__object/parameter/keyserver")" - echo "apt-key adv --keyserver \"$keyserver\" --recv-keys \"$keyid\"" + + if [ -f "$__object/parameter/uri" ]; then + uri="$(cat "$__object/parameter/uri")" + + if [ -d "$keydir" ]; then + cat << EOF + +curl -s -L \\ + -o "$keyfile" \\ + "$uri" + +if grep -Fq 'BEGIN PGP PUBLIC KEY BLOCK' \\ + "$keyfile" +then + cat "$keyfile" \\ + | gpg --export > "$keyfile" +fi + +EOF + else + # fallback to deprecated apt-key + echo "curl -s -L '$uri' | apt-key add -" + fi + elif [ -d "$keydir" ]; then + tmp='/tmp/cdist_apt_key_tmp' + + # we need to kill gpg after 30 seconds, because gpg + # can get stuck if keyserver is not responding. + # exporting env var and not exit 1, + # because we need to clean up and kill dirmngr. + cat << EOF + +mkdir -m 700 -p "$tmp" + +if timeout 30s \\ + gpg --homedir "$tmp" \\ + --keyserver "$keyserver" \\ + --recv-keys "$keyid" +then + gpg --homedir "$tmp" \\ + --export "$keyid" \\ + > "$keyfile" +else + export GPG_GOT_STUCK=1 +fi + +GNUPGHOME="$tmp" gpgconf --kill dirmngr + +rm -rf "$tmp" + +if [ -n "\$GPG_GOT_STUCK" ] +then + echo "GPG GOT STUCK - no response from keyserver after 30 seconds" >&2 + exit 1 +fi + +EOF + else + # fallback to deprecated apt-key + echo "apt-key adv --keyserver \"$keyserver\" --recv-keys \"$keyid\"" + fi + + echo "added '$keyid'" >> "$__messages_out" ;; absent) - echo "apt-key del \"$keyid\"" + if [ -f "$keyfile" ]; then + echo "rm '$keyfile'" + else + # fallback to deprecated apt-key + echo "apt-key del \"$keyid\"" + fi + + echo "removed '$keyid'" >> "$__messages_out" ;; esac diff --git a/cdist/conf/type/__apt_key/man.rst b/cdist/conf/type/__apt_key/man.rst index 9009877e..234bc715 100644 --- a/cdist/conf/type/__apt_key/man.rst +++ b/cdist/conf/type/__apt_key/man.rst @@ -28,6 +28,12 @@ keyserver the keyserver from which to fetch the key. If omitted the default set in ./parameter/default/keyserver is used. +keydir + key save location, defaults to ``/etc/apt/trusted.pgp.d`` + +uri + the URI from which to download the key + EXAMPLES -------- @@ -47,15 +53,20 @@ EXAMPLES # same thing with other keyserver __apt_key UbuntuArchiveKey --keyid 437D05B5 --keyserver keyserver.ubuntu.com + # download key from the internet + __apt_key rabbitmq \ + --uri http://www.rabbitmq.com/rabbitmq-signing-key-public.asc + AUTHORS ------- Steven Armstrong +Ander Punnar COPYING ------- -Copyright \(C) 2011-2014 Steven Armstrong. 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 +Copyright \(C) 2011-2019 Steven Armstrong and 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/__apt_key/manifest b/cdist/conf/type/__apt_key/manifest new file mode 100755 index 00000000..010357cd --- /dev/null +++ b/cdist/conf/type/__apt_key/manifest @@ -0,0 +1,8 @@ +#!/bin/sh -e + +__package gnupg + +if [ -f "$__object/parameter/uri" ] +then __package curl +else __package dirmngr +fi diff --git a/cdist/conf/type/__apt_key/parameter/default/keydir b/cdist/conf/type/__apt_key/parameter/default/keydir new file mode 100644 index 00000000..190eb2de --- /dev/null +++ b/cdist/conf/type/__apt_key/parameter/default/keydir @@ -0,0 +1 @@ +/etc/apt/trusted.gpg.d diff --git a/cdist/conf/type/__apt_key/parameter/optional b/cdist/conf/type/__apt_key/parameter/optional index 18cf2586..de647375 100644 --- a/cdist/conf/type/__apt_key/parameter/optional +++ b/cdist/conf/type/__apt_key/parameter/optional @@ -1,3 +1,5 @@ state keyid keyserver +keydir +uri From 520cfeda989fbcaf12706a3540a9267ad23afdee Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 25 May 2019 16:10:18 +0200 Subject: [PATCH 1194/1332] ++ --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index 86ac6c9e..66140bb1 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,10 @@ Changelog --------- +next: + * Type __apt_key: Use gpg key, fallback to deprecated apt-key (Ander Punnar) + * Type __acl: Fix and improve (Ander Punnar) + 5.1.0: 2019-05-22 * Type __consul: Add alpine support (Nico Schottelius) * Type __consul: Add version 1.5.0 (Nico Schottelius) From 68837e45cc768fed8a891d22c60cde4ecb3ed62b Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sat, 25 May 2019 19:19:47 +0200 Subject: [PATCH 1195/1332] Document type stdin inside loop caveats --- docs/changelog | 1 + docs/src/cdist-type.rst | 67 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/docs/changelog b/docs/changelog index 66140bb1..1cded1f9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Type __apt_key: Use gpg key, fallback to deprecated apt-key (Ander Punnar) * Type __acl: Fix and improve (Ander Punnar) + * Documentation: Document type stdin inside loop caveats (Darko Poljak) 5.1.0: 2019-05-22 * Type __consul: Add alpine support (Nico Schottelius) diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index dfad6fa0..6cf83258 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -216,6 +216,73 @@ In the __file type, stdin is used as source for the file, if - is used for sourc .... +Stdin inside a loop +~~~~~~~~~~~~~~~~~~~ +Since cdist saves type's stdin content in the object as **$__object/stdin**, +so it can be accessed in manifest and gencode-* scripts, this can lead to +unexpected behavior. For example, suppose you have some type with the following +in its manifest: + +.. code-block:: sh + + if [ -f "$__object/parameter/foo" ] + then + while read -r l + do + __file "$l" + echo "$l" >&2 + done < "$__object/parameter/foo" + fi + +and init manifest: + +.. code-block:: sh + + __foo foo --foo a --foo b --foo c + +You expect that manifest stderr content is: + +.. code-block:: sh + + a + b + c + +and that files *a*, *b* and *c* are created. But all you get in manifest stderr +is: + +.. code-block:: sh + + a + +and only *a* file is created. + +When redirecting parameter *foo* file content to while's stdin that means that all +commands in while body have this same stdin. So when *__file* type gets executed, +cdist saves its stdin which means it gets the remaining content of parameter *foo* +file, i.e.: + +.. code-block:: sh + + b + c + +The solution is to make sure that your types inside such loops get their stdin +from somewhere else, e.g. for the above problem *__file* type can get empty +stdin from */dev/null*: + +.. code-block:: sh + + if [ -f "$__object/parameter/foo" ] + then + while read -r l + do + __file "$l" < /dev/null + echo "$l" >&2 + done < "$__object/parameter/foo" + fi + + Writing the manifest -------------------- In the manifest of a type you can use other types, so your type extends From 8315677ad1fc6dff6e10cb78754cbb5748340811 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Tue, 28 May 2019 17:53:34 +0200 Subject: [PATCH 1196/1332] Release 5.1.1 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 1cded1f9..2f20fd84 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +5.1.1: 2019-05-28 * Type __apt_key: Use gpg key, fallback to deprecated apt-key (Ander Punnar) * Type __acl: Fix and improve (Ander Punnar) * Documentation: Document type stdin inside loop caveats (Darko Poljak) From 55ba49efacc962d3233e28483b4237059356f887 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 19 Jun 2019 18:19:32 +0200 Subject: [PATCH 1197/1332] Add support for deprecated type parameters --- cdist/config.py | 5 ++++ cdist/core/cdist_type.py | 21 ++++++++++++++++ cdist/test/cdist_type/__init__.py | 12 ++++++++++ .../__with_deprecated_parameters/deprecated | 0 .../parameter/deprecated | 2 ++ .../parameter/optional | 4 ++++ docs/src/cdist-type.rst | 24 ++++++++++++++++++- 7 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 cdist/test/cdist_type/fixtures/__with_deprecated_parameters/deprecated create mode 100644 cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated create mode 100644 cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/optional diff --git a/cdist/config.py b/cdist/config.py index 1a0ab4d5..6622823b 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -767,6 +767,11 @@ class Config(object): deprecated) else: self.log.warning("Type %s is deprecated.", cdist_type.name) + for param in cdist_object.parameters: + if param in cdist_type.deprecated_parameters: + self.log.warning(("%s parameter of type %s is deprecated, " + "see man page for details"), + param, cdist_type.name) def object_prepare(self, cdist_object, transfer_type_explorers=True): """Prepare object: Run type explorer + manifest""" diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 7cabd72f..48926a03 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -69,6 +69,7 @@ class CdistType(object): self.__optional_multiple_parameters = None self.__boolean_parameters = None self.__parameter_defaults = None + self.__deprecated_parameters = None def __hash__(self): return hash(self.name) @@ -275,3 +276,23 @@ class CdistType(object): finally: self.__parameter_defaults = defaults return self.__parameter_defaults + + @property + def deprecated_parameters(self): + """Return a list of deprecated parameters""" + if not self.__deprecated_parameters: + parameters = [] + try: + with open(os.path.join(self.absolute_path, + "parameter", + "deprecated")) as fd: + for line in fd: + line = line.strip() + if line: + parameters.append(line) + except EnvironmentError: + # error ignored + pass + finally: + self.__deprecated_parameters = parameters + return self.__deprecated_parameters diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index ac84d874..9eee395c 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -200,3 +200,15 @@ class TypeTestCase(test.CdistTestCase): self.assertEqual( list(sorted(cdist_type.parameter_defaults.keys())), ['bar', 'foo']) + + def test_without_deprecated_parameters(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, + '__without_deprecated_parameters') + self.assertEqual(cdist_type.deprecated_parameters, []) + + def test_with_deprecated_parameters(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, '__with_deprecated_parameters') + self.assertEqual(cdist_type.deprecated_parameters, + ['eggs', 'spam']) diff --git a/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/deprecated b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/deprecated new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated new file mode 100644 index 00000000..81830edb --- /dev/null +++ b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated @@ -0,0 +1,2 @@ +eggs +spam diff --git a/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/optional b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/optional new file mode 100644 index 00000000..7c804d5f --- /dev/null +++ b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/optional @@ -0,0 +1,4 @@ +spam +eggs +sausage +spam diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 6cf83258..623ba481 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -74,7 +74,7 @@ prevents to be run in more than one instance. Deprecated types ----------------- If a type is flagged with 'deprecated' marker then it is considered deprecated. -Upon it's usage cdist writes warning line. If 'deprecated' marker has content +When it is used cdist writes warning line. If 'deprecated' marker has content then this content is printed as a deprecation messages, e.g.: .. code-block:: sh @@ -186,6 +186,28 @@ Example: (e.g. in cdist/conf/type/__nginx_vhost/manifest) fi +Deprecated parameters +--------------------- +To deprecate type parameters one can declare a newline separated file +**parameter/deprecated** where each line contains deprecated parameter. +When it is used cdist writes warning line, e.g.: + +.. code-block:: sh + + $ cat parameter/optional_multiple + foo + spam + eggs + $ cat parameter/deprecated + spam + eggs + $ echo '__foo foo --foo foo --spam spam' | ./bin/cdist config -i - 185.203.112.26 + WARNING: 185.203.112.26: spam parameter of type __foo is deprecated, see man page for details + $ echo '__foo foo --foo foo --eggs eggs --spam spam' | ./bin/cdist config -i - 185.203.112.26 + WARNING: 185.203.112.26: spam parameter of type __foo is deprecated, see man page for details + WARNING: 185.203.112.26: eggs parameter of type __foo is deprecated, see man page for details + + Input from stdin ---------------- Every type can access what has been written on stdin when it has been called. From 3cb4e76175c06370cc7b69a326c9ae1c6c0b0c37 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 19 Jun 2019 18:19:32 +0200 Subject: [PATCH 1198/1332] Allow custom message for each deprecated parameter --- cdist/config.py | 11 +++++-- cdist/core/cdist_type.py | 24 +++++++------- cdist/test/cdist_type/__init__.py | 9 ++++-- .../parameter/deprecated | 2 -- .../parameter/deprecated/eggs | 1 + .../{deprecated => parameter/deprecated/spam} | 0 .../parameter/optional | 1 - docs/src/cdist-type.rst | 31 ++++++++++--------- 8 files changed, 44 insertions(+), 35 deletions(-) delete mode 100644 cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated create mode 100644 cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated/eggs rename cdist/test/cdist_type/fixtures/__with_deprecated_parameters/{deprecated => parameter/deprecated/spam} (100%) diff --git a/cdist/config.py b/cdist/config.py index 6622823b..26d07fc4 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -769,9 +769,14 @@ class Config(object): self.log.warning("Type %s is deprecated.", cdist_type.name) for param in cdist_object.parameters: if param in cdist_type.deprecated_parameters: - self.log.warning(("%s parameter of type %s is deprecated, " - "see man page for details"), - param, cdist_type.name) + msg = cdist_type.deprecated_parameters[param] + if msg: + format = "%s parameter of type %s is deprecated: %s" + args = [param, cdist_type.name, msg] + else: + format = "%s parameter of type %s is deprecated." + args = [param, cdist_type.name] + self.log.warning(format, *args) def object_prepare(self, cdist_object, transfer_type_explorers=True): """Prepare object: Run type explorer + manifest""" diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 48926a03..4500f50d 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -279,20 +279,20 @@ class CdistType(object): @property def deprecated_parameters(self): - """Return a list of deprecated parameters""" if not self.__deprecated_parameters: - parameters = [] + deprecated = {} try: - with open(os.path.join(self.absolute_path, - "parameter", - "deprecated")) as fd: - for line in fd: - line = line.strip() - if line: - parameters.append(line) + deprecated_dir = os.path.join(self.absolute_path, + "parameter", + "deprecated") + for name in cdist.core.listdir(deprecated_dir): + try: + with open(os.path.join(deprecated_dir, name)) as fd: + deprecated[name] = fd.read().strip() + except EnvironmentError: + pass # Swallow errors raised by open() or read() except EnvironmentError: - # error ignored - pass + pass # Swallow error raised by os.listdir() finally: - self.__deprecated_parameters = parameters + self.__deprecated_parameters = deprecated return self.__deprecated_parameters diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index 9eee395c..a51a1e6f 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -205,10 +205,13 @@ class TypeTestCase(test.CdistTestCase): base_path = fixtures cdist_type = core.CdistType(base_path, '__without_deprecated_parameters') - self.assertEqual(cdist_type.deprecated_parameters, []) + self.assertEqual(cdist_type.deprecated_parameters, {}) def test_with_deprecated_parameters(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__with_deprecated_parameters') - self.assertEqual(cdist_type.deprecated_parameters, - ['eggs', 'spam']) + self.assertTrue('eggs' in cdist_type.deprecated_parameters) + self.assertTrue('spam' in cdist_type.deprecated_parameters) + self.assertEqual(cdist_type.deprecated_parameters['eggs'], + 'Deprecated') + self.assertEqual(cdist_type.deprecated_parameters['spam'], '') diff --git a/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated deleted file mode 100644 index 81830edb..00000000 --- a/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated +++ /dev/null @@ -1,2 +0,0 @@ -eggs -spam diff --git a/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated/eggs b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated/eggs new file mode 100644 index 00000000..69d9f456 --- /dev/null +++ b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated/eggs @@ -0,0 +1 @@ +Deprecated diff --git a/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/deprecated b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated/spam similarity index 100% rename from cdist/test/cdist_type/fixtures/__with_deprecated_parameters/deprecated rename to cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/deprecated/spam diff --git a/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/optional b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/optional index 7c804d5f..bfe09199 100644 --- a/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/optional +++ b/cdist/test/cdist_type/fixtures/__with_deprecated_parameters/parameter/optional @@ -1,4 +1,3 @@ spam eggs sausage -spam diff --git a/docs/src/cdist-type.rst b/docs/src/cdist-type.rst index 623ba481..582c0938 100644 --- a/docs/src/cdist-type.rst +++ b/docs/src/cdist-type.rst @@ -188,24 +188,27 @@ Example: (e.g. in cdist/conf/type/__nginx_vhost/manifest) Deprecated parameters --------------------- -To deprecate type parameters one can declare a newline separated file -**parameter/deprecated** where each line contains deprecated parameter. -When it is used cdist writes warning line, e.g.: +To deprecate type parameters one can declare a file for each deprecated +parameter under **parameter/deprecated** directory. + +When such parameter is used cdist writes warning line with deprecation message. +If such file has content then this content is printed as deprecation message. +If there is no content then generic parameter deprecation message is printed. + +Example: .. code-block:: sh - $ cat parameter/optional_multiple - foo - spam - eggs - $ cat parameter/deprecated - spam - eggs - $ echo '__foo foo --foo foo --spam spam' | ./bin/cdist config -i - 185.203.112.26 - WARNING: 185.203.112.26: spam parameter of type __foo is deprecated, see man page for details + $ ls parameter/deprecated/ + eggs spam + $ cat parameter/deprecated/eggs + eggs parameter is deprecated, please use multiple egg parameter. + $ cat parameter/deprecated/spam + $ echo '__foo foo --foo foo --eggs eggs' | ./bin/cdist config -i - 185.203.112.26 + WARNING: 185.203.112.26: eggs parameter of type __foo is deprecated: eggs parameter is deprecated, please use multiple egg parameter. $ echo '__foo foo --foo foo --eggs eggs --spam spam' | ./bin/cdist config -i - 185.203.112.26 - WARNING: 185.203.112.26: spam parameter of type __foo is deprecated, see man page for details - WARNING: 185.203.112.26: eggs parameter of type __foo is deprecated, see man page for details + WARNING: 185.203.112.26: spam parameter of type __foo is deprecated. + WARNING: 185.203.112.26: eggs parameter of type __foo is deprecated: eggs parameter is deprecated, please use multiple egg parameter. Input from stdin From d723f60673c35b91017319a6699c53e3d0f38425 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 20 Jun 2019 18:12:50 +0200 Subject: [PATCH 1199/1332] ++changelog --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 2f20fd84..a79b116d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Core: Add support for type parameters deprecation (Darko Poljak) + 5.1.1: 2019-05-28 * Type __apt_key: Use gpg key, fallback to deprecated apt-key (Ander Punnar) * Type __acl: Fix and improve (Ander Punnar) From 91a6ecc70173638aae928ddadabd93d9d46f097e Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Thu, 30 May 2019 23:04:46 +0300 Subject: [PATCH 1200/1332] __acl: rewrite --- cdist/conf/type/__acl/explorer/checks | 32 ++++------ cdist/conf/type/__acl/gencode-remote | 54 ++++++++--------- cdist/conf/type/__acl/man.rst | 59 ++++++++++--------- cdist/conf/type/__acl/parameter/optional | 2 - .../type/__acl/parameter/optional_multiple | 2 - .../type/__acl/parameter/required_multiple | 1 + 6 files changed, 66 insertions(+), 84 deletions(-) delete mode 100644 cdist/conf/type/__acl/parameter/optional delete mode 100644 cdist/conf/type/__acl/parameter/optional_multiple create mode 100644 cdist/conf/type/__acl/parameter/required_multiple diff --git a/cdist/conf/type/__acl/explorer/checks b/cdist/conf/type/__acl/explorer/checks index a2fcf44d..5b379a08 100755 --- a/cdist/conf/type/__acl/explorer/checks +++ b/cdist/conf/type/__acl/explorer/checks @@ -20,29 +20,17 @@ # TODO check if filesystem has ACL turned on etc -for parameter in user group +grep -E '^(default:)?(user|group):' "$__object/parameter/acl" \ +| while read -r acl do - if [ ! -f "$__object/parameter/$parameter" ] + param="$( echo "$acl" | awk -F: '{print $(NF-2)}' )" + check="$( echo "$acl" | awk -F: '{print $(NF-1)}' )" + + [ "$param" = 'user' ] && db=passwd || db="$param" + + if ! getent "$db" "$check" > /dev/null then - continue + echo "missing $param '$check'" >&2 + exit 1 fi - - while read -r acl - do - check="$( echo "$acl" | awk -F: '{print $1}' )" - - if [ "$parameter" = 'user' ] - then - getent_db=passwd - else - getent_db="$parameter" - fi - - if ! getent "$getent_db" "$check" > /dev/null - then - echo "missing $parameter '$check'" >&2 - exit 1 - fi - done \ - < "$__object/parameter/$parameter" done diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index f5b0474f..3c7085f0 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -24,41 +24,35 @@ file_is="$( cat "$__object/explorer/file_is" )" os="$( cat "$__global/explorer/os" )" -acl_is="$( cat "$__object/explorer/acl_is" )" - acl_path="/$__object_id" -if [ -f "$__object/parameter/default" ] && [ "$file_is" = 'directory' ] +acl_is="$( cat "$__object/explorer/acl_is" )" + +acl_should="$( cat "$__object/parameter/acl" )" + +if [ -f "$__object/parameter/default" ] then - set_default=1 -else - set_default=0 + acl_should="$( echo "$acl_should" \ + | sed 's/^default://' \ + | sort -u \ + | sed 's/\(.*\)/default:\1\n\1/' )" fi -acl_should="$( for parameter in user group mask other -do - if [ ! -f "$__object/parameter/$parameter" ] - then - continue - fi +if [ "$file_is" = 'regular' ] \ + && echo "$acl_should" | grep -Eq '^default:' +then + # only directories can have default ACLs, + # but instead of error, + # let's just remove default entries + acl_should="$( echo "$acl_should" | grep -Ev '^default:' )" +fi - while read -r acl - do - if echo "$acl" | awk -F: '{ print $NF }' | grep -Fq 'X' - then - [ "$file_is" = 'directory' ] && rep=x || rep=- +if echo "$acl_should" | awk -F: '{ print $NF }' | grep -Fq 'X' +then + [ "$file_is" = 'directory' ] && rep=x || rep=- - acl="$( echo "$acl" | sed "s/\\(.*\\)X/\\1$rep/" )" - fi - - echo "$parameter" | grep -Eq '(mask|other)' && sep=:: || sep=: - - echo "$parameter$sep$acl" - - [ "$set_default" = '1' ] && echo "default:$parameter$sep$acl" - done \ - < "$__object/parameter/$parameter" -done )" + acl_should="$( echo "$acl_should" | sed "s/\\(.*\\)X/\\1$rep/" )" +fi setfacl_exec='setfacl' @@ -76,7 +70,7 @@ if [ -f "$__object/parameter/remove" ] then echo "$acl_is" | while read -r acl do - # Skip wanted ACL entries which already exist + # skip wanted ACL entries which already exist # and skip mask and other entries, because we # can't actually remove them, but only change. if echo "$acl_should" | grep -Eq "^$acl" \ @@ -103,7 +97,7 @@ do if echo "$os" | grep -Fq 'freebsd' \ && echo "$acl" | grep -Eq '^default:' then - echo "setting default ACL in $os is currently not supported. sorry :(" >&2 + echo "setting default ACL in $os is currently not supported" >&2 else echo "$setfacl_exec -m \"$acl\" \"$acl_path\"" echo "added '$acl'" >> "$__messages_out" diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst index d066aae5..a71e0d3c 100644 --- a/cdist/conf/type/__acl/man.rst +++ b/cdist/conf/type/__acl/man.rst @@ -8,42 +8,30 @@ cdist-type__acl - Set ACL entries DESCRIPTION ----------- -ACL must be defined as 3-symbol combination, using ``r``, ``w``, ``x`` and ``-``. - Fully supported and tested on Linux (ext4 filesystem), partial support for FreeBSD. See ``setfacl`` and ``acl`` manpages for more details. -OPTIONAL MULTIPLE PARAMETERS +REQUIRED MULTIPLE PARAMETERS ---------------------------- -user - Add user ACL entry. - -group - Add group ACL entry. - - -OPTIONAL PARAMETERS -------------------- -mask - Add mask ACL entry. - -other - Add other ACL entry. +acl + Set ACL entry following ``getfacl`` output syntax. BOOLEAN PARAMETERS ------------------ +default + Set all ACL entries as default too. + Only directories can have default ACLs. + Setting default ACL in FreeBSD is currently not supported. + recursive Make ``setfacl`` recursive (Linux only), but not ``getfacl`` in explorer. -default - Add default ACL entries (FreeBSD not supported). - remove - Remove undefined ACL entries (Solaris not supported). - ACL entries for ``mask`` and ``other`` can't be removed. + Remove undefined ACL entries. + ``mask`` and ``other`` entries can't be removed, but only changed. EXAMPLES @@ -52,15 +40,30 @@ EXAMPLES .. code-block:: sh __acl /srv/project \ + --default \ --recursive \ + --remove \ + --acl user:alice:rwx \ + --acl user:bob:r-x \ + --acl group:project-group:rwx \ + --acl group:some-other-group:r-x \ + --acl mask::r-x \ + --acl other::r-x + + # give Alice read-only access to subdir, + # but don't allow her to see parent content. + + __acl /srv/project2 \ + --remove \ + --acl default:group:secret-project:rwx \ + --acl group:secret-project:rwx \ + --acl user:alice:--x + + __acl /srv/project2/subdir \ --default \ --remove \ - --user alice:rwx \ - --user bob:r-x \ - --group project-group:rwx \ - --group some-other-group:r-x \ - --mask r-x \ - --other r-x + --acl group:secret-project:rwx \ + --acl user:alice:r-x AUTHORS diff --git a/cdist/conf/type/__acl/parameter/optional b/cdist/conf/type/__acl/parameter/optional deleted file mode 100644 index 4b32086b..00000000 --- a/cdist/conf/type/__acl/parameter/optional +++ /dev/null @@ -1,2 +0,0 @@ -mask -other diff --git a/cdist/conf/type/__acl/parameter/optional_multiple b/cdist/conf/type/__acl/parameter/optional_multiple deleted file mode 100644 index 22f5a52c..00000000 --- a/cdist/conf/type/__acl/parameter/optional_multiple +++ /dev/null @@ -1,2 +0,0 @@ -user -group diff --git a/cdist/conf/type/__acl/parameter/required_multiple b/cdist/conf/type/__acl/parameter/required_multiple new file mode 100644 index 00000000..39fead3b --- /dev/null +++ b/cdist/conf/type/__acl/parameter/required_multiple @@ -0,0 +1 @@ +acl From a5df0badaf1d38bc0f47e3e30bfd9f2e683677d1 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Sun, 16 Jun 2019 15:18:39 +0300 Subject: [PATCH 1201/1332] __acl: add compatibility for deprecated parameters --- cdist/conf/type/__acl/explorer/checks | 27 ++++++++++--------- cdist/conf/type/__acl/gencode-remote | 22 ++++++++++++++- cdist/conf/type/__acl/man.rst | 6 +++++ cdist/conf/type/__acl/parameter/optional | 2 ++ .../type/__acl/parameter/optional_multiple | 3 +++ .../type/__acl/parameter/required_multiple | 1 - 6 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 cdist/conf/type/__acl/parameter/optional create mode 100644 cdist/conf/type/__acl/parameter/optional_multiple delete mode 100644 cdist/conf/type/__acl/parameter/required_multiple diff --git a/cdist/conf/type/__acl/explorer/checks b/cdist/conf/type/__acl/explorer/checks index 5b379a08..70bb0412 100755 --- a/cdist/conf/type/__acl/explorer/checks +++ b/cdist/conf/type/__acl/explorer/checks @@ -20,17 +20,20 @@ # TODO check if filesystem has ACL turned on etc -grep -E '^(default:)?(user|group):' "$__object/parameter/acl" \ -| while read -r acl -do - param="$( echo "$acl" | awk -F: '{print $(NF-2)}' )" - check="$( echo "$acl" | awk -F: '{print $(NF-1)}' )" +if [ -f "$__object/parameter/acl" ] +then + grep -E '^(default:)?(user|group):' "$__object/parameter/acl" \ + | while read -r acl + do + param="$( echo "$acl" | awk -F: '{print $(NF-2)}' )" + check="$( echo "$acl" | awk -F: '{print $(NF-1)}' )" - [ "$param" = 'user' ] && db=passwd || db="$param" + [ "$param" = 'user' ] && db=passwd || db="$param" - if ! getent "$db" "$check" > /dev/null - then - echo "missing $param '$check'" >&2 - exit 1 - fi -done + if ! getent "$db" "$check" > /dev/null + then + echo "missing $param '$check'" >&2 + exit 1 + fi + done +fi diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote index 3c7085f0..6dab4d09 100755 --- a/cdist/conf/type/__acl/gencode-remote +++ b/cdist/conf/type/__acl/gencode-remote @@ -28,7 +28,27 @@ acl_path="/$__object_id" acl_is="$( cat "$__object/explorer/acl_is" )" -acl_should="$( cat "$__object/parameter/acl" )" +if [ -f "$__object/parameter/acl" ] +then + acl_should="$( cat "$__object/parameter/acl" )" +elif + [ -f "$__object/parameter/user" ] \ + || [ -f "$__object/parameter/group" ] \ + || [ -f "$__object/parameter/mask" ] \ + || [ -f "$__object/parameter/other" ] +then + acl_should="$( for param in user group mask other + do + [ ! -f "$__object/parameter/$param" ] && continue + + echo "$param" | grep -Eq 'mask|other' && sep=:: || sep=: + + echo "$param$sep$( cat "$__object/parameter/$param" )" + done )" +else + echo 'no parameters set' >&2 + exit 1 +fi if [ -f "$__object/parameter/default" ] then diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst index a71e0d3c..85e946ce 100644 --- a/cdist/conf/type/__acl/man.rst +++ b/cdist/conf/type/__acl/man.rst @@ -34,6 +34,12 @@ remove ``mask`` and ``other`` entries can't be removed, but only changed. +DEPRECATED PARAMETERS +--------------------- +Parameters ``user``, ``group``, ``mask`` and ``other`` are deprecated and they +will be removed in future versions. Please use ``acl`` parameter instead. + + EXAMPLES -------- diff --git a/cdist/conf/type/__acl/parameter/optional b/cdist/conf/type/__acl/parameter/optional new file mode 100644 index 00000000..4b32086b --- /dev/null +++ b/cdist/conf/type/__acl/parameter/optional @@ -0,0 +1,2 @@ +mask +other diff --git a/cdist/conf/type/__acl/parameter/optional_multiple b/cdist/conf/type/__acl/parameter/optional_multiple new file mode 100644 index 00000000..95c25d55 --- /dev/null +++ b/cdist/conf/type/__acl/parameter/optional_multiple @@ -0,0 +1,3 @@ +acl +user +group diff --git a/cdist/conf/type/__acl/parameter/required_multiple b/cdist/conf/type/__acl/parameter/required_multiple deleted file mode 100644 index 39fead3b..00000000 --- a/cdist/conf/type/__acl/parameter/required_multiple +++ /dev/null @@ -1 +0,0 @@ -acl From a4bc051ad9ecb538d5d239a03990b788acf81d88 Mon Sep 17 00:00:00 2001 From: Ander Punnar Date: Fri, 21 Jun 2019 13:02:44 +0300 Subject: [PATCH 1202/1332] __acl: use type deprecation --- cdist/conf/type/__acl/parameter/deprecated/group | 1 + cdist/conf/type/__acl/parameter/deprecated/mask | 1 + cdist/conf/type/__acl/parameter/deprecated/other | 1 + cdist/conf/type/__acl/parameter/deprecated/user | 1 + 4 files changed, 4 insertions(+) create mode 100644 cdist/conf/type/__acl/parameter/deprecated/group create mode 100644 cdist/conf/type/__acl/parameter/deprecated/mask create mode 100644 cdist/conf/type/__acl/parameter/deprecated/other create mode 100644 cdist/conf/type/__acl/parameter/deprecated/user diff --git a/cdist/conf/type/__acl/parameter/deprecated/group b/cdist/conf/type/__acl/parameter/deprecated/group new file mode 100644 index 00000000..94e14159 --- /dev/null +++ b/cdist/conf/type/__acl/parameter/deprecated/group @@ -0,0 +1 @@ +see manual for details diff --git a/cdist/conf/type/__acl/parameter/deprecated/mask b/cdist/conf/type/__acl/parameter/deprecated/mask new file mode 100644 index 00000000..94e14159 --- /dev/null +++ b/cdist/conf/type/__acl/parameter/deprecated/mask @@ -0,0 +1 @@ +see manual for details diff --git a/cdist/conf/type/__acl/parameter/deprecated/other b/cdist/conf/type/__acl/parameter/deprecated/other new file mode 100644 index 00000000..94e14159 --- /dev/null +++ b/cdist/conf/type/__acl/parameter/deprecated/other @@ -0,0 +1 @@ +see manual for details diff --git a/cdist/conf/type/__acl/parameter/deprecated/user b/cdist/conf/type/__acl/parameter/deprecated/user new file mode 100644 index 00000000..94e14159 --- /dev/null +++ b/cdist/conf/type/__acl/parameter/deprecated/user @@ -0,0 +1 @@ +see manual for details From 8881ff22246afb78e71a7b992fcb032eb4ce1e90 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 21 Jun 2019 12:55:33 +0200 Subject: [PATCH 1203/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index a79b116d..2548b4ce 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Core: Add support for type parameters deprecation (Darko Poljak) + * Type __acl: Rewrite and improve (Ander Punnar) 5.1.1: 2019-05-28 * Type __apt_key: Use gpg key, fallback to deprecated apt-key (Ander Punnar) From 6915d300153e690e569f3f691d8bdec4952d91a6 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 21 Jun 2019 14:13:25 +0200 Subject: [PATCH 1204/1332] Release 5.1.2 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 2548b4ce..4952991b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +5.1.2: 2019-06-21 * Core: Add support for type parameters deprecation (Darko Poljak) * Type __acl: Rewrite and improve (Ander Punnar) From 5c11c15ae4f7962588f88a9fcdad5bc812d819d0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 23 Jun 2019 19:55:37 +0200 Subject: [PATCH 1205/1332] Overcome bash CDPATH issue Thanks to Dmitry Bogatov. --- Makefile | 6 +++--- docs/changelog | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b739ab1f..fa3327d1 100644 --- a/Makefile +++ b/Makefile @@ -31,9 +31,9 @@ help: @echo "docs-clean clean documentation" @echo "clean clean" -DOCS_SRC_DIR=docs/src -SPEECHDIR=docs/speeches -TYPEDIR=cdist/conf/type +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 diff --git a/docs/changelog b/docs/changelog index 4952991b..e4e312fd 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Build: Overcome bash CDPATH when building docs (Dmitry Bogatov) + 5.1.2: 2019-06-21 * Core: Add support for type parameters deprecation (Darko Poljak) * Type __acl: Rewrite and improve (Ander Punnar) From 6bb58f882086f5f46c20355f768ee1095540f4d2 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Wed, 24 Jul 2019 13:32:39 +0200 Subject: [PATCH 1206/1332] Updated the __grafana_dashboard type for the new package repository - Changed the signing key uri - Changed the repo uri --- cdist/conf/type/__grafana_dashboard/manifest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest index 9cd1465d..c1fe9416 100755 --- a/cdist/conf/type/__grafana_dashboard/manifest +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -21,10 +21,10 @@ case $os in __apt_key_uri grafana \ --name 'Grafana Release Signing Key' \ - --uri https://packagecloud.io/gpg.key + --uri https://packages.grafana.com/gpg.key require="$require __apt_key_uri/grafana" __apt_source grafana \ - --uri https://packagecloud.io/grafana/stable/debian/ \ + --uri https://packages.grafana.com/oss/deb \ --distribution $apt_source_distribution \ --component main From a70d2e0af5a7b842d8a1b0ceb03abb90a770e001 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Wed, 24 Jul 2019 13:35:46 +0200 Subject: [PATCH 1207/1332] Had to change the apt_source_distribution to stable, since the repository doesn't differ in distributions --- cdist/conf/type/__grafana_dashboard/manifest | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__grafana_dashboard/manifest b/cdist/conf/type/__grafana_dashboard/manifest index c1fe9416..e652202b 100755 --- a/cdist/conf/type/__grafana_dashboard/manifest +++ b/cdist/conf/type/__grafana_dashboard/manifest @@ -8,10 +8,12 @@ case $os in debian|devuan) case $os_version in 8*|jessie) - apt_source_distribution=jessie + # Differntation not needed anymore + apt_source_distribution=stable ;; 9*|ascii/ceres|ascii) - apt_source_distribution=stretch + # Differntation not needed anymore + apt_source_distribution=stable ;; *) echo "Don't know how to install Grafana on $os $os_version. Send us a pull request!" >&2 From f7efde0d0a28cd0e82f6126abcbc7f797a0602b8 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 25 Jul 2019 08:06:58 +0200 Subject: [PATCH 1208/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e4e312fd..ae2eac8d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -3,6 +3,7 @@ Changelog next: * Build: Overcome bash CDPATH when building docs (Dmitry Bogatov) + * Type __grafana_dashboard: Update distribution name, package signing key URI and repository URI (Dominique Roux) 5.1.2: 2019-06-21 * Core: Add support for type parameters deprecation (Darko Poljak) From 031d59c82ccadb931db70bc3c22a013f1104b8e5 Mon Sep 17 00:00:00 2001 From: Dominique Roux Date: Sun, 4 Aug 2019 21:23:44 +0200 Subject: [PATCH 1209/1332] Added Devuan support for __docker type --- cdist/conf/type/__docker/manifest | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index 04a9ff27..f20337d7 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -64,6 +64,43 @@ case "$os" in require="__apt_source/docker" __package docker-ce --state "${state}" fi ;; + devuan) + os_version="$(cat "$__global/explorer/os_version")" + + case "$os_version" in + ascii) + distributione="stretch" + ;; + jessie) + distribution="jessie" + ;; + *) + echo "Your devuan release ($os_version) is currently not supported by this type (${__type##*/}).">&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 + ;; + esac + + if [ "${state}" = "present" ]; then + __package apt-transport-https + __package ca-certificates + __package gnupg2 + fi + __apt_key_uri docker --name "Docker Release (CE deb) " \ + --uri "https://download.docker.com/linux/${os}/gpg" --state "${state}" + + require="__apt_key_uri/docker" __apt_source docker \ + --uri "https://download.docker.com/linux/${os}" \ + --distribution "${distribution}" \ + --state "${state}" \ + --component "stable" + if [ "$version" != "latest" ]; then + require="__apt_source/docker" __package docker-ce --version "${version}" --state "${state}" + else + require="__apt_source/docker" __package docker-ce --state "${state}" + fi + + ;; *) echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2 echo "Please contribute an implementation for it if you can." >&2 From c6b739b5b6de870e629d421b140587278777b5de Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 4 Aug 2019 21:52:59 +0200 Subject: [PATCH 1210/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ae2eac8d..57412999 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Build: Overcome bash CDPATH when building docs (Dmitry Bogatov) * Type __grafana_dashboard: Update distribution name, package signing key URI and repository URI (Dominique Roux) + * Type __docker: Add devuan support (Dominique Roux) 5.1.2: 2019-06-21 * Core: Add support for type parameters deprecation (Darko Poljak) From 2f7dc5a65d264d7f210ab06834980d8782c4a565 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Sun, 4 Aug 2019 21:54:13 +0200 Subject: [PATCH 1211/1332] Fix variable typo --- cdist/conf/type/__docker/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker/manifest b/cdist/conf/type/__docker/manifest index f20337d7..6a57d85a 100755 --- a/cdist/conf/type/__docker/manifest +++ b/cdist/conf/type/__docker/manifest @@ -69,7 +69,7 @@ case "$os" in case "$os_version" in ascii) - distributione="stretch" + distribution="stretch" ;; jessie) distribution="jessie" From c0aa2214aa5b34ae1a073682fc3bd6545ceacf36 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Aug 2019 14:19:54 +0200 Subject: [PATCH 1212/1332] [letsencrypt] add support for devuan/beowulf --- cdist/conf/type/__letsencrypt_cert/manifest | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cdist/conf/type/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest index d6892c9b..072fa398 100755 --- a/cdist/conf/type/__letsencrypt_cert/manifest +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -67,6 +67,9 @@ if [ -z "${certbot_fullpath}" ]; then require="__apt_source/ascii-backports" __package_apt certbot \ --target-release ascii-backports ;; + bewoulf*) + __package_apt certbot + ;; *) echo "Unsupported OS version: $os_version" >&2 exit 1 From 7182de596891f963c6867c1d0b08a5276450c56f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Aug 2019 14:20:14 +0200 Subject: [PATCH 1213/1332] ++changes --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ae2eac8d..b13e54fa 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,7 @@ Changelog next: * Build: Overcome bash CDPATH when building docs (Dmitry Bogatov) * Type __grafana_dashboard: Update distribution name, package signing key URI and repository URI (Dominique Roux) + * Type __letsencrypt_cert: Add Devuan Beowulf support (Nico Schottelius) 5.1.2: 2019-06-21 * Core: Add support for type parameters deprecation (Darko Poljak) From a86893889b3a9d84712a71a23da60461671ca0e9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Aug 2019 14:24:11 +0200 Subject: [PATCH 1214/1332] [letsencrypt] devuan/ascii: only install certbot package It seems python-certbot is gone --- cdist/conf/type/__letsencrypt_cert/manifest | 2 -- 1 file changed, 2 deletions(-) diff --git a/cdist/conf/type/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest index 072fa398..d598949e 100755 --- a/cdist/conf/type/__letsencrypt_cert/manifest +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -62,8 +62,6 @@ if [ -z "${certbot_fullpath}" ]; then --distribution ascii-backports \ --component main - require="__apt_source/ascii-backports" __package_apt python-certbot \ - --target-release ascii-backports require="__apt_source/ascii-backports" __package_apt certbot \ --target-release ascii-backports ;; From 6c780c24c7d1fdf8a316fef98a304c07ffd57d0e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 15 Aug 2019 14:25:16 +0200 Subject: [PATCH 1215/1332] ++changes --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 6e20c64e..f3b84ba8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ next: * Build: Overcome bash CDPATH when building docs (Dmitry Bogatov) * Type __grafana_dashboard: Update distribution name, package signing key URI and repository URI (Dominique Roux) * Type __letsencrypt_cert: Add Devuan Beowulf support (Nico Schottelius) + * Type __letsencrypt_cert: Fix Devuan Ascii: support (Nico Schottelius) * Type __docker: Add devuan support (Dominique Roux) 5.1.2: 2019-06-21 From 451dfaffe49fc85f8222da19177b7aa05c864f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=BDubom=C3=ADr=20Ku=C4=8Dera?= Date: Fri, 23 Aug 2019 11:28:13 +0200 Subject: [PATCH 1216/1332] __docker_swarm: Fix for Docker 19.03 --- cdist/conf/type/__docker_swarm/explorer/swarm-state | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__docker_swarm/explorer/swarm-state b/cdist/conf/type/__docker_swarm/explorer/swarm-state index 9c1bc32d..2c9fd598 100755 --- a/cdist/conf/type/__docker_swarm/explorer/swarm-state +++ b/cdist/conf/type/__docker_swarm/explorer/swarm-state @@ -18,4 +18,4 @@ # along with cdist. If not, see . # -docker info 2>/dev/null | grep "^Swarm: " | cut -d " " -f 2- +docker info 2>/dev/null | grep '^ *Swarm: ' | awk '{print $2}' From 65b9e1d00f230ca97ef30546e1490a8b51e83c19 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Thu, 29 Aug 2019 14:40:16 +0200 Subject: [PATCH 1217/1332] ++changelog --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index f3b84ba8..b790b983 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ next: * Type __letsencrypt_cert: Add Devuan Beowulf support (Nico Schottelius) * Type __letsencrypt_cert: Fix Devuan Ascii: support (Nico Schottelius) * Type __docker: Add devuan support (Dominique Roux) + * Type __docker_swarm: Fix for Docker 19.03 (Ľubomír Kučera) 5.1.2: 2019-06-21 * Core: Add support for type parameters deprecation (Darko Poljak) From 067d0a62e73d89fef35e1f7183a3b376634da5c0 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 30 Aug 2019 08:51:08 +0200 Subject: [PATCH 1218/1332] Release 5.1.3 --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index b790b983..7594a6d4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,7 +1,7 @@ Changelog --------- -next: +5.1.3: 2019-08-30 * Build: Overcome bash CDPATH when building docs (Dmitry Bogatov) * Type __grafana_dashboard: Update distribution name, package signing key URI and repository URI (Dominique Roux) * Type __letsencrypt_cert: Add Devuan Beowulf support (Nico Schottelius) From 4294ff55e16ae8aba978721f8077605c6157eaf1 Mon Sep 17 00:00:00 2001 From: Dennis Camera Date: Mon, 9 Sep 2019 16:12:16 +0200 Subject: [PATCH 1219/1332] [type/__git] Add --recursive parameter --- cdist/conf/type/__git/gencode-remote | 32 ++++++++++++------------- cdist/conf/type/__git/man.rst | 2 ++ cdist/conf/type/__git/parameter/boolean | 1 + 3 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 cdist/conf/type/__git/parameter/boolean diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote index 5a9e23fc..3ba21add 100755 --- a/cdist/conf/type/__git/gencode-remote +++ b/cdist/conf/type/__git/gencode-remote @@ -19,32 +19,31 @@ # # -state_is="$(cat "$__object/explorer/state")" -owner_is="$(cat "$__object/explorer/owner")" -group_is="$(cat "$__object/explorer/group")" +state_is=$(cat "$__object/explorer/state") +owner_is=$(cat "$__object/explorer/owner") +group_is=$(cat "$__object/explorer/group") -state_should="$(cat "$__object/parameter/state")" +state_should=$(cat "$__object/parameter/state") -branch="$(cat "$__object/parameter/branch")" +branch=$(cat "$__object/parameter/branch") -source="$(cat "$__object/parameter/source")" +source=$(cat "$__object/parameter/source") destination="/$__object_id" -owner="$(cat "$__object/parameter/owner")" -group="$(cat "$__object/parameter/group")" -mode="$(cat "$__object/parameter/mode")" +owner=$(cat "$__object/parameter/owner") +group=$(cat "$__object/parameter/group") +mode=$(cat "$__object/parameter/mode") -[ "$state_should" = "$state_is" ] && \ -[ "$owner" = "$owner_is" ] && \ -[ "$group" = "$group_is" ] && \ -[ -n "$mode" ] && exit 0 +[ "$state_should" = "$state_is" ] \ + && [ "$owner" = "$owner_is" ] \ + && [ "$group" = "$group_is" ] \ + && [ -n "$mode" ] && exit 0 case $state_should in present) - if [ "$state_should" != "$state_is" ]; then - echo git clone --quiet --branch "$branch" "$source" "$destination" + echo git clone --quiet $([ -f "$__object/parameter/recursive" ] && echo '--recursive') --branch "$branch" "$source" "$destination" fi if { [ -n "$owner" ] && [ "$owner_is" != "$owner" ]; } || \ { [ -n "$group" ] && [ "$group_is" != "$group" ]; }; then @@ -54,8 +53,9 @@ case $state_should in echo chmod -R "$mode" "$destination" fi ;; - # Handled in manifest + absent) + # Handled in manifest ;; *) diff --git a/cdist/conf/type/__git/man.rst b/cdist/conf/type/__git/man.rst index 130925c8..e4c06c99 100644 --- a/cdist/conf/type/__git/man.rst +++ b/cdist/conf/type/__git/man.rst @@ -35,6 +35,8 @@ mode owner User to chown to. +recursive + Recursive clone... EXAMPLES -------- diff --git a/cdist/conf/type/__git/parameter/boolean b/cdist/conf/type/__git/parameter/boolean new file mode 100644 index 00000000..a633e659 --- /dev/null +++ b/cdist/conf/type/__git/parameter/boolean @@ -0,0 +1 @@ +recursive From 88fe83ed735d533a77c1cd68081893442a1acc1e Mon Sep 17 00:00:00 2001 From: PCoder Date: Sat, 14 Sep 2019 15:24:36 +0530 Subject: [PATCH 1220/1332] Fix beowulf's spelling --- cdist/conf/type/__letsencrypt_cert/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__letsencrypt_cert/manifest b/cdist/conf/type/__letsencrypt_cert/manifest index d598949e..f736f3f2 100755 --- a/cdist/conf/type/__letsencrypt_cert/manifest +++ b/cdist/conf/type/__letsencrypt_cert/manifest @@ -65,7 +65,7 @@ if [ -z "${certbot_fullpath}" ]; then require="__apt_source/ascii-backports" __package_apt certbot \ --target-release ascii-backports ;; - bewoulf*) + beowulf*) __package_apt certbot ;; *) From eab540bd0fc4a81408890f0dc8f45e8a7f609d06 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Wed, 18 Sep 2019 07:04:41 +0200 Subject: [PATCH 1221/1332] ++ --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 7594a6d4..e7e6b182 100644 --- a/docs/changelog +++ b/docs/changelog @@ -1,6 +1,9 @@ Changelog --------- +next: + * Type __letsencrypt_cert: Fix beowulf's spelling (Mondi Ravi) + 5.1.3: 2019-08-30 * Build: Overcome bash CDPATH when building docs (Dmitry Bogatov) * Type __grafana_dashboard: Update distribution name, package signing key URI and repository URI (Dominique Roux) From 799ec7236971fac597ccb3f80a646fae7e4817f5 Mon Sep 17 00:00:00 2001 From: Darko Poljak Date: Fri, 20 Sep 2019 07:15:37 +0200 Subject: [PATCH 1222/1332] Implement preos --- cdist/argparse.py | 6 +- cdist/preos.py | 101 + cdist/preos/debootstrap/__init__.py | 1 + cdist/preos/debootstrap/debootstrap.py | 240 ++ cdist/preos/debootstrap/files/code | 274 ++ .../files/devuan-debootstrap/Makefile | 18 + .../files/devuan-debootstrap/README | 65 + .../debootstrap/files/devuan-debootstrap/TODO | 11 + .../devuan-debootstrap/debian/.gitignore | 6 + .../debian/README.DevuanSource | 15 + .../files/devuan-debootstrap/debian/changelog | 2655 +++++++++++++++++ .../files/devuan-debootstrap/debian/compat | 1 + .../files/devuan-debootstrap/debian/control | 26 + .../files/devuan-debootstrap/debian/copyright | 30 + .../debian/debootstrap.docs | 1 + .../debian/debootstrap.manpages | 1 + .../files/devuan-debootstrap/debian/gbp.conf | 9 + .../files/devuan-debootstrap/debian/rules | 47 + .../devuan-debootstrap/debian/source/format | 1 + .../files/devuan-debootstrap/debootstrap | 703 +++++ .../files/devuan-debootstrap/debootstrap.8 | 189 ++ .../files/devuan-debootstrap/functions | 1735 +++++++++++ .../files/devuan-debootstrap/scripts/aequorea | 202 ++ .../files/devuan-debootstrap/scripts/ascii | 1 + .../devuan-debootstrap/scripts/bartholomea | 1 + .../files/devuan-debootstrap/scripts/breezy | 163 + .../files/devuan-debootstrap/scripts/bullseye | 1 + .../files/devuan-debootstrap/scripts/buster | 1 + .../files/devuan-debootstrap/scripts/ceres | 218 ++ .../devuan-debootstrap/scripts/chromodoris | 1 + .../files/devuan-debootstrap/scripts/dapper | 168 ++ .../files/devuan-debootstrap/scripts/dasyatis | 1 + .../files/devuan-debootstrap/scripts/edgy | 187 ++ .../files/devuan-debootstrap/scripts/etch | 1 + .../devuan-debootstrap/scripts/etch-m68k | 1 + .../files/devuan-debootstrap/scripts/feisty | 190 ++ .../files/devuan-debootstrap/scripts/gutsy | 230 ++ .../files/devuan-debootstrap/scripts/hardy | 1 + .../files/devuan-debootstrap/scripts/hoary | 179 ++ .../devuan-debootstrap/scripts/hoary.buildd | 159 + .../files/devuan-debootstrap/scripts/intrepid | 1 + .../files/devuan-debootstrap/scripts/jaunty | 1 + .../files/devuan-debootstrap/scripts/jessie | 1 + .../scripts/jessie-kfreebsd | 1 + .../files/devuan-debootstrap/scripts/karmic | 1 + .../files/devuan-debootstrap/scripts/lenny | 1 + .../files/devuan-debootstrap/scripts/lucid | 1 + .../files/devuan-debootstrap/scripts/maverick | 1 + .../files/devuan-debootstrap/scripts/natty | 1 + .../devuan-debootstrap/scripts/oldoldstable | 1 + .../devuan-debootstrap/scripts/oldstable | 1 + .../files/devuan-debootstrap/scripts/oneiric | 1 + .../files/devuan-debootstrap/scripts/potato | 104 + .../files/devuan-debootstrap/scripts/precise | 1 + .../files/devuan-debootstrap/scripts/quantal | 1 + .../files/devuan-debootstrap/scripts/raring | 1 + .../files/devuan-debootstrap/scripts/sarge | 218 ++ .../devuan-debootstrap/scripts/sarge.buildd | 166 ++ .../scripts/sarge.fakechroot | 171 ++ .../files/devuan-debootstrap/scripts/saucy | 1 + .../files/devuan-debootstrap/scripts/sid | 214 ++ .../files/devuan-debootstrap/scripts/squeeze | 1 + .../files/devuan-debootstrap/scripts/stable | 1 + .../files/devuan-debootstrap/scripts/stretch | 1 + .../files/devuan-debootstrap/scripts/testing | 1 + .../files/devuan-debootstrap/scripts/trusty | 1 + .../files/devuan-debootstrap/scripts/unstable | 1 + .../files/devuan-debootstrap/scripts/utopic | 1 + .../files/devuan-debootstrap/scripts/vivid | 1 + .../files/devuan-debootstrap/scripts/warty | 166 ++ .../devuan-debootstrap/scripts/warty.buildd | 159 + .../files/devuan-debootstrap/scripts/wheezy | 1 + .../files/devuan-debootstrap/scripts/wily | 1 + .../files/devuan-debootstrap/scripts/woody | 203 ++ .../devuan-debootstrap/scripts/woody.buildd | 166 ++ .../files/devuan-debootstrap/scripts/xenial | 1 + .../files/devuan-debootstrap/scripts/yakkety | 1 + .../files/devuan-debootstrap/scripts/zesty | 1 + .../debootstrap/files/init-manifest-debian | 39 + .../debootstrap/files/init-manifest-devuan | 39 + .../debootstrap/files/init-manifest-ubuntu | 39 + cdist/preos/debootstrap/files/remote-copy.sh | 8 + cdist/preos/debootstrap/files/remote-exec.sh | 24 + completions/bash/cdist-completion.bash | 2 +- completions/zsh/_cdist | 2 +- docs/changelog | 1 + docs/src/cdist-preos.rst | 137 + docs/src/cdist-reference.rst.sh | 3 + docs/src/index.rst | 1 + docs/src/man1/cdist.rst | 172 +- hacking/preos-sh/init | 32 + hacking/preos-sh/preos.sh | 31 + hacking/preos-sh/remote-copy.sh | 8 + hacking/preos-sh/remote-exec.sh | 24 + scripts/cdist | 3 + 95 files changed, 9997 insertions(+), 4 deletions(-) create mode 100644 cdist/preos.py create mode 100644 cdist/preos/debootstrap/__init__.py create mode 100644 cdist/preos/debootstrap/debootstrap.py create mode 100755 cdist/preos/debootstrap/files/code create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/Makefile create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/README create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/TODO create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/.gitignore create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/README.DevuanSource create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/changelog create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/compat create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/control create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/copyright create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/debootstrap.docs create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/debootstrap.manpages create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/gbp.conf create mode 100755 cdist/preos/debootstrap/files/devuan-debootstrap/debian/rules create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debian/source/format create mode 100755 cdist/preos/debootstrap/files/devuan-debootstrap/debootstrap create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/debootstrap.8 create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/functions create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/aequorea create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/ascii create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/bartholomea create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/breezy create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/bullseye create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/buster create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/ceres create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/chromodoris create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/dapper create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/dasyatis create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/edgy create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/etch create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/etch-m68k create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/feisty create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/gutsy create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/hardy create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/hoary create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/hoary.buildd create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/intrepid create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/jaunty create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/jessie create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/jessie-kfreebsd create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/karmic create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/lenny create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/lucid create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/maverick create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/natty create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/oldoldstable create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/oldstable create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/oneiric create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/potato create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/precise create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/quantal create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/raring create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/sarge create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/sarge.buildd create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/sarge.fakechroot create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/saucy create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/sid create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/squeeze create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/stable create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/stretch create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/testing create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/trusty create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/unstable create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/utopic create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/vivid create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/warty create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/warty.buildd create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/wheezy create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/wily create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/woody create mode 100644 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/woody.buildd create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/xenial create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/yakkety create mode 120000 cdist/preos/debootstrap/files/devuan-debootstrap/scripts/zesty create mode 100644 cdist/preos/debootstrap/files/init-manifest-debian create mode 100644 cdist/preos/debootstrap/files/init-manifest-devuan create mode 100644 cdist/preos/debootstrap/files/init-manifest-ubuntu create mode 100755 cdist/preos/debootstrap/files/remote-copy.sh create mode 100755 cdist/preos/debootstrap/files/remote-exec.sh create mode 100644 docs/src/cdist-preos.rst create mode 100644 hacking/preos-sh/init create mode 100644 hacking/preos-sh/preos.sh create mode 100644 hacking/preos-sh/remote-copy.sh create mode 100644 hacking/preos-sh/remote-exec.sh diff --git a/cdist/argparse.py b/cdist/argparse.py index 421d1b54..3ccc0545 100644 --- a/cdist/argparse.py +++ b/cdist/argparse.py @@ -5,10 +5,11 @@ import logging import collections import functools import cdist.configuration +import cdist.preos # set of beta sub-commands -BETA_COMMANDS = set(('install', 'inventory', )) +BETA_COMMANDS = set(('install', 'inventory', 'preos', )) # set of beta arguments for sub-commands BETA_ARGS = { 'config': set(('tag', 'all_tagged_hosts', 'use_archiving', )), @@ -422,6 +423,9 @@ def get_parsers(): parser['inventory'].set_defaults( func=cdist.inventory.Inventory.commandline) + # PreOs + parser['preos'] = parser['sub'].add_parser('preos', add_help=False) + # Shell parser['shell'] = parser['sub'].add_parser( 'shell', parents=[parser['loglevel']]) diff --git a/cdist/preos.py b/cdist/preos.py new file mode 100644 index 00000000..46b45554 --- /dev/null +++ b/cdist/preos.py @@ -0,0 +1,101 @@ +import os +import os.path +import sys +import inspect +import argparse +import cdist +import logging + + +_PREOS_CALL = "commandline" +_PREOS_NAME = "_preos_name" +_PREOS_MARKER = "_cdist_preos" +_PLUGINS_DIR = "preos" +_PLUGINS_PATH = [os.path.join(os.path.dirname(__file__), _PLUGINS_DIR), ] +cdist_home = cdist.home_dir() +if cdist_home: + cdist_home_preos = os.path.join(cdist_home, "preos") + if os.path.isdir(cdist_home_preos): + _PLUGINS_PATH.append(cdist_home_preos) +sys.path.extend(_PLUGINS_PATH) + + +log = logging.getLogger("PreOS") + + +def preos_plugin(obj): + """It is preos if _PREOS_MARKER is True and has _PREOS_CALL.""" + if hasattr(obj, _PREOS_MARKER): + is_preos = getattr(obj, _PREOS_MARKER) + else: + is_preos = False + + if is_preos and hasattr(obj, _PREOS_CALL): + yield obj + + +def scan_preos_dir_plugins(dir): + for fname in os.listdir(dir): + if os.path.isfile(os.path.join(dir, fname)): + fname = os.path.splitext(fname)[0] + module_name = fname + try: + module = __import__(module_name) + yield from preos_plugin(module) + clsmembers = inspect.getmembers(module, inspect.isclass) + for cm in clsmembers: + c = cm[1] + yield from preos_plugin(c) + except ImportError as e: + log.warning("Cannot import '{}': {}".format(module_name, e)) + + +def find_preos_plugins(): + for dir in _PLUGINS_PATH: + yield from scan_preos_dir_plugins(dir) + + +def find_preoses(): + preoses = {} + for preos in find_preos_plugins(): + if hasattr(preos, _PREOS_NAME): + preos_name = getattr(preos, _PREOS_NAME) + else: + preos_name = preos.__name__.lower() + preoses[preos_name] = preos + return preoses + + +def check_root(): + if os.geteuid() != 0: + raise cdist.Error("Must be run with root privileges") + + +class PreOS(object): + preoses = None + + @classmethod + def commandline(cls, argv): + + if not cls.preoses: + cls.preoses = find_preoses() + + parser = argparse.ArgumentParser( + description="Create PreOS", prog="cdist preos") + parser.add_argument('preos', help='PreOS to create, one of: {}'.format( + set(cls.preoses))) + args = parser.parse_args(argv[1:2]) + + preos_name = args.preos + if preos_name in cls.preoses: + preos = cls.preoses[preos_name] + func = getattr(preos, _PREOS_CALL) + if inspect.ismodule(preos): + func_args = [preos, argv[2:], ] + else: + func_args = [argv[2:], ] + log.info("Running preos : {}".format(preos_name)) + func(*func_args) + else: + log.error("Unknown preos: {}, available preoses: {}".format( + preos_name, set(cls.preoses.keys()))) diff --git a/cdist/preos/debootstrap/__init__.py b/cdist/preos/debootstrap/__init__.py new file mode 100644 index 00000000..6d340b4a --- /dev/null +++ b/cdist/preos/debootstrap/__init__.py @@ -0,0 +1 @@ +from debootstrap.debootstrap import Debian, Ubuntu, Devuan diff --git a/cdist/preos/debootstrap/debootstrap.py b/cdist/preos/debootstrap/debootstrap.py new file mode 100644 index 00000000..617d280b --- /dev/null +++ b/cdist/preos/debootstrap/debootstrap.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 2016 Darko Poljak (darko.poljak at ungleich.ch) +# +# 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 . +# +# + +import cdist +import cdist.config +import cdist.core +import cdist.preos +import argparse +import cdist.argparse +import logging +import os +import subprocess + + +class Debian(object): + _preos_name = 'debian' + _cdist_preos = True + + _files_dir = os.path.join(os.path.dirname(__file__), "files") + + @classmethod + def default_args(cls): + default_remote_exec = os.path.join(cls._files_dir, "remote-exec.sh") + default_remote_copy = os.path.join(cls._files_dir, "remote-copy.sh") + default_init_manifest = os.path.join( + cls._files_dir, "init-manifest-{}".format(cls._preos_name)) + + defargs = argparse.Namespace() + defargs.arch = 'amd64' + defargs.bootstrap = False + defargs.configure = False + defargs.cdist_params = '-v' + defargs.rm_bootstrap_dir = False + defargs.suite = 'stable' + defargs.remote_exec = default_remote_exec + defargs.remote_copy = default_remote_copy + defargs.manifest = default_init_manifest + + return defargs + + @classmethod + def get_parser(cls): + defargs = cls.default_args() + cdist_parser = cdist.argparse.get_parsers() + parser = argparse.ArgumentParser( + prog='cdist preos {}'.format(cls._preos_name), + parents=[cdist_parser['loglevel'], cdist_parser['beta']]) + parser.add_argument('target_dir', nargs=1, + help=("target directory where PreOS will be " + "bootstrapped")) + parser.add_argument( + '-a', '--arch', + help="target debootstrap architecture, by default '{}'".format( + defargs.arch), dest='arch', default=defargs.arch) + parser.add_argument( + '-B', '--bootstrap', + help='do bootstrap step', + dest='bootstrap', action='store_true', default=defargs.bootstrap) + parser.add_argument( + '-C', '--configure', + help='do configure step', + dest='configure', action='store_true', default=defargs.configure) + parser.add_argument( + '-c', '--cdist-params', + help=("parameters that will be passed to cdist config, by default" + " '{}' is used".format(defargs.cdist_params)), + dest='cdist_params', default=defargs.cdist_params) + parser.add_argument( + '-D', '--drive-boot', + help='create bootable PreOS on specified drive', + dest='drive') + parser.add_argument( + '-e', '--remote-exec', + help=("remote exec that cdist config will use, by default " + "internal script is used"), + dest='remote_exec', default=defargs.remote_exec) + parser.add_argument( + '-i', '--init-manifest', + help=("init manifest that cdist config will use, by default " + "internal init manifest is used"), + dest='manifest', default=defargs.manifest) + parser.add_argument( + '-k', '--keyfile', action="append", + help=("ssh key files that will be added to cdist config; " + "'__ssh_authorized_keys root ...' type is appended to " + "initial manifest"), + dest='keyfile') + parser.add_argument( + '-m', '--mirror', + help='use specified mirror for debootstrap', + dest='mirror') + parser.add_argument( + '-P', '--root-password', + help='Set specified password for root, generated by default', + dest='root_password') + parser.add_argument('-p', '--pxe-boot-dir', help='PXE boot directory', + dest='pxe_boot_dir') + parser.add_argument( + '-r', '--rm-bootstrap-dir', + help='remove target directory after finishing', + dest='rm_bootstrap_dir', action='store_true', + default=defargs.rm_bootstrap_dir) + parser.add_argument( + '-S', '--script', + help='use specified script for debootstrap', + dest='script') + parser.add_argument('-s', '--suite', + help="suite used for debootstrap, " + "by default '{}'".format(defargs.suite), + dest='suite', default=defargs.suite) + parser.add_argument( + '-y', '--remote-copy', + help=("remote copy that cdist config will use, by default " + "internal script is used"), + dest='remote_copy', default=defargs.remote_copy) + parser.epilog = cdist.argparse.EPILOG + + return parser + + @classmethod + def update_env(cls, env): + pass + + @classmethod + def commandline(cls, argv): + log = logging.getLogger(cls.__name__) + + parser = cls.get_parser() + cdist.argparse.add_beta_command(cls._preos_name) + args = parser.parse_args(argv) + if args.script and not args.mirror: + raise cdist.Error("script option cannot be used without " + "mirror option") + + args.command = cls._preos_name + cdist.argparse.check_beta(vars(args)) + + cdist.preos.check_root() + + args.target_dir = os.path.realpath(args.target_dir[0]) + args.os = cls._preos_name + args.remote_exec = os.path.realpath(args.remote_exec) + args.remote_copy = os.path.realpath(args.remote_copy) + args.manifest = os.path.realpath(args.manifest) + if args.keyfile: + new_keyfile = [os.path.realpath(x) for x in args.keyfile] + args.keyfile = new_keyfile + if args.pxe_boot_dir: + args.pxe_boot_dir = os.path.realpath(args.pxe_boot_dir) + + cdist.argparse.handle_loglevel(args) + log.debug("preos: {}, args: {}".format(cls._preos_name, args)) + try: + env = vars(args) + new_env = {} + for key in env: + if key == 'verbose': + if env[key] >= 3: + new_env['debug'] = "yes" + elif env[key] == 2: + new_env['verbose'] = "yes" + elif not env[key]: + new_env[key] = '' + elif isinstance(env[key], bool) and env[key]: + new_env[key] = "yes" + elif isinstance(env[key], list): + val = env[key] + new_env[key + "_cnt"] = str(len(val)) + for i, v in enumerate(val): + new_env[key + "_" + str(i)] = v + else: + new_env[key] = str(env[key]) + env = new_env + env.update(os.environ) + cls.update_env(env) + log.debug("preos: {} env: {}".format(cls._preos_name, env)) + cmd = os.path.join(cls._files_dir, "code") + info_msg = ["Running preos: {}, suite: {}, arch: {}".format( + cls._preos_name, args.suite, args.arch), ] + if args.mirror: + info_msg.append("mirror: {}".format(args.mirror)) + if args.script: + info_msg.append("script: {}".format(args.script)) + if args.bootstrap: + info_msg.append("bootstrapping") + if args.configure: + info_msg.append("configuring") + if args.pxe_boot_dir: + info_msg.append("creating PXE") + if args.drive: + info_msg.append("creating bootable drive") + log.info(info_msg) + log.debug("cmd={}".format(cmd)) + subprocess.check_call(cmd, env=env, shell=True) + except subprocess.CalledProcessError as e: + log.error("preos {} failed: {}".format(cls._preos_name, e)) + + +class Ubuntu(Debian): + _preos_name = "ubuntu" + + @classmethod + def default_args(cls): + defargs = super().default_args() + defargs.suite = 'xenial' + return defargs + + +class Devuan(Debian): + _preos_name = "devuan" + + @classmethod + def default_args(cls): + defargs = super().default_args() + defargs.suite = 'jessie' + return defargs + + @classmethod + def update_env(cls, env): + env['DEBOOTSTRAP_DIR'] = os.path.join(cls._files_dir, + 'devuan-debootstrap') diff --git a/cdist/preos/debootstrap/files/code b/cdist/preos/debootstrap/files/code new file mode 100755 index 00000000..9e37003b --- /dev/null +++ b/cdist/preos/debootstrap/files/code @@ -0,0 +1,274 @@ +#!/bin/sh +## +## 2016 Darko Poljak (darko.poljak at ungleich.ch) +## +## 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 . + +set -e + +if [ "${debug}" ] +then + set -x + cdist_params="${cdist_params} -d" +fi + +bootstrap_dir="${target_dir}" + +case "${os}" in + ubuntu|debian|devuan) + # nothing, those are valid values + ;; + *) + echo "ERROR: invalid os value: ${os}" >&2 + exit 1 + ;; +esac + +check_bootstrap_dir() { + if [ ! -e "$1" ] + then + echo "ERROR: bootstrap directory $1 does not exist" >&2 + exit 1 + fi +} + +# bootstrap +if [ "${bootstrap}" ] +then + if [ "${DEBOOTSTRAP_DIR}" ] + then + debootstrap_cmd="${DEBOOTSTRAP_DIR}/debootstrap" + else + command -v debootstrap 2>&1 > /dev/null || { + echo "ERROR: debootstrap not found" >&2 + exit 1 + } + debootstrap_cmd="debootstrap" + fi + + # If PreOS on drive then do not check for directory emptiness. + # Partition can at least contain 'lost+found' directory. + if [ ! "${drive}" ] + then + if [ -e "${bootstrap_dir}" ] + then + dir_content=$(ls -A "${bootstrap_dir}" | wc -l) + else + dir_content=0 + fi + if [ "${dir_content}" -ne 0 ] + then + echo "ERROR: "${bootstrap_dir}" not empty " >&2 + exit 1 + fi + fi + + if [ "${verbose}" -o "${debug}" ] + then + echo "bootstrapping..." + fi + mkdir -p "${bootstrap_dir}" + "${debootstrap_cmd}" --include=openssh-server --arch=${arch} ${suite} ${bootstrap_dir} \ + ${mirror} ${script} + if [ "${verbose}" -o "${debug}" ] + then + echo "bootstrap finished" + fi +fi + +chroot_mount() { + mount -t proc none "${bootstrap_dir}/proc" || true + mount -t sysfs none "${bootstrap_dir}/sys" || true + mount -o bind /dev "${bootstrap_dir}/dev" || true + mount -t devpts none "${bootstrap_dir}/dev/pts" || true +} + +chroot_umount() { + umount "${bootstrap_dir}/dev/pts" || true + umount "${bootstrap_dir}/dev" || true + umount "${bootstrap_dir}/sys" || true + umount "${bootstrap_dir}/proc" || true +} + +TRAPFUNC="umount \"${bootstrap_dir}/dev/pts\" || true; \ +umount \"${bootstrap_dir}/dev\" || true; \ +umount \"${bootstrap_dir}/sys\" || true; \ +umount \"${bootstrap_dir}/proc\" || true;" + +# config +if [ "${configure}" ] +then + if [ ! -f "${manifest}" ] + then + echo "ERROR: ${manifest} does not exist" >&2 + exit 1 + fi + if [ ! -f "${remote_exec}" ] + then + echo "ERROR: ${remote_exec} does not exist" >&2 + exit 1 + fi + if [ ! -f "${remote_copy}" ] + then + echo "ERROR: ${remote_copy} does not exist" >&2 + exit 1 + fi + + if [ "${keyfile_cnt}" -a "${keyfile_cnt}" -gt 0 ] + then + i="$((keyfile_cnt - 1))" + keyfiles="" + while [ "${i}" -ge 0 ] + do + kf_var="keyfile_${i}" + eval kf='$'"${kf_var}" + if [ ! -f "${kf}" ] + then + echo "ERROR: ${kf} does not exist" >&2 + exit 1 + fi + key=$(cat "${kf}") + keyfiles="${keyfiles} --key '${key}'" + i=$((i - 1)) + done + ssh_auth_keys_line="__ssh_authorized_keys root ${keyfiles}\n" + else + ssh_auth_keys_line="" + fi + + check_bootstrap_dir "${bootstrap_dir}" + + if [ "${verbose}" -o "${debug}" ] + then + echo "configuring..." + fi + + trap "${TRAPFUNC}" 0 1 2 3 15 + + chroot_mount + + chroot "${bootstrap_dir}" /usr/bin/apt-get update + + if [ "${drive}" ] + then + grub_manifest_line="__package grub-pc --state present\n" + grub_kern_params_line="__line linux_kernel_params \ +--file /etc/default/grub \ +--line 'GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash net.ifnames=0\"'\n" + else + grub_manifest_line="" + grub_kern_params_line="" + fi + grub_lines="${grub_manifest_line}${grub_kern_params_line}" + + printf "${ssh_auth_keys_line}${grub_lines}" \ + | cat "${manifest}" - |\ + cdist config \ + ${cdist_params} -i - \ + --remote-exec "${remote_exec}" \ + --remote-copy "${remote_copy}" \ + "${bootstrap_dir}" + + # __hostname with systmed uses hostnamectl which needs dbus running + # set hostname explicitly here instead + printf "preos\n" > "${bootstrap_dir}/etc/hostname" + + chroot "${bootstrap_dir}" /usr/bin/apt-get autoclean + chroot "${bootstrap_dir}" /usr/bin/apt-get clean + chroot "${bootstrap_dir}" /usr/bin/apt-get autoremove + + chroot_umount + + trap - 0 1 2 3 15 + + if [ "${verbose}" -o "${debug}" ] + then + echo "configuring finished" + fi +fi + +if [ "${pxe_boot_dir}" ] +then + check_bootstrap_dir "${bootstrap_dir}" + + if [ "${verbose}" -o "${debug}" ] + then + echo "creating pxe..." + fi + + mkdir -p "${pxe_boot_dir}" + cp "${bootstrap_dir}"/boot/vmlinuz-* "${pxe_boot_dir}/kernel" + cd "${bootstrap_dir}" + find . -print0 | cpio --null -o --format=newc | gzip -9 > "${pxe_boot_dir}/initramfs" + + mkdir -p "${pxe_boot_dir}/pxelinux.cfg" + cat < "${pxe_boot_dir}/pxelinux.cfg/default" + DEFAULT preos + LABEL preos + KERNEL kernel + APPEND utf8 load_ramdisk=1 root=/dev/ram nofb initrd=initramfs console=ttyS1,115200 net.ifnames=0 +EOPXEF + + cp "${bootstrap_dir}/usr/lib/PXELINUX/pxelinux.0" "${pxe_boot_dir}/pxelinux.0" + cp "${bootstrap_dir}/usr/lib/syslinux/modules/bios/ldlinux.c32" \ + "${pxe_boot_dir}/ldlinux.c32" + # network boot need all files world readable + chmod -R 644 "${pxe_boot_dir}"/* + + if [ "${verbose}" -o "${debug}" ] + then + echo "pxe creation finished" + fi +fi + +if [ "${drive}" ] +then + trap "${TRAPFUNC}" 0 1 2 3 15 + chroot_mount + chroot "${bootstrap_dir}" grub-install ${drive} + chroot "${bootstrap_dir}" /bin/sh -c "GRUB_DISABLE_OS_PROBER=true update-grub" + # set root password + if [ ! "${root_password}" ] + then + if ! which strings >/dev/null 2>&1 + then + printf "strings is missing\n" >&2 + exit 1 + fi + root_password="$(head -n 1000 /dev/urandom | strings | \ + grep -o '[[:alnum:]]' | head -n 30 | tr -d '\n')" + printf "Generated root password (without quotes):'${root_password}'\n" + fi + chroot "${bootstrap_dir}" /bin/sh -c "echo \"root:${root_password}\" | \ + chpasswd" + # /etc/securetty must not be world writeable. + chmod 644 "${bootstrap_dir}"/etc/securetty + chroot_umount + trap - 0 1 2 3 15 +fi + +if [ "${rm_bootstrap_dir}" ] +then + if [ "${verbose}" -o "${debug}" ] + then + echo "removing bootstrap dir..." + fi + rm -r -f "${bootstrap_dir}" + if [ "${verbose}" -o "${debug}" ] + then + echo "removing bootstrap dir finished" + fi +fi diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/Makefile b/cdist/preos/debootstrap/files/devuan-debootstrap/Makefile new file mode 100644 index 00000000..85168031 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/Makefile @@ -0,0 +1,18 @@ +# avoid dpkg-dev dependency; fish out the version with sed +VERSION := $(shell sed 's/.*(\(.*\)).*/\1/; q' debian/changelog) + +all: + +clean: + +DSDIR=$(DESTDIR)/usr/share/debootstrap +install: + mkdir -p $(DSDIR)/scripts + mkdir -p $(DESTDIR)/usr/sbin + + cp -a scripts/* $(DSDIR)/scripts/ + install -o root -g root -m 0644 functions $(DSDIR)/ + + sed 's/@VERSION@/$(VERSION)/g' debootstrap >$(DESTDIR)/usr/sbin/debootstrap + chown root:root $(DESTDIR)/usr/sbin/debootstrap + chmod 0755 $(DESTDIR)/usr/sbin/debootstrap diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/README b/cdist/preos/debootstrap/files/devuan-debootstrap/README new file mode 100644 index 00000000..4d8c3049 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/README @@ -0,0 +1,65 @@ +README for debootstrap +====================== + +See the manpage for (some) documentation. + +Running debootstrap from source +------------------------------- + +You can run debootstrap from its source tree without installing it. This +can be useful if you want a quick way to make a Debian chroot on another +system, or if you are testing modifications to debootstrap. + +First, get the source. + +* Either by using git + git clone https://anonscm.debian.org/git/d-i/debootstrap.git + +* Or by visiting + and downloading the tar.gz file + +Then in the debootstrap source directory: + + export DEBOOTSTRAP_DIR=`pwd` + sudo ./debootstrap stable my-stable-dir + +If you are running a multi-stage boot strap (for example for a QEMU +rootfs) you don't even need root: + + export DEBOOTSTRAP_DIR=`pwd` + fakeroot ./debootstrap --foreign --arch=armhf testing my-testing-dir http://deb.debian.org/debian + +Of course you will need to execute the second stage as root to finish the bootstrap: + + (on foreign hardware) + /debootstrap/debootstrap --second-stage + + +Future +------ + + * Cross-strap support - so you can bootstrap a filesystem to the + point where it will successfully boot, and finish installing itself + without having to be running the target architecture or OS yourself. + + debootstrap --arch powerpc sarge ./sarge-ppc-chroot ... + + on an i386 system, boot a powerpc box with sarge-ppc-chroot as its + root files system, and have it "work". The cross-hurd package does + something similar, and should be replaced by this feature. + + * There should be some (better) way of telling debootstrap what "base" + packages you want to install -- this varies between making a chroot, + doing an install, and doing a buildd. Also, some installs want + different base packages (to setup networking, or kernels, eg) + + +NMUing +------ + +If there's a problem with debootstrap that you need fixed, feel free to do +an NMU to fix it. Usual rules: try not to break anything, and mail the +patch to the BTS. Don't worry about asking first though. + +However, note that debootstrap is now team maintained. Anyone in d-i can do +a release without the bother of a NMU. diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/TODO b/cdist/preos/debootstrap/files/devuan-debootstrap/TODO new file mode 100644 index 00000000..e5fde0e4 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/TODO @@ -0,0 +1,11 @@ + +Features: + ++ second stage via chroot debootstrap/debootstrap + ++ debootstrap/deb file to record deb destinations/information + + -- configuration file + -- versus command line + -- support for sources (vs mirrors) + -- faux-pinning for packages + + ++ makedev in second stage diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/.gitignore b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/.gitignore new file mode 100644 index 00000000..39638d97 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/.gitignore @@ -0,0 +1,6 @@ +debootstrap +debootstrap-udeb +files +*.debhelper.log +*.substvars + diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/README.DevuanSource b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/README.DevuanSource new file mode 100644 index 00000000..6446a088 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/README.DevuanSource @@ -0,0 +1,15 @@ +To sync up with debians source for inspiration you should run the following: + + `git remote add alioth-git git://anonscm.debian.org/d-i/debootstrap.git` + `git fetch alioth-git` + +After that you can either cherry-pick or merge releases from debian. To +merge a release, it's do: + `git tag` to list the release tags +and + `git merge ` +followed by all the fixups and then commit with an appropriate message like + "Merging Release from debian" + +Copyright 2016 Daniel Reurich + diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/changelog b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/changelog new file mode 100644 index 00000000..8688197d --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/changelog @@ -0,0 +1,2655 @@ +debootstrap (1.0.87+devuan1.1) unstable; urgency=medium + + * add git to builddeps + + -- Daniel Reurich Fri, 13 Jan 2017 23:12:50 +1300 + +debootstrap (1.0.87+devuan1.0) unstable; urgency=high + + [ Julien Cristau ] + * Default to split /usr again, as merged-/usr breaks dpkg-shlibdeps + (closes: #844221). + + [ Riku Voipio ] + * remove scratchbox2 support (closes: #796189) + + -- Christian Perrier Wed, 16 Nov 2016 06:47:27 +0100 + +debootstrap (1.0.86+devuan1.0) unstable; urgency=high + + [ Daniel Reurich ] + * Restore Devuan Jessie version + * switch to 3.0 (git) source format + * set git-depth + * Add directions for inspiration from debians source + * removed file so we can build using git source format + * merge 1.0.86 for jessie + + -- Daniel Reurich Fri, 13 Jan 2017 15:58:19 +1300 + +debootstrap (1.0.86) unstable; urgency=high + + * Rework split_inline_sig by using shell built-ins instead of trying to + mix sed and tr together, which might work on regular systems but not + from inside the Debian Installer (Closes: #842591). Thanks to Ansgar + Burchardt for the proof of concept! + + -- Cyril Brulebois Sun, 30 Oct 2016 23:35:45 +0100 + +debootstrap (1.0.85-1+devuan1) unstable; urgency=medium + + * sync with debian upstream package + * add right keyrings with the new schema on devuan-keyring package + + -- Franco (nextime) Lanza Sat, 29 Oct 2016 23:21:57 +0200 + + +debootstrap (1.0.85) unstable; urgency=medium + + [ Julien Cristau ] + * Add support for downloading and validating InRelease files, by splitting + up detached signature from signed data. + * Switch default mirror to deb.debian.org. + + [ Colin Watson ] + * Add (Ubuntu) zesty as a symlink to gutsy. + + [ Ansgar Burchardt ] + * Add jessie-kfreebsd to merged-/usr blacklist. + * No longer Build-Depend on makedev. The code using it was already + removed in debootstrap 1.0.82. + * Do not use `tar -k` for older releases which might have file + conflicts between the packages to be installed. (Closes: #838388) + * Error out when seeing short options. (Closes: #548880) + * Add oldoldstable -> sid script symlink. (Closes: #792734) + * Add buster -> sid and bullseye -> sid script symlinks. + * Only unpack and configure the base system when there are actually + packages to install. (Closes: #825034) + * debootstrap.8: Use stretch instead of wheezy in examples. + + [ Marco d'Itri ] + * Enable merged-/usr by default. (Closes: #839046) + + -- Julien Cristau Fri, 21 Oct 2016 20:22:49 +0200 + +debootstrap (1.0.84) unstable; urgency=medium + + [ Ansgar Burchardt ] + * Add support for xz-compressed Packages indices. (Closes: #837649) + + -- Christian Perrier Thu, 06 Oct 2016 06:59:38 +0200 + +debootstrap (1.0.83) unstable; urgency=medium + + [ Ansgar Burchardt ] + * functions: Validate that the requested suite is listed in the + Release file's Suite or Codename field. (Closes: #837075) + * Add support for merged-/usr, enabled by a new --merged-usr option. + (Closes: #810301) + * Feign install of dpkg in second stage. This avoids problems when + using dpkg-deb together with busybox' tar. (Closes: #837185) + * README: Use https://. + + [ Steve McIntyre ] + * Update Standards-Version to 3.9.8 (no changes needed) + + -- Steve McIntyre <93sam@debian.org> Tue, 13 Sep 2016 13:16:41 +0100 + +debootstrap (1.0.82) unstable; urgency=medium + + [ Alex Bennée ] + * Excise all devices.tar.gz code. Closes: #830869 + + -- Christian Perrier Thu, 08 Sep 2016 07:09:56 +0200 + +debootstrap (1.0.81) unstable; urgency=medium + + [ Luca Falavigna ] + * Add (Ubuntu) yakkety as a symlink to gutsy. + + -- Christian Perrier Tue, 03 May 2016 06:51:57 +0200 + +debootstrap (1.0.80-1+devuan1) unstable; urgency=medium + + * sync with debian upstream package. + + -- Franco (nextime) Lanza Sun, 24 Apr 2016 06:16:29 +0200 + +debootstrap (1.0.80) unstable; urgency=medium + + [ Jon Boden ] + * scripts/gutsy: Support kfreebsd & hurd arches on Ubuntu targets + (closes: #818748) + + -- Christian Perrier Tue, 22 Mar 2016 19:27:45 +0100 + +debootstrap (1.0.79) unstable; urgency=medium + + [ Samuel Thibault ] + * hurd: move setting up dev and servers firmlink to setup_proc stage. Also + firmlink proc there. Thanks Gabriele Giacone for all the investigation! + (Closes: #768102) + + -- Christian Perrier Fri, 19 Feb 2016 07:23:59 +0100 + +debootstrap (1.0.78+nmu1) unstable; urgency=medium + + * Non-maintainer upload. + * Split setup_devices in setup_devices (which now only deals with static + device nodes) and setup_dynamic_devices, and move the calls to + setup_devices from the beginning of the second stage to the end of the + first stage. + setup_dynamic_devices mounts the appropriate filesystems which provide + dynamic device nodes for the architectures which need one in + debootstrap (kfreebsd and hurd). + This fixes a bug in --second-stage introduced in 1.0.34 and exposed + by the devices-related changes of 1.0.76: the second stage debootstrap + runs "dpkg --print-architecture >/dev/null" at the very beginning of + the program when /dev is still empty, so it creates an empty regular + file in place of /dev/null and this will cause mknod to fail later. + (Closes: #813232) + + -- Marco d'Itri Wed, 17 Feb 2016 01:23:23 +0100 + +debootstrap (1.0.78) unstable; urgency=high + + * Use HTTPS for Vcs-* URLs, and link to cgit rather than gitweb. + * Don't call mknod with the --mode option, it's not supported in + busybox. Use -m instead - fixes the broken fix for #812811. + Closes: #813124. Urgency high to get this fix propagated quickly - + it's breaking d-i installs right now. Adding myself to uploaders and + uploading. + + -- Steve McIntyre <93sam@debian.org> Fri, 29 Jan 2016 16:36:00 +0000 + +debootstrap (1.0.77) unstable; urgency=medium + + [ Marco d'Itri ] + * Fix permissions on device nodes (Closes: #812811). + + -- Cyril Brulebois Wed, 27 Jan 2016 20:22:05 +0100 + +debootstrap (1.0.76) unstable; urgency=medium + + [ Marco d'Itri ] + * Stop creating useless device nodes (Closes: #571136). + + -- Cyril Brulebois Sun, 24 Jan 2016 08:55:18 +0100 + +debootstrap (1.0.75-1+devuan1) unstable; urgency=medium + + * sync with debian upstream package + + -- Franco (nextime) Lanza Wed, 02 Dec 2015 04:05:36 +0100 + +debootstrap (1.0.75) unstable; urgency=medium + + * Stop cleaning KEEP_DEBOOTSTRAP_DIR twice, as spotted by Chris Lamb + (Closes: #804415). + * Add Tanglu support (Closes: #771687), thanks to Matthias Klumpp. At + the moment, the following extra suites are recognized: + - aequorea + - bartholomea + - chromodoris + - dasyatis + + -- Cyril Brulebois Wed, 11 Nov 2015 18:49:28 +0100 + +debootstrap (1.0.74) unstable; urgency=medium + + [ Colin Watson ] + * Add (Ubuntu) xenial as a symlink to gutsy. + + -- Christian Perrier Tue, 03 Nov 2015 07:09:23 +0100 + +debootstrap (1.0.73) unstable; urgency=medium + + * Generate a deburis file with (package, version, uri) tuples, similar + to the existing debpaths. + + -- Cyril Brulebois Thu, 22 Oct 2015 12:43:35 +0200 + +debootstrap (1.0.72-1+devuan1) unstable; urgency=medium + + * Rebase on debian 1.0.70 debootstrap version + * Added Daniel Reurich in Uploaders + * Integrating Daniel Reurich patches for d-i + * Updated manpage with Daniel Reurich changes + + -- Franco (nextime) Lanza Thu, 21 May 2015 05:45:36 +0200 + +debootstrap (1.0.72) unstable; urgency=medium + + [ Iain Lane ] + * Add (Ubuntu) wily as a symlink to gutsy (closes: #787117). + + [ Colin Watson ] + * Fix resolve_deps and setup_available to work in the --foreign case + (closes: #757819, LP: #1450980). + + -- Colin Watson Tue, 28 Jul 2015 14:32:19 +0100 + +debootstrap (1.0.71-1+devuan1) unstable; urgency=medium + + * make devuan-baseconf and devuan-keyring requireds packages + * make sure we have sysvinit-core and not systemd in the chroot + + -- Franco (nextime) Lanza Fri, 01 May 2015 02:13:04 +0200 + +debootstrap (1.0.71) unstable; urgency=medium + + * Adjust sed call to render it more portable (missing ';'), making it + work with FreeBSD sed. Thanks to Nikolai Lifanov for the report and + the patch (Closes: #791802). + + -- Cyril Brulebois Fri, 10 Jul 2015 01:29:52 +0200 + +debootstrap (1.0.70-1+devuan1) unstable; urgency=medium + + * Debianization of debootstrap. + * added ceres script and link jessie and ascii to it + + -- Franco (nextime) Lanza Sat, 11 Apr 2015 08:03:36 +0200 + +debootstrap (1.0.70) unstable; urgency=medium + + * Use tr instead of (missing in d-i) xargs (Closes: #785693). Thanks, + Julian Schauder! + + -- Cyril Brulebois Tue, 19 May 2015 11:38:27 +0200 + +debootstrap (1.0.69-1+devuan1) unstable; urgency=medium + + * Fix package description. + + -- Franco (nextime) Lanza Sat, 07 Mar 2015 21:31:07 +0100 + +debootstrap (1.0.69) unstable; urgency=medium + + [ Cyril Brulebois ] + * Make sure to deduplicate package list in download_release to avoid + issues while counting downloaded packages. The failure path could lead + to printing some strange integer (Closes: #709751, #768445, #785276, + #774752). + This was reported to mostly happen whenever --no-resolve-deps is used. + * Add support for --force-check-gpg so that one can programmatically + make sure keyring checks are used and that no fallback to an https + mirror happens (Closes: #661501, #733179, #775454). + * Switch default mirror from ftp.us.debian.org to the new, official + http redirector service: httpredir.debian.org + * Make it possible to override the MAKEDEV variable (Closes: #734743). + Thanks, Wookey! + + [ Christian Perrier ] + * Update Standards to 3.9.6 (checked) + + -- Christian Perrier Mon, 18 May 2015 14:07:43 +0200 + +debootstrap (1.0.68-2+devuan1) unstable; urgency=medium + + * Added missing symlink. + + -- Franco (nextime) Lanza Sat, 07 Mar 2015 21:18:26 +0100 + +debootstrap (1.0.68-1+devuan1) unstable; urgency=medium + + * Added script for ascii. + + -- Franco (nextime) Lanza Sat, 07 Mar 2015 11:47:02 +0100 +debootstrap (1.0.68) unstable; urgency=medium + + [ Steven Chamberlain ] + * Support the jessie-kfreebsd suite, by using the same script as + jessie (a symlink to sid) (Closes: #784927). + + -- Christian Perrier Mon, 11 May 2015 07:46:19 +0200 + +debootstrap (1.0.67-1+devuan2) unstable; urgency=medium + + * Switch to quilt format + + -- Franco (nextime) Lanza Tue, 03 Mar 2015 07:44:11 +0100 + +debootstrap (1.0.67+devuan1) unstable; urgency=medium + + * Applied init freedom patch (debian bug 668001) + * moved to devuan + + -- Franco (nextime) Lanza Tue, 03 Mar 2015 07:09:36 +0100 + +debootstrap (1.0.67) unstable; urgency=medium + + [ Cyril Brulebois ] + * Apply patch by Jérémy Bobbio to support reproducible builds: specify + a modification time on the tar side, and add the -n option to gzip + (Closes: #774069). Thanks, Jérémy! + * Update setup_apt_sources to look at USE_COMPONENTS if COMPONENTS is + empty, fixing the empty sources.list bug with foreign architectures + (Closes: #732255, #773867). + + -- Christian Perrier Wed, 14 Jan 2015 07:03:17 +0100 + +debootstrap (1.0.66) unstable; urgency=low + + [ Cyril Brulebois ] + * Specify gzip compression in debian/source/options to allow for better + portability on other platforms (Closes: #770214). Thanks, Joey Hess! + * Specify gzip compression for debootstrap, and xz for debootstrap-udeb, + to mitigate the need for xz on non-Debian platforms (see: #770217). + + -- Christian Perrier Mon, 24 Nov 2014 09:15:50 +0100 + +debootstrap (1.0.65) unstable; urgency=medium + + [ Julien Cristau ] + * Add support for stretch. + + -- Christian Perrier Mon, 10 Nov 2014 09:24:56 +0100 + +debootstrap (1.0.64) unstable; urgency=medium + + * Add (Ubuntu) vivid as a symlink to gutsy. + + -- Colin Watson Mon, 20 Oct 2014 16:48:49 +0100 + +debootstrap (1.0.63) unstable; urgency=medium + + [ Joey Hess ] + * Move set -e out of shebang line. Closes: #762713 + + -- Christian Perrier Thu, 25 Sep 2014 06:44:16 +0200 + +debootstrap (1.0.62) unstable; urgency=medium + + [ Cyril Brulebois ] + * Fix reporting of package version in retrieval and validation steps + to cope with epochs. + + -- Christian Perrier Mon, 15 Sep 2014 11:40:54 +0200 + +debootstrap (1.0.61) unstable; urgency=medium + + * Fix "possibly the package $pkg is at fault" warnings to account for + changed error output in dpkg 1.17.2. + + -- Colin Watson Sun, 31 Aug 2014 22:07:49 +0100 + +debootstrap (1.0.60) unstable; urgency=medium + + [ Adam Conrad ] + * Add (Ubuntu) utopic as a symlink to gutsy. + + [ Guillem Jover ] + * Sync deb support with latest dpkg-deb (closes: #739136): + - Add uncompressed data.tar deb member support. + - Add uncompressed and xz control.tar deb member support. + + -- Colin Watson Tue, 06 May 2014 09:37:34 +0100 + +debootstrap (1.0.59) unstable; urgency=medium + + * Install ca-certificates as well as apt-transport-https for HTTPS + installations. This makes it possible to copy certificates that were + built into the installer to /usr/local/share/ca-certificates/ and thus + have them continue to be trusted after installation. + + -- Colin Watson Thu, 13 Feb 2014 13:42:54 +0000 + +debootstrap (1.0.58) unstable; urgency=medium + + * Policy version 3.9.5: no changes required. + * Install apt-transport-https if installing from an HTTPS mirror + (LP: #1135163). It may still be necessary to copy certificates into + place, but there's at least a reasonable chance that somebody installing + from HTTPS may want to keep using it, and we have to install + apt-transport-https at this point otherwise they won't be able to do + that end-to-end. + + -- Colin Watson Tue, 11 Feb 2014 17:46:41 +0000 + +debootstrap (1.0.57) unstable; urgency=medium + + * pkgdetails_perl: Only interpret percentages following whitespace, to + cope with GNU wget outputting the local file name (which may contain "%" + due to URL-encoding) after it finishes the download (LP: #1172101). + + -- Colin Watson Fri, 07 Feb 2014 16:12:23 +0000 + +debootstrap (1.0.56) unstable; urgency=low + + [ Tollef Fog Heen ] + * Install base-passwd and base-files in two calls rather than one to + avoid problems with home-built media with different ordering in + Packages. Thanks to Jo Shields for pointing this out and providing + the workaround. Closes: #601670. LP: #1001131. + + [ Joey Hess ] + * When deboostrapping Debian, and the debian-archive-keyring is not + available, switch the default mirror to a https url. This way at + least the CA level of security is available even for users who + have no way to check gpg keys in the WoT. The https mirror is + currently https://mirrors.kernel.org/debian. + * Avoid writing https urls into sources.list, as apt does not support https. + + -- Christian Perrier Mon, 30 Dec 2013 08:00:41 +0100 + +debootstrap (1.0.55) unstable; urgency=low + + [ Matthias Klose ] + * Add (Ubuntu) trusty as a symlink to gutsy. + + -- Christian Perrier Tue, 22 Oct 2013 13:43:23 +0200 + +debootstrap (1.0.53) unstable; urgency=low + + [ Dmitrijs Ledkovs ] + * Set debian source format to '3.0 (native)'. + * Bump debhelper compat level to 9. + * Set Vcs-* to canonical format. + + [ Christian Perrier ] + * Update Standards to 3.9.4 (checked) + + -- Christian Perrier Sun, 14 Jul 2013 13:06:33 +0200 + +debootstrap (1.0.52) unstable; urgency=low + + * scripts/gutsy: Make the fake initctl pass through "initctl version" + calls, used by such things as invoke-rc.d to figure out whether it's + running under Upstart (LP: #1182540). + * scripts/sid, scripts/gutsy: Add a policy-rc.d, matching that in + debian-installer-utils. This is the primary way to disable daemon + startup. + + -- Colin Watson Wed, 22 May 2013 16:55:59 +0100 + +debootstrap (1.0.51) unstable; urgency=low + + [ Scott Kitterman ] + * Add (Ubuntu) saucy as a symlink to gutsy (closes: #706989). + + [ Colin Watson ] + * Clarify location of pkgdetails.c in error message (closes: #708771). + * Resolve mount point symlinks relative to the target chroot before + unmounting them (closes: #702861, #703037, #704744). + + -- Colin Watson Sat, 18 May 2013 23:18:08 +0100 + +debootstrap (1.0.50) unstable; urgency=low + + [ Hector Oron ] + * Report package version information on package retrieve and validation. + Closes: #697675 + + -- Christian Perrier Fri, 17 May 2013 13:34:34 +0200 + +debootstrap (1.0.49) unstable; urgency=medium + + * Add support for jessie. Closes: #706788 + + -- Joey Hess Sat, 04 May 2013 23:37:52 -0400 + +debootstrap (1.0.48) unstable; urgency=low + + * Team upload + + [ Julien Cristau ] + * Disable InRelease support. gpgv won't give us back the signed data, and + full gpg is not available inside d-i (closes: #703889). + * Move extract_release_components to after signature verification. + Suggested by Ansgar Burchardt. + + -- Didier Raboud Thu, 04 Apr 2013 16:17:57 +0200 + +debootstrap (1.0.47) unstable; urgency=low + + * Team upload + * Properly decrypt the InRelease file when downloading from an archive + where InRelease is used. This longstanding bug was masked by former + APT behaviour and was revealed only with recent APT versions + Closes: #703146 + Thanks to Michael Vogt for the analysis and patch + * Add a dependency on gpg because of the above change. + + -- Christian Perrier Wed, 20 Mar 2013 21:34:29 +0100 + +debootstrap (1.0.46) unstable; urgency=low + + * Team upload. + * Use `which` to find out sh only if /bin/sh does not exist. + + -- Samuel Thibault Thu, 27 Dec 2012 15:47:16 +0100 + +debootstrap (1.0.45) unstable; urgency=low + + [ Joey Hess ] + * Better support use on Android by not hardcoding /bin/sh + in a test file that's created, and instead putting in the + actual path to sh. Closes: #694310 Thanks, Shawn Landden + + -- Christian Perrier Sat, 22 Dec 2012 12:56:32 +0100 + +debootstrap (1.0.44) unstable; urgency=low + + * Remove double quotes to fix for loop on GNU/kFreeBSD, thanks to + Oleg Ginzburg (Closes: #693718). + + -- Cyril Brulebois Tue, 20 Nov 2012 23:55:53 +0100 + +debootstrap (1.0.43) unstable; urgency=low + + [ Joey Hess ] + * Fix "arc" typo. Closes: #686680 + + [ Colin Watson ] + * Add (Ubuntu) raring as a symlink to gutsy. + + [ Christian Perrier ] + * Add myself to Uploaders and drop Anthony Towns who is no + longer active in debootstrap maintenance for a few years. Thanks + for your work, Anthony. + * Bump Standards to 3.9.3 (checked) + * Replace XC-Package-Type by Package-Type in debian/control + + -- Christian Perrier Sat, 27 Oct 2012 12:46:46 +0200 + +debootstrap (1.0.42) unstable; urgency=low + + * Downgrade the absence of an InRelease file from a warning to an info + message. For now, debootstrap can cope fine without, and it's possible + there are Debian mirrors that don't have InRelease; Ubuntu doesn't quite + have InRelease support yet either (LP: #1017398). + + -- Colin Watson Tue, 03 Jul 2012 15:34:57 +0100 + +debootstrap (1.0.41) unstable; urgency=low + + [ Mehdi Dogguy ] + * Add support for InRelease files (Closes: #638682) + + -- Joey Hess Thu, 21 Jun 2012 13:16:22 -0400 + +debootstrap (1.0.40) unstable; urgency=low + + [ Joey Hess ] + * When installation or configuration of a package fails, output a message + that points the user to the log file. Attempt to grep out the first + package that dpkg failed on and show its name too. Closes: #472704 + + [ Colin Watson ] + * Add (Ubuntu) quantal as a symlink to gutsy. + + -- Colin Watson Thu, 26 Apr 2012 17:44:44 +0100 + +debootstrap (1.0.39) unstable; urgency=low + + * Retry corrupted downloads rather than carrying on almost regardless. + Patch mostly due to Michael Gilbert, rearranged somewhat by me (closes: + #618920). + * Stop at the end of the retrieval phase if any packages failed to + download. + + -- Colin Watson Tue, 13 Mar 2012 17:21:13 +0000 + +debootstrap (1.0.38) unstable; urgency=low + + [ Joey Hess ] + * Improve error message when a decompressor is not available, + to indicate which package has been built with bzip today. + Closes: #644719 + + [ Otavio Salvador ] + * Fix --print-debs support when using --foreign param. Closes: + #551837. + + [ Colin Watson ] + * pkgdetails_perl: Use the last of a sequence of stanzas for the same + package name, rather than the first (closes: #649319). + + -- Colin Watson Mon, 21 Nov 2011 13:20:53 +0000 + +debootstrap (1.0.37) unstable; urgency=low + + * Add (Ubuntu) precise as a symlink to gutsy. + + -- Colin Watson Wed, 05 Oct 2011 21:58:37 +0100 + +debootstrap (1.0.36) unstable; urgency=low + + * Guess host OS based on uname for non-Debian systems. Closes: #637363 + * Clarify "target" in usage message. + * Fix support for running debootstrap on a FreeBSD host to create a kFreeBSD + chroot or jail. Thanks, Arno Toell. + * Search PATH for programs, rather than checking hardcoded locations. + * Support using md5 and shaN programs, as found on FreeBSD, in addition + to md5sum and shaNsum. + * When FreeBSD (not kfreebsd) is the host, don't chroot to mount special + filesystems. + * When debootstrapping on FreeBSD, warn if necessary modules are not + loaded. Thanks, Arno Toell. + * Workaround for umount bug #634107, which broke pbuilder and "debootstrap ." + Closes: #631087 + + -- Joey Hess Sun, 21 Aug 2011 18:39:26 -0400 + +debootstrap (1.0.35) unstable; urgency=low + + [ Robert Millan ] + * Don't build devices.tar.gz if building on GNU/kFreeBSD (closes: + #637297). + * Don't use --arch when we specifically care about the host architecture + (closes: #637298). + + -- Colin Watson Wed, 10 Aug 2011 13:04:41 +0100 + +debootstrap (1.0.34) unstable; urgency=low + + * Add more information regarding the version and architecture in case + a download fails. Closes: #633625. + * add /usr/sbin and /sbin to PATH for fakechroot variant. Closes: + #588773 + * Move setup_devices to second stage of bootstrap. Closes: #498731, + #531316 + + -- Otavio Salvador Thu, 28 Jul 2011 19:13:10 +0200 + +debootstrap (1.0.33) unstable; urgency=low + + [ Joey Hess ] + * Mention minbase variant in --help. Closes: #632418 + * Use md5sums for sarge, which did not consistently have sha1sums + everywhere. Closes: #633158 + + [ Colin Watson ] + * Improve text of error message when decompression command is not + available. + + -- Otavio Salvador Sun, 24 Jul 2011 10:33:56 +0200 + +debootstrap (1.0.32) unstable; urgency=low + + * Use md5sums for woody and potato, which only had those checksums + in the Packages files. Closes: #627365 + + -- Joey Hess Mon, 30 May 2011 13:57:46 -0400 + +debootstrap (1.0.31) unstable; urgency=low + + [ Mark Hymers ] + * Don't use the Build-Essential: yes field in Debian, use the + build-essential package. Closes: #619700. + + [ Colin Watson ] + * If ubuntu-keyring is installed, check Release signatures against it when + bootstrapping Ubuntu gutsy and later. + * Recommend ubuntu-keyring rather than debian-archive-keyring on + Ubuntu-derived systems. + + -- Colin Watson Fri, 20 May 2011 09:45:48 +0100 + +debootstrap (1.0.30) unstable; urgency=low + + [ Joey Hess ] + * Recommend debian-archive-keyring, and if it is installed, + default to checking gpg signatures of the Release file against it + when bootstrapping sid, squeeze, wheezy, etch, and lenny. + Closes: #560038 + * Add --no-check-gpg option that can be used to disable release file + verification. Closes: #624229 + * Needs base-installer 1.117. + * Add a warning message if the keyring file is not available, and + --no-check-gpg is not specified. + * Clear all global variables used for options, so that unclean + environment doesn't break debootstrap. Closes: #621657 + * Removed the --boot-floppies switch and mode. Assuming this has + not been used in 10 years. + + [ Colin Watson ] + * Resolve dependencies from all requested components (LP: #740167). + + -- Joey Hess Tue, 26 Apr 2011 17:10:00 -0400 + +debootstrap (1.0.29) unstable; urgency=low + + [ Joey Hess ] + * Support bootstrapping oldstable. (Lenny could already be bootstrapped + using that suite name.) + + [ Colin Watson ] + * Add (Ubuntu) oneiric as a symlink to gutsy. + + -- Colin Watson Tue, 22 Mar 2011 10:58:49 +0000 + +debootstrap (1.0.28) unstable; urgency=low + + [ Miguel Figueiredo ] + * Fix for ar usage, thanks to Guillem Jover. Closes: #598729 + + [ Joey Hess ] + * Remove 5 second sleeps when debootstrap finds additional required + dependencies. d-i just got that much faster. + * Use SHA checksums. Defaulting to SHA256, and configurable by + SHA_SIZE environment variable. Closes: #614315 + * If a sha256sum program is not available, fall back to sha1sum. + This is to support debootstrap use on embedded systems, which are more + likely to have the latter. + * Avoid new(?) warning from dpkg about missing Maintainer field when + feigning install of a package. + + -- Joey Hess Mon, 21 Feb 2011 20:48:46 -0400 + +debootstrap (1.0.27) unstable; urgency=low + + [ Miguel Figueiredo ] + * Fix bug and typo on --private-key + Patch by Jonathan Klee. + + [ Jeremie Koenig ] + * Hurd support: + - Use the newer setup-translators script and firmlink + $TARGET/{dev,servers} in setup_devices_hurd; + - Don't attempt to build devices.tar.gz, which is not needed. + + -- Otavio Salvador Mon, 07 Feb 2011 19:40:24 -0200 + +debootstrap (1.0.26) unstable; urgency=low + + [ Christian Perrier ] + * Consistently use tab indenting in scripts/gutsy and scripts/sid + Patch by Karl Goetz. Closes: #601821 + * Fix a typo in the debootstrap script + Patch by Karl Goetz. Closes: #601822 + + [ Joey Hess ] + * sid: Remove old workaround for etch era coreutils/textutils md5sum + diversion problem. (#329394) + + -- Otavio Salvador Fri, 12 Nov 2010 10:07:41 -0200 + +debootstrap (1.0.25) unstable; urgency=low + + * Remove debug statement that slipped in. + * Add test to guard against devices.tar.gz being empty. + * /dev/MAKEDEV cannot be relied on (udev likes to make it a symlink to + true). Always use /sbin/MAKEDEV. Closes: #598080 + + -- Joey Hess Sun, 26 Sep 2010 13:18:31 -0400 + +debootstrap (1.0.24) unstable; urgency=low + + [ Miguel Figueiredo ] + * Apply patches from by Jonathan Klee and Guillaume Chauvel + to add support to https (closes: #521196). + + [ Colin Watson ] + * Add (Ubuntu) natty as a symlink to gutsy. + + [ Joey Hess ] + * Add support for wheezy. Closes: #597461 + + -- Joey Hess Sun, 19 Sep 2010 21:40:00 -0400 + +debootstrap (1.0.23) unstable; urgency=low + + * Add (Ubuntu) maverick as a symlink to gutsy. + * Add ${misc:Depends}. + + -- Colin Watson Wed, 19 May 2010 13:35:34 +0100 + +debootstrap (1.0.22) unstable; urgency=low + + * Redo release since it ended up with testing directory in tar.gz. + + -- Otavio Salvador Mon, 22 Feb 2010 16:52:49 -0300 + +debootstrap (1.0.21) unstable; urgency=low + + [ Otavio Salvador ] + * Apply patch from Clint Adams to add support for + gz/bz2/xz data.tar (closes: #458663). + + [ Guillem Jover ] + * Refactor deb extractors into two new functions. + * Use dpkg-deb if available instead of ar (closes: #557296). + * Add an --extractor option to override the automatic extractor selection. + + [ Otavio Salvador ] + * Document new --extractor option in manpage. + * Apply patch from Vagrant Cascadian not + fail if resolv.conf is a broken symlink (closes: #390647). + + [ Frans Pop ] + * Use tab indentation in scripts/debian/sid to reduce its size (relevant + for Debian Installer). + * Add apt to base packages for the buildd variant as it is no longer marked + Build-Essential. + + [ Otavio Salvador ] + * Apply patch from Andres Salomon to honor + --components when using mirror_style 'main' (closes: #561283). + * Apply patch from Andres Salomon to fix + iteration through components in download_main (closes: #561298). + + [ Joey Hess ] + * Allow the suite to be stable, testing, or unstable when debootstrapping + Debian. Closes: #288109 + * Make scripts directory in source tree look like installed directory, + and add a section to README explaining an easy way to run + debootstrap w/o installing it. Closes: #345762 + * Convert rules file to use dh with overrides. + * Remove binary-basedebs target from debian/rules. + This target has been broken in multiple ways since 2007. While I + accidentially partially fixed it with the above changes, this is evidence + it's dead code that can be safely removed. + + -- Otavio Salvador Sun, 21 Feb 2010 23:11:06 -0300 + +debootstrap (1.0.20) unstable; urgency=low + + * For recent Ubuntu versions, move $TARGET/sbin/initctl aside in the same + way we do start-stop-daemon, so that attempts to control Upstart jobs + won't inadvertently affect jobs in the host system. + * Rename EXAMPLE section in debootstrap(8) to EXAMPLES (closes: #548458). + + -- Colin Watson Sun, 04 Oct 2009 21:23:07 +0100 + +debootstrap (1.0.19) unstable; urgency=low + + * Ignore failures from dpkg --predep-package. It exits 1 if there are no + suitable packages available, which isn't an error for us, but in_target + complains anyway, so just use in_target_nofail; the termination + condition is handled immediately afterwards anyway. + + -- Colin Watson Thu, 24 Sep 2009 19:57:05 +0100 + +debootstrap (1.0.18) unstable; urgency=low + + * Only use dpkg from the chroot, as there is no guarantee dpkg is + available outside of the chroot (d-i installation for example). + + -- Aurelien Jarno Wed, 23 Sep 2009 11:37:01 +0200 + +debootstrap (1.0.17) unstable; urgency=low + + * Remove boneheaded use of sudo left over from testing (closes: #547949). + + -- Colin Watson Tue, 22 Sep 2009 20:10:19 +0100 + +debootstrap (1.0.16) unstable; urgency=low + + [ Colin Watson ] + * Cope with pre-dependencies of included packages that aren't in Priority: + required (closes: #487908). + * Upgrade to debhelper v7. (Override rules get pretty hairy for this + package, so I haven't switched to dh(1).) + * Use ports.ubuntu.com as default mirror on sparc for Ubuntu hardy and + beyond (LP: #431145). + * Add (Ubuntu) lucid as a symlink to gutsy. + + [ Frans Pop ] + * Makefile: remove unused ARCH variable. + + -- Colin Watson Mon, 21 Sep 2009 16:28:40 +0100 + +debootstrap (1.0.15) unstable; urgency=low + + * On Linux, clear out /etc/mtab on exit if it's not a symlink. Should fix + problems Wouter Verhelst and Martin Michlmayr are seeing with + initramfs-tools MODULES=dep, although it probably isn't a perfect + solution. + + -- Colin Watson Thu, 23 Jul 2009 16:45:00 +0100 + +debootstrap (1.0.14) unstable; urgency=low + + * Apply patch from Felix Zielcke to use "dpkg + --print-architecture" to avoid deprecation warning. Closes: #531680. + * Reference squeeze instead of sarge in manpage. Based on a patch from + Geoff Simmons . Closes: #534575. + * Apply patch from Riku Voipio to add support for + scratchbox variant. Closes: #536820. + + -- Otavio Salvador Wed, 22 Jul 2009 12:34:54 -0300 + +debootstrap (1.0.13) unstable; urgency=low + + [ Otavio Salvador ] + * Apply patch from Luca Favatella to improve + coding style. + + [ Colin Watson ] + * Add (Ubuntu) karmic as a symlink to gutsy. + + -- Colin Watson Fri, 24 Apr 2009 20:08:24 +0100 + +debootstrap (1.0.12) unstable; urgency=low + + [ Otavio Salvador ] + * Improve code to choose between libc packages. Thanks to Luca Favatella + for first version of the patch. + + [ Colin Watson ] + * Remove partial support for emitting translated progress messages with + gettext. Don't panic; d-i still has all the support necessary for this. + debootstrap's own support for doing this outside d-i with gettext's + shell bindings has been completely broken ever since it was added in + 2003, though, and nobody has complained. Fixing it would require a big + pile of infrastructure and some non-trivial patches, plus arranging to + copy all the translations over from base-installer, and it just doesn't + seem worth it, so lose the cruft (LP: #188690). + * Export PATH, just to make sure. It isn't necessarily exported by shells + running from init=/bin/sh or similar, and the upstream bash maintainer + is unwilling to export it by default; it's easy enough to do so here + (LP: #320188). + + -- Colin Watson Tue, 17 Mar 2009 16:38:46 +0000 + +debootstrap (1.0.11) unstable; urgency=low + + * Add (Ubuntu) jaunty as a symlink to gutsy. + * Clarify that --second-stage is needed to complete the bootstrapping + process after --foreign. + * Fix --make-tarball= option (closes: #484869). + * Fix old Debian scripts and all Ubuntu scripts to cope with Anthony's + change in 1.0.8 to make --second-stage not bother recalculating required + and base. + * Rename 'repeat' to 'repeatn', since 'repeat' is a reserved word in zsh; + although strictly speaking this seems like an incompatibility in zsh + when linked to /bin/sh (closes: #340058). + * Fix --unpack-tarball= option (thanks, Torsten Landschoff; closes: + #500759). + * Fix handling of relative DEBOOTSTRAP_DIR (thanks, Mikhail Gusarov; + closes: #503460). + * Cope with ancient versions of chroot(8) that don't call chdir() (thanks, + Patrik Arvhult; closes: #350635). + * Recommend gnupg for --keyring option (thanks, Robert Millan; closes: + #467571). + * Note that you can't --include packages with non-required Pre-Depends + (see #487908). + * Mention /sys in EXAMPLE section of manual page, and use "defaults" + rather than "none" as the mount options for /proc (thanks, Raúl Sánchez + Siles; closes: #410787). + * Add /dev/console to devices.tar.gz (after all, MAKEDEV's 'consoleonly' + was added for boot-floppies in the first place; see + https://lists.ubuntu.com/archives/ubuntu-devel/2009-January/027230.html). + * Add support for squeeze (closes: #513488). + + -- Colin Watson Wed, 18 Feb 2009 23:46:12 +0000 + +debootstrap (1.0.10) unstable; urgency=low + + [ Joey Hess ] + * Avoid "broken pipe" errors in bootstrap.log from the the smallyes function. + The errors themselves are inherent to how the function is used, so just + suppress them. Closes: #480560. + + [ Frans Pop ] + * Do not cache Release and Release.gpg files. Closes: #488424. + * Abort if a Packages file failed to verify. + * Update standards version to 3.8.0; no other changes needed. + + -- Frans Pop Wed, 02 Jul 2008 17:44:25 +0200 + +debootstrap (1.0.9) unstable; urgency=low + + [ Frans Pop ] + * Error out on unrecognized options to avoid invalid options to be + recognized as arguments. + + [ Colin Watson ] + * Use 'chown 0:0' in all scripts rather than deprecated 'chown 0.0' + (thanks, Evan Klitzke). + * Add (Ubuntu) intrepid as a symlink to gutsy. + + -- Colin Watson Tue, 29 Apr 2008 19:36:19 +0100 + +debootstrap (1.0.8) unstable; urgency=low + + [ Frans Pop ] + * Change Priority for the udeb to extra in line with overrides file. + + [ Colin Watson ] + * Partially revert r50134; there are people who depend on being able to + use the "upstream" Makefile on non-Debian systems. Create necessary + directories in the Makefile rather than relying on dh_installdirs to do + it (LP: #172645). + * Use ftp.us.debian.org rather than ftp.debian.org + (http://lists.debian.org/debian-devel-announce/2007/12/msg00002.html). + + [ Anthony Towns ] + * Add minbase variant for the sid script that only install apt (and + its dependencies) instead of all of base. (Closes: Bug#351912, + Bug#452654) + * Make --second-stage not bother recalculating required and base as + it's not needed. + * Make --arch and other arguments accept both "--arch i386" and + "--arch=i386" forms of specifying a parameter to avoid the + inconsistency. + + [ Stephen R. Marenka ] + * Allow installation of etch-m68k. (Closes: Bug#458965) + + [ Colin Watson ] + * Add minbase variant for Ubuntu gutsy/hardy; see Anthony's change above. + * Minor manual page formatting improvements. + + -- Colin Watson Tue, 15 Jan 2008 11:19:34 +0000 + +debootstrap (1.0.7) unstable; urgency=low + + * No longer include full devices tarball in udeb. + * Also try 'udpkg --print-architecture' when determining the target + architecture. + * Utility pkgdetails moved from debootstrap-udeb to bootstrap-base so that + the udeb can become 'Architecture: all'. + * Change /usr/lib/debootstrap to /usr/share/debootstrap. Closes: #430615. + * Use tab indentation in debootstrap and functions saving 3kB (relevant for + Debian Installer). + * Fix various inconsistencies in build scripts. + * Fix dpkg-genchanges warning 'missing Priority for source files'. + * Update Standards-Version to 3.7.2. No changes needed. + * Changes in udeb require base-installer 1.85. + + -- Frans Pop Wed, 14 Nov 2007 12:15:45 +0100 + +debootstrap (1.0.6) unstable; urgency=low + + * Ensure that the target directory exists in check_sane_mount. + * Don't ignore 'make clean' errors. (The Makefile is always present.) + + -- Colin Watson Sun, 21 Oct 2007 10:50:59 +0100 + +debootstrap (1.0.5) unstable; urgency=low + + [ Colin Watson ] + * Don't rely on GNU sed's s///I extension (closes: #350583). + + [ Joey Hess ] + * Skip the noexec/nodev test when running --print-debs or other operations + that do not involve building systems. + + -- Joey Hess Sat, 20 Oct 2007 23:10:34 -0400 + +debootstrap (1.0.4) unstable; urgency=low + + [ Neil Williams ] + * Add --second-stage-target option that allows embedded to test for + installations in a chroot on the device (closes: #445157). + + [ Colin Watson ] + * Add (Ubuntu) hardy as a symlink to gutsy. + * Unmount /lib/init/rw on exit (closes: #391604). + * Cope if uncompressed Packages is missing from Release (closes: #402380). + * Don't rely on XSI test(1) extensions. + * Add support for ssh:/// URLs (thanks, Steffen Joeris; closes: #434893). + * Fix Ubuntu hoary and breezy scripts to unmount /dev etc. on exit + (closes: #327708). + * Emit an error if we cannot create working devices or executables on the + target (based on work by Bastian Kleineidam; closes: #233798). + + -- Colin Watson Fri, 19 Oct 2007 14:57:37 +0100 + +debootstrap (1.0.3) unstable; urgency=low + + * Ignore errors when unmounting filesystems, to avoid stopping at the + first one with problems. + + -- Colin Watson Tue, 21 Aug 2007 12:32:37 +0100 + +debootstrap (1.0.2) unstable; urgency=low + + [ Joey Hess ] + * Document --components in man page. + * Update man page, as packages listed in --include should now be auto + dep-resolved by default. + + [ Colin Watson ] + * Extensive quoting fixes, allowing installation to a target containing + spaces (closes: #387673). + * scripts/debian/sid: Handle libc0.3 on hurd-i386 (thanks, Michael Banck; + closes: #314304). + * functions: Stub out /proc setup and add device setup for the Hurd + (thanks, Michael Banck; closes: #314311). + * Add --version option (closes: #294484). + + [ Otavio Salvador ] + * Fix bunzip2 path. Thanks Martín Ferrari by + the patch (closes: #436218). + + -- Otavio Salvador Tue, 07 Aug 2007 20:12:55 -0300 + +debootstrap (1.0.1) unstable; urgency=low + + * scripts/ubuntu/gutsy: Determine buildd variant dynamically using + Build-Essential: yes. + * scripts/ubuntu/gutsy.fakechroot: Remove devmapper postinst hack, no + longer needed. + * scripts/ubuntu/*.fakechroot: Merge into the corresponding main scripts + as variants. + + -- Colin Watson Fri, 20 Jul 2007 11:55:22 +0100 + +debootstrap (1.0.0) unstable; urgency=low + + [ Anthony Towns ] + * Make debootstrap team maintained under the d-i banner. + * Add Joey, Frans and Junichi as uploaders, remove JHM (not in the + d-i group). + * Make pkgdetails.c not need C99 extensions. (Closes: Bug#398977) + * Fix am_doing_phase implementation in debootstrap script. Thanks to + Tero Janka for spotting the problem and the fix. (Closes: Bug#409881) + + [ Joey Hess ] + * Drop support for sarge from the udeb. + * Update README.Debian: + - One todo item is done. (I think cross-strap is too, but unsure.) + - Reword NMU policy to note that it's team-maintained now. + * ACK my prior NMU. Closes: #418600 + * If /dev/MAKEDEV DNE, as on certain s390 machines, use /sbin/MAKEDEV. + Closes: #420908 + Note that /dev/MAKEDEV is still the correct location, and is still tried + first so that building works on all FHS systems, as noted in #190239. + + [ Colin Watson ] + * Add support for Ubuntu dapper (Closes: #342838), edgy, feisty, and + gutsy. Exclude everything but gutsy from the udeb. + * Fix "deboostrap" typo in debootstrap(8) (thanks, Adam Conrad). + * Fix "htp" typo in temporary /etc/apt/sources.list. + * Drop support for woody from the udeb too. + * When removing $TARGET/debootstrap, debootstrap.log is still open as + stdout/stderr and needs to remain so, but after unlinking it some NFS + servers implement this by a temporary file in the same directory, which + makes it impossible to rmdir that directory. Moving it instead works + around the problem (thanks, Steven McCoy; + https://launchpad.net/bugs/65003). + * Fix formatting error in debootstrap(8) (.R is not a macro). + * Reorganise scripts into scripts/debian/ and scripts/ubuntu/ directories + in the source tree to declutter the top level. + * Add default_mirror function; reorganise the debootstrap script a little + so that it works. Set the default mirror for Ubuntu suites to + http://archive.ubuntu.com/ubuntu, and the default mirror for Debian + etch/lenny/sid architectures other than amd64 and i386 to + http://ftp.us.debian.org/debian (per ajt; see bug #363049). + * Add devices created by fd to devices-std.tar.gz, so that + /dev/std{in,out,err} is available conveniently in chroots with /proc and + /dev/pts mounted (thanks, Matthias Klose). + * Document --keyring and --make-tarball. (Closes: #368988) + * Update Ubuntu mirrors: warty/hoary/breezy => old-releases.ubuntu.com, + unsupported architectures => ports.ubuntu.com. + * Add myself to Uploaders. + * Bump to 1.0.0. Nobody uses debootstrap in production, do they? + + [ Joey Hess ] + * Remove the extended package description (aka bloat) from the udeb. + + -- Colin Watson Sat, 23 Jun 2007 02:19:27 +0100 + +debootstrap (0.3.3.3) unstable; urgency=low + + * NMU + * Add support for lenny. + + -- Joey Hess Tue, 10 Apr 2007 15:24:15 -0400 + +debootstrap (0.3.3.2) unstable; urgency=low + + * NMU with maintainer approval + * Remove --force-auto-select option for 'sid' script as it is no longer + supported by dpkg. Closes: #409527. + + -- Frans Pop Fri, 16 Feb 2007 20:43:36 +0100 + +debootstrap (0.3.3.1) unstable; urgency=low + + * NMU with maintainer approval + * functions/get_debs: build list of available packages from all specified + sources; this allows debootstrap to also use e.g. custom versions of base + packages from a source of local packages included on an installation CD. + Closes: #398762. + + -- Frans Pop Thu, 16 Nov 2006 05:30:43 +0100 + +debootstrap (0.3.3) unstable; urgency=low + + * Include kFreeBSD and fakechroot support from 0.3.2.1 and 0.3.2.2 NMUs, + thanks to Otavio Salvador and Piotr Roszatycki. (Closes: Bug#319100, + Bug#328446, Bug#204652, Bug#315044, Bug#Bug#319799) + + * Require target to be specified in all cases; document usage of target + for --print-debs. (Closes: Bug#335922, Bug#337230) + + * Use ln -sf when symlinking awk for woody and sarge. (Closes: Bug#299048) + + -- Anthony Towns Sun, 6 Nov 2005 04:12:39 +1000 + +debootstrap (0.3.2.2) unstable; urgency=low + + * NMU + * Added relicensed fakechroot variant. Closes: #204652. + + -- Piotr Roszatycki Sat, 29 Oct 2005 11:29:00 +0200 + +debootstrap (0.3.2.1) unstable; urgency=low + + * NMU with maintainer approval + * Applied patch from Robert Millan to add support to + Debian GNU/kFreeBSD. Closes: #319799 + + -- Otavio Salvador Fri, 28 Oct 2005 16:14:57 -0200 + +debootstrap (0.3.2) unstable; urgency=low + + * Revert fakechroot NMUs (0.3.1.1, 0.3.1.3, 0.3.1.7) due to incompatible + license requirements (GPL) (Reopens: Bug#204652) + + * Changes from 0.3.1.2 NMU, thanks to Joey Hess: (Closes: Bug#314810) + + Fix incorrect use of "$@" in local. Closes: #314157, #314547 + + Fix fd redirection in download progress code. See #314373 + + Remove md5sums file from udeb. Closes: #314378 + + Fix debian-installer mode warning code. Closes: #314340 + + * Changes from 0.3.1.4 NMU, thanks to Joey Hess: + + Wrap eval statement in exit_function in parens, working around + bug #315444 in busybox sh. Closes: #314373 + + * Changes from 0.3.1.5 NMU, thanks to Anibal Monsalve Salazar: + + Fixed "--variant=buildd option does not work" for pbuilder, + closes: #314858. Patch by Matt Kraai . + + * Changes from 0.3.1.6 NMU, thanks to Joey Hess: + + Patch from Colin to redirect status messages to stderr when running + --print-debs. Closes: #315875 + + Restore logging to stderr in debian-installer mode. Closes: #314160 + + * Changes from 0.3.1.8 NMU, thanks to Petter Reinholdtsen: + + [functions] Mount /sys if it exist and is supported by the kernel. + Patch from Cajus Pollmeier, Colin Watson and Ubuntu. (Closes: #289105) + + [debootstrap] Document --resolve-deps in usage info. (Closes: #328161) + + [etch] Replace libsigc++-1.2-5c102 with libsigc++-1.2-5c2. (Closes: #334506) + + [etch] Remove pppoe from base, and only install + ipchains on m68k. Patch from Sven Luther. (Closes: #239390) + + [sarge] Remove duplicate entries for m68k and amd64. Patch from + Frans Pop. (Workaround for bug #319777) + + [etch] Add support for ppc64. The patch for 'sid' did no longer + apply. Patch from Andreas Jochens. (Closes: #313353) + + [sarge,etch,sid] Set DEBCONF_NONINTERACTIVE_SEEN=true during build, to + avoid questions during upgrade. (Closes: #238301) + + Add script for breezy. Patch from Colin Watson. (Closes: #315940) + + * Changes from 0.3.1.9 NMU, thanks to Joey Hess: + + Replace the etch script with a copy of the sid script, which pulls in + gnupg, so the installed etch system has a usable apt. Closes: #334521 + + * Create /dev/ptmx in minimal devices tarball. (Closes: Bug#317072) + + * Don't create empty available files, since old dpkg and new kernels can't + deal with them. (Closes: Bug#308169, Bug#329468) + + * Bump Standards-Version. Bump debhelper compatability level to 4. + * Cleanup debian/rules, thanks to Joey Hess. (Closes: Bug#314863) + + * Emit error message if no pkgdetails is available. (Closes: Bug#326831) + + * Turn on --resolve-deps by default. Add --no-resolve-deps as an option. + Combined with the previous changes to make the etch script dynamically + determine base, this should resolve all the "can't install " + bugs. (Closes: Bug#280210, Bug#308361, Bug#318281, Bug#323362, + Bug#318254, Bug#313292, Bug#334683, Bug#248578, Bug#289635) + + * md5sum doesn't exist when coreutils is unpacked but not configured; + cp it across so it's available for --second-stage. (Closes: Bug#329394) + + * Catch failures in "dpkg --status-fd" (Closes: Bug#317447, Bug#323661) + + * Make "without" work right for duplicates (Closes: Bug#316884, + Bug#319777) + + * Simplify and correct file descriptor handling and debootstrap.log + behaviour. + + * Delete $TARGET with --print-debs and --make-tarball. (Closes: Bug#328369) + + * Add a --make-tarball option. (Closes: Bug#152845) + + * Create a default sources.list for apt. (Closes: Bug#283234, Bug#315225) + + * Update manpage to talk about woody instead of sarge. (Closes: Bug#315862) + + * Use partial/ directory when downloading. (Closes: Bug#109176) + + -- Anthony Towns Sun, 23 Oct 2005 14:49:08 +1000 + +debootstrap (0.3.1) unstable; urgency=low + + * sid script updated: + - Determine base dynamically (Priority: required for required packages, + Priority: important for base packages, Build-Essential: yes for buildd + variant base). (Closes: Bug#88984, Bug#193134) + - Use fine grained dpkg progress display, thanks again to Colin Watson. + (Closes: Bug#229314, Bug#231109, Bug#244563) + + * dpkg output (etc) goes to /var/log/bootstrap.log in the target, rather + than stdout. This is probably difficult for frontends to capture + at present. + + * Parsing of Packages file sped up. (Yay!) + + * debootstrap.deb now arch: all (Closes: Bug#122465, Bug#131552) + - perl implementation of pkgdetails used by preference + - devices.tar.gz reduced to minimal set of devices; frontends should + setup udev or supply their own devices or similar in future + - /usr/lib/debootstrap/arch not shipped + - none of the above applies to udebs yet; though the devices.tar.gz + change will eventually + + * Support for verifying based on Release.gpg files (--keyring). Thanks + to Colin Watson. (Closes: Bug#313383) + + -- Anthony Towns Tue, 14 Jun 2005 00:22:55 +1000 + +debootstrap (0.3.0) unstable; urgency=low + + * The Gernot Heiser release, dedicated to everyone who drinks enough to + lose their better judgement, and those of us who didn't have any in + the first place. + + * Major update. New features: + + Use $TARGET/debootstrap directory for state info + (--keep-debootstrap-dir) + + Support for cross-strapping (--foreign / --second-stage) + (Closes: Bug#202529) + + Support for resolving dependencies (--resolve-deps) + + Support for Debian etch, and Ubuntu warty and hoary (Closes: Bug#312417) + + Support for handling variants within the main suite script + + Support for other versions of base packages in /v/c/apt/archives + + Initial support for fine-grained dpkg progress display, thanks to + Colin Watson (currently only for warty and hoary) + + Initial support for determining base system dynamically. + + No longer display "debootstrap.invalid" when working with + Release/Packages files. (Closes: Bug#241795, Bug#256255) + + Ignores failures for on_exit cleanup commands. (Closes: Bug#253387, + Bug#253468, Bug#308774) + + Early reporting of unavailable packages. + + More efficient parsing of Packages files. + + Generalised additions and exclusions. (Closes: Bug#191793) + + Handles symlinked configuration files in /etc a little better. + (Closes: Bug#161987, Bug#252907, Bug#272257) + + * Dropped support for slink. + + * Use ln -fs for mawk/awk link. (Closes: Bug#248398, Bug#258524) + + * Dropped mail-transport-agent, and hence mailx and at from sid/etch base. + (Closes: Bug#168473) + * Dropped ipchains for i386 (Closes: Bug#266119) + * Other minor changes to meet dependencies, also. (Closes: Bug#312701) + + * Minor manpage fixes. (Closes: Bug#285777) + * Add check for specifying no components (CloseS: Bug#283810) + + * Include 0.2.45 NMUs, thanks to Steve Langasek. + (Closes: Bug#295571, Bug#283752, Bug#278158) + + -- Anthony Towns Sun, 12 Jun 2005 23:49:58 +1000 + +debootstrap (0.2.45-0.2) unstable; urgency=low + + * Non-maintainer upload. + * [sarge, sid] Replace libparted1.6-0 with libparted1.6-12 for ia64, + to keep up with the ABI changes for that package. (Closes: #295571) + * [sarge, sid] include pciutils on hppa as well, per request of the + hppa folks. (Closes: #283752) + + -- Steve Langasek Fri, 25 Feb 2005 22:23:30 -0800 + +debootstrap (0.2.45-0.1) unstable; urgency=low + + * Non-maintainer upload. + * [sarge, sid] Drop libgnutls10 and libgcrypt7, since they are no + longer needed by exim4. (Closes: #278158). + + -- Steve Langasek Thu, 20 Jan 2005 21:20:22 -0800 + +debootstrap (0.2.45) unstable; urgency=high + + * Acknowledge NMUs. (Closes: #270135) + * [woody.buildd] Corrected ia64 special cases. Patch by Brett Johnson + . (Closes: #271894) + + -- J.H.M. Dassen (Ray) Sat, 18 Sep 2004 13:49:23 +0200 + +debootstrap (0.2.44.2) unstable; urgency=low + + * NMU again, this time using the makedev in unstable instead of the + experimental so devices.tar.gz isn't empty on ia64... oops... /o\ + + -- Bdale Garbee Tue, 14 Sep 2004 20:03:56 -0600 + +debootstrap (0.2.44.1) unstable; urgency=low + + * NMU to resolve d-i inability to install sid on ia64 + * add pciutils to the base package list for ia64, to avoid having to regress + efibootmgr in unstable, closes: #270315, #268490 + + -- Bdale Garbee Mon, 13 Sep 2004 15:11:11 -0500 + +debootstrap (0.2.44) unstable; urgency=high + + * [sarge] Removed "gcc-3.0-base" and "libstdc++3" for HPPA as they have been + removed from sarge as well on that arch. (Closes: #268917) + + -- J.H.M. Dassen (Ray) Mon, 30 Aug 2004 08:53:30 +0200 + +debootstrap (0.2.43) unstable; urgency=high + + * [sarge] Added back libgnutls10 in order not to break d-i testing. + (Closes: #268578, #268663). + + -- J.H.M. Dassen (Ray) Sun, 29 Aug 2004 09:08:48 +0200 + +debootstrap (0.2.42) unstable; urgency=high + + * Acknowledge NMUs. (Closes: #262137, #262165, #262178, #262375) + * [sarge] Switch to libgnutls11 so exim4 can switch. (Closes: #268325) + * [sid] Removed "gcc-3.0-base" and "libstdc++3" for HPPA as they have been + removed from sid. (Closes: #268049) + * [Makefile] Make the regular video devices on all archs. (Closes: #265081) + * [Makefile,debootstrap] Switched away from deprecated chown syntax; + switched away from XSIisms '-a' and '-o'. (Closes: #256098) + * [debootstrap.8] Use '\-' rather than '-' in options. (Closes: #263955) + Confirmed that the "exlude" typo has already been fixed. (Closes: #254108) + Applied patch by Javier Fernández-Sanguino Peña + for "file" URL documentation and a more complete example. (Closes: #226662) + + -- J.H.M. Dassen (Ray) Fri, 27 Aug 2004 15:40:02 +0200 + +debootstrap (0.2.41-0.2) unstable; urgency=low + + * Non-maintainer upload + * [sarge, sid] Add missing libgcrypt11 to base, needed by libgnutls11 + in sid and needed in sarge for opencdk8 to be rebuilt against it + (closes: #262375, #262178). + + -- Steve Langasek Fri, 30 Jul 2004 20:26:57 -0700 + +debootstrap (0.2.41-0.1) unstable; urgency=low + + * Non-maintainer upload with consent of JHM. + * Pull libfribidi0 back out of base, it's opportunistically installed + by d-i now for the locales that need it (closes: #262137). + * Re-add bootloaders on ia64, sparc, mips, hppa, and m68k to base, + because debian-installer isn't ready for this change (closes: #262165). + + -- Steve Langasek Thu, 29 Jul 2004 14:14:33 -0700 + +debootstrap (0.2.41) unstable; urgency=high + + * High urgency upload as per tbm's request. + * [sarge, sid] No longer install setserial, as it causes problems on some + systems (e.g. #212646) and there is a consensus it is no longer needed in + a base environment. + * [sarge, sid] Removed aboot, aboot-base, elilo, efibootmgr, silo, dvhtool, + delo, palo, vmelilo. As per the consensus reached in the thread starting + with http://lists.debian.org/debian-boot/2004/04/msg00634.html, the + installation of boot loaders is now debian-installer's responsibility. + (Closes: #247906) + * [sarge, sid] Added libfribidi0 to base to make debconf localisation into + right to left languages possible. (Closes: #253229) + * [sarge.buildd] Drop libdb4.0 for libdb4.2 as needed by perl. + * [sid] Added libgnutls11 as libgnutls10 is being phased out. + * [Makefile] Include /dev/ida on ia64. (Closes: #258055) + + -- J.H.M. Dassen (Ray) Thu, 29 Jul 2004 20:37:37 +0200 + +debootstrap (0.2.40) unstable; urgency=medium + + * [woody.buildd] Ensure the on_exit umounting of /dev/pts doesn't mess up + an otherwise OK exit status. (Closes: #260699) + * Acknowledge NMUs. (Closes: #258350, #260253) + + -- J.H.M. Dassen (Ray) Thu, 22 Jul 2004 21:53:20 +0200 + +debootstrap (0.2.39.2) unstable; urgency=low + + * Non-maintainer upload. + * [sarge, sid] Drop quik from powerpc, as debian-installer handles this + now (closes: #260253). + + -- Colin Watson Thu, 22 Jul 2004 16:56:19 +0100 + +debootstrap (0.2.39.1) unstable; urgency=low + + * NMU + * add passwd to sid.buildd,sarge.buildd as bash depends on them + + -- Junichi Uekawa Fri, 9 Jul 2004 09:07:28 +0900 + +debootstrap (0.2.39) unstable; urgency=medium + + * [sarge,sid] Dropped libdb2. Thanks Matt Zimmerman. (Closes: #250813) + * [sarge,sid] Dropped libident. Thanks LaMont Jones. (Closes: #251320) + * [sarge,sid] Dropped slang1. Thanks LaMont Jones. (Closes: #251328) + * [woody.buildd] Install libperl5.6. Thanks Rene Engelhard. (Closes: #251702) + * [sarge.buildd] Install libc6.1 rather than libc6 on alpha. Thanks Rene + Engelhard. (Closes: #251703) + + Goswin von Brederlow + * Copy script for sarge to sid + * Add handling for amd64 to sarge/sid scripts + * Dropped gcc-3.2-base. (Closes: #250836) + + -- J.H.M. Dassen (Ray) Sat, 5 Jun 2004 10:02:50 +0200 + +debootstrap (0.2.38.1) unstable; urgency=low + + * NMU. + * [sarge] Add libdb4.2 since apt-utils (0.5.25) depends on this. + + -- Otavio Salvador Thu, 20 May 2004 22:18:41 -0300 + +debootstrap (0.2.38) unstable; urgency=medium + + * [woody.buildd] Readd libgdbmg1 (for perl-modules). + + -- J.H.M. Dassen (Ray) Fri, 7 May 2004 10:55:13 +0200 + +debootstrap (0.2.37) unstable; urgency=medium + + * [debian/control] Bumped makedev build dependency so as not to get pty + permissions problems. (Closes: #246709) + * [sid, sid.buildd] Add/switch to libdb4.2 for the new perl packages. + * Acknowledge NMU 0.2.36.1. (Closes: #246368) + + -- J.H.M. Dassen (Ray) Tue, 4 May 2004 07:58:02 +0200 + +debootstrap (0.2.36.1) unstable; urgency=low + + * Non-maintainer upload with maintainer permission. + * [sarge, sid] Drop yaboot from powerpc, as debian-installer handles this + now (closes: #246368). + + -- Colin Watson Fri, 30 Apr 2004 00:05:02 +0100 + +debootstrap (0.2.36) unstable; urgency=high + + Joey Hess : + * [sid, sarge] Add a subst_package function, and use it to replace libc6 + with libc6.1 on alpha and ia64, to avoid reordering libc in the required + list and work around bug #238963. (Closes: #245680) + + -- J.H.M. Dassen (Ray) Sun, 25 Apr 2004 18:37:42 +0200 + +debootstrap (0.2.35) unstable; urgency=high + + * [sarge, sid] Dropped syslinux. (Closes: #205379) + * [woody, woody.buildd] Removed libgdbmg1. (Closes: #244447) + * [debootstrap, functions] Sync at the end of debootstrap. (Closes: #225742) + + -- J.H.M. Dassen (Ray) Thu, 22 Apr 2004 16:51:49 +0200 + +debootstrap (0.2.34) unstable; urgency=high + + * [sid] Dropped libpci1 and libpci2 as the pciutils dependency change has + been reverted. (Closes: #244344) + + -- J.H.M. Dassen (Ray) Thu, 22 Apr 2004 08:14:28 +0200 + +debootstrap (0.2.33) unstable; urgency=high + + * [sid] Added libpci1 and libpci2 for all archs where pciutils is installed, + as pciutils now depends on them. (Closes: #244344) + + -- J.H.M. Dassen (Ray) Sun, 18 Apr 2004 09:41:23 +0200 + +debootstrap (0.2.32) unstable; urgency=high + + * [sarge, sid] No longer try to filter out console-tools on s390. While + console-tools is basically useless on s390, base-config depends on it. + (Closes: #241727) + + -- J.H.M. Dassen (Ray) Fri, 9 Apr 2004 16:26:23 +0200 + +debootstrap (0.2.31) unstable; urgency=medium + + * [sarge] Exim has changed GnuTLS dependencies. Added libgnutls10, + libgcrypt7, libgpg-error0, libopencdk8, libtasn1-2; dropped libgnutls7, + libgcrypt1, libtasn1-0. + * [sarge] Removed libgnutls7, libgcrypt1, libtasn1-0. + + -- J.H.M. Dassen (Ray) Tue, 23 Mar 2004 22:47:28 +0100 + +debootstrap (0.2.30) unstable; urgency=medium + + * [sarge, sid] aboot needs aboot-base. (Closes: #236368, #239302) + + -- J.H.M. Dassen (Ray) Mon, 22 Mar 2004 21:10:31 +0100 + +debootstrap (0.2.29) unstable; urgency=low + + * NMU with permission of maintainer. + * Added {woody,sarge,sid}.buildd scripts to create build chroots. + Closes: #236418. + * Added --variant=buildd option for convenient access to these scripts. + + -- Daniel Schepler Wed, 10 Mar 2004 02:29:27 -0800 + +debootstrap (0.2.28) unstable; urgency=medium + + * [sid] Exim has changed GnuTLS dependencies. Added libgnutls10, libgcrypt7, + libgpg-error0, libopencdk8, libtasn1-2; dropped libgnutls7, libgcrypt1, + libtasn1-0. + * [sarge,sid] Dropped lilo, mbr, modconf, libdevmapper1.00 as + debian-installer handles the bootloader installation and modules + configuration. (Closes: #232667, #232672, #232673) + + -- J.H.M. Dassen (Ray) Tue, 24 Feb 2004 09:57:35 +0100 + +debootstrap (0.2.27) unstable; urgency=medium + + * [sarge] Lilo now needs libdevmapper1.00; Removed libopencdk8, libgcrypt7, + libgpg-error0. + + -- J.H.M. Dassen (Ray) Sat, 14 Feb 2004 01:19:48 +0100 + +debootstrap (0.2.26) unstable; urgency=medium + + * [sarge] Removed gcc-3.2-base. (Closes: #230697) + * [sid] Lilo now needs libdevmapper1.00 . + + -- J.H.M. Dassen (Ray) Tue, 3 Feb 2004 08:27:54 +0100 + +debootstrap (0.2.25) unstable; urgency=high + + * [functions] Unmount proc/bus/usb, not proc/usb. (Closes: #229122) + + -- J.H.M. Dassen (Ray) Fri, 30 Jan 2004 18:01:29 +0100 + +debootstrap (0.2.24) unstable; urgency=high + + * [functions, sarge, sid] Try to unmount proc/usb, dev/shm, dev/pts on exit; + don't fail when there's nothing to unmount. + (Closes: #229122, #229901, #229907) + * [woody] Don't fail when there's no dev/pts to unmount. + * [sarge, sid] Don't install pcmcia-cs as debian-installer takes care of + that where needed. (Closes: #221907) + * [sid] Removed libopencdk8, libgcrypt7, libgpg-error0. + * [sarge] libopencdk8 (needed for exim4-daemon-light via libgnutls7) + Depends: libgcrypt7, libgpg-error0. (Closes: #229989) + + -- J.H.M. Dassen (Ray) Wed, 28 Jan 2004 18:48:02 +0100 + +debootstrap (0.2.23) unstable; urgency=high + + * [sarge] Dropped libopencdk4 in favour of libopencdk8 as gnutls has switched. + + -- J.H.M. Dassen (Ray) Thu, 1 Jan 2004 01:30:02 +0100 + +debootstrap (0.2.22) unstable; urgency=high + + * [sid] libopencdk8 Depends: libgcrypt7, libgpg-error0. + + -- J.H.M. Dassen (Ray) Wed, 31 Dec 2003 12:35:03 +0100 + +debootstrap (0.2.21) unstable; urgency=high + + * [sarge] Added coreutils' new predependencies libacl1 and libattr1; removed + libsasl2 as it is no longer needed. + + -- J.H.M. Dassen (Ray) Sun, 28 Dec 2003 22:54:08 +0100 + +debootstrap (0.2.20) unstable; urgency=high + + * [sarge] base-config now Depends: aptitude; aptitude Depends: + libsigc++-1.2-5c102. + + -- J.H.M. Dassen (Ray) Sun, 28 Dec 2003 15:11:31 +0100 + +debootstrap (0.2.19) unstable; urgency=high + + * [sid] base-config now Depends: aptitude; aptitude Depends: + libsigc++-1.2-5c102. + + -- J.H.M. Dassen (Ray) Wed, 24 Dec 2003 09:03:44 +0100 + +debootstrap (0.2.18) unstable; urgency=low + + * Thanks to Steinar Gunderson and Matt Kraii for the NMU fixing some + d-i related problems. (Closes: Bug#220150) + * Acknowledge that the problems really are fixed now. (Closes: + Bug#213669, Bug#209273, Bug#210912) + + * Fix downloading of Packages files to retry if bz2 or gz isn't available + on the mirror. (Closes: Bug#194592) + + -- Anthony Towns Sat, 15 Nov 2003 00:13:13 +1000 + +debootstrap (0.2.17.1) unstable; urgency=high + + * NMU + * [sarge,sid] Display only the package name when retrieving packages. + (Closes: #213669, #209273) + * [sarge,sid] Added progress information for downloading package + details. (Closes: #210912) + + -- Steinar H. Gunderson Mon, 10 Nov 2003 15:11:09 +0100 + +debootstrap (0.2.17) unstable; urgency=high + + * [sarge] Fixed typo: libreadlin4 -> libreadline4. (Closes: #219655) + + -- J.H.M. Dassen (Ray) Sat, 8 Nov 2003 23:23:37 +0100 + +debootstrap (0.2.16) unstable; urgency=high + + * [sarge,sid] libreadline4 is required for amiga-fdisk on powerpc. + (Closes: #218533) + * [sarge,sid] Put libreadline4 in required rather than base for ia64. + + -- J.H.M. Dassen (Ray) Wed, 5 Nov 2003 08:09:41 +0100 + +debootstrap (0.2.15) unstable; urgency=high + + * ia64 fixes by Richard Hirst : (Closes: #218533) + * [sarge, sid] Add libreadline4 to base for ia64 as parted needs it. + * [sarge, sid] Remove gcc-2.96-base from required for ia64. + + -- J.H.M. Dassen (Ray) Sat, 1 Nov 2003 12:58:34 +0100 + +debootstrap (0.2.14) unstable; urgency=high + + * [sarge] Made exim4 the default MTA. (Closes: #217657) + * [sarge] Removed libstdc++2.10-glibc2.2, libldap2 . + * [sid] Dropped libopencdk4 in favour of libopencdk8 as gnutls has switched. + + -- J.H.M. Dassen (Ray) Tue, 28 Oct 2003 09:56:27 +0100 + +debootstrap (0.2.13) unstable; urgency=high + + * [sarge] Added libtextwrap1 for tasksel. + + -- J.H.M. Dassen (Ray) Wed, 22 Oct 2003 08:10:37 +0200 + +debootstrap (0.2.12) unstable; urgency=high + + * [sarge, sid] Add libreadline4 to required for m68k as amiga-fdisk needs + it. (Closes: #216617) + + -- J.H.M. Dassen (Ray) Mon, 20 Oct 2003 10:05:09 +0200 + +debootstrap (0.2.11) unstable; urgency=high + + * [sid] Added libc6-sparc64 lib64gcc1 lib64ncurses5 to base for sparc. + (Closes: #215590) + * [sarge, sid] Dropped libreadline as bash no longer depends on it. + * [sid] Dropped libstdc++2.10-glibc2.2 and its associated special cases as + it is no longer needed. + + -- J.H.M. Dassen (Ray) Wed, 15 Oct 2003 19:42:58 +0200 + +debootstrap (0.2.10) unstable; urgency=high + + * [sid] Fixed /usr/sbin/sendmail symlink to point to exim4. (Closes: #213734) + + -- J.H.M. Dassen (Ray) Sat, 4 Oct 2003 15:47:31 +0200 + +debootstrap (0.2.9) unstable; urgency=high + + * [sarge] Added libgdbm3 for man-db. + + -- J.H.M. Dassen (Ray) Thu, 2 Oct 2003 23:57:09 +0200 + +debootstrap (0.2.8) unstable; urgency=high + + * [sid] Added libtextwrap1 for tasksel; removed libsasl2 as it is no longer + needed. + + -- J.H.M. Dassen (Ray) Thu, 2 Oct 2003 07:57:16 +0200 + +debootstrap (0.2.7) unstable; urgency=high (fixes RC d-i bug) + + * [sarge] Reinstated special-case for libperl5.8; it is still needed for + non-i386 until sarge has perl >= 5.8.0-20. (Closes: #213280) + * [debian/control] Updated Standards-Version; fixed removal of slink and + potato scripts from udeb. + * [debian/control] Updated priorities; debootstrap-udeb is required (for + debian-installer). + * [debian/rules] Fixed dpkg-distaddfile accordingly. + + -- J.H.M. Dassen (Ray) Tue, 30 Sep 2003 14:31:57 +0200 + +debootstrap (0.2.6) unstable; urgency=low + + * [sarge] Added e2fslibs, libcomerr2, libss2, libuuid1 for e2fsprogs. + + -- J.H.M. Dassen (Ray) Fri, 26 Sep 2003 13:50:58 +0200 + +debootstrap (0.2.5) unstable; urgency=low + + * [sid] Added libgdbm3 for man-db. + * [sarge, sid] Dropped special-case for libperl5.8 (Closes: #210425). + * [sid] Make exim4 the default MTA as it is configured through debconf. + (Closes: #208047) + * [sid] Removed libldap2 which is no longer needed. + + -- J.H.M. Dassen (Ray) Sun, 21 Sep 2003 13:30:49 +0200 + +debootstrap (0.2.4) unstable; urgency=low + + * [sid] Added coreutils' new predependencies libacl1 and libattr1. + * [debian/README.Debian] Corrected example invocation. (Closes: #206142) + * [debian/README.Debian] Fixed a typo. + + -- J.H.M. Dassen (Ray) Wed, 20 Aug 2003 10:28:49 +0200 + +debootstrap (0.2.3) unstable; urgency=low + + * [sarge] Add new dependencies of debconf: debconf-i18n + liblocale-gettext-perl libtext-wrapi18n-perl libtext-charwidth-perl. + * Acknowledge NMU. (Closes: #203370) + + -- J.H.M. Dassen (Ray) Sat, 16 Aug 2003 20:15:40 +0200 + +debootstrap (0.2.2-0.1) unstable; urgency=low + + * NMU. + * Fix typo in woody script. (Closes: #203370) + + -- Petter Reinholdtsen Tue, 29 Jul 2003 20:29:01 +0200 + +debootstrap (0.2.2) unstable; urgency=low + + * [debian/changelog] Included entries for NMUs 0.1.17.31 through .34 whose + changes were incorporated by aj already. + * [Makefile] Invoke MAKEDEV through its FHS location (noted by Matt + Zimmerman). (Closes: #190239) + * Acknowledge older NMUs whose changes have been incoporated. + (Closes: #135675, #161695, #191849) + + -- J.H.M. Dassen (Ray) Tue, 29 Jul 2003 18:31:49 +0200 + +debootstrap (0.2.1) unstable; urgency=low + + * The Day of the Daffodils release. + + * Accept NMUs up to 0.1.17.30. Thanks guys! (Closes: Bug#148377, + Bug#150161, Bug#150492, Bug#153962, Bug#154463, Bug#155906, + Bug#160879, Bug#161469, Bug#161469, Bug#161722, Bug#163860, + Bug#172118, Bug#176221, Bug#179504, Bug#179725, Bug#185397, + Bug#187893, Bug#188053, Bug#189472, Bug#189551, Bug#190108, + Bug#191288, Bug#193794, Bug#193806, Bug#195012, Bug#195742, + Bug#199333, Bug#201066) + * JHM added to Uploaders. + + * Change the info/error/warning/progress calls to include a unique word + for each string, a printf format string, and any arguments to the + printf string. + * Add support for debian-installer interaction + + * Add some support for l10n. Gettext is used if it's available; no + translations are included as of yet. This support doesn't + affect debian-installer, which has its own stuff for i18n, nor + boot-floppies. (Closes: Bug#125647) + + * Some initial support for cross-bootstrapping in the sid script. + + * Use dpkg --print-installation-architecture instead of + --print-architecture. (Closes: Bug#138526, Bug#159720) + + * Add new dependencies of debconf: debconf-i18n liblocale-gettext-perl + libtext-wrapi18n-perl libtext-charwidth-perl. (Closes: Bug#201066) + * Add new dependencies of libldap2: libgnutls7 libgcrypt1 liblzo1 + libopencdk4 libtasn1-0 zlib1g. (Closes: Bug#201663) + * Remove libgdbmg1. (Closes: Bug#202304) + * Add new dependecies of e2fsprogs: e2fslibs libcomerr2 libss2 libuuid1. + (Closes: Bug#203033) + * Add wget to base. (Closes: Bug#145635) + * Switch from netkit-ping to iputils-ping. + + * Changed the manpage a little. (Closes: Bug#126864) + * Updated README.Debian. + + -- Anthony Towns Tue, 29 Jul 2003 18:15:24 +1000 + +debootstrap (0.1.17.34) unstable; urgency=medium + + * [sid] Added e2fsprogs' new predependencies (e2fslibs, libcomerr2, libss2, + libuuid1). + * [sarge] Removed libgdbmg1 as it is no longer needed. + + -- J.H.M. Dassen (Ray) Sun, 27 Jul 2003 09:20:49 +0200 + +debootstrap (0.1.17.33) unstable; urgency=medium + + * [sid] Removed libgdbmg1 as it is no longer needed. + * [sarge] libldap2 now Depends: libgnutls7, libsasl2; added those and their + dependencies (libgcrypt1 liblzo1 libopencdk4 libtasn1-0 zlib1g). Dropped + libsasl7 in favour of libsasl2. + + -- J.H.M. Dassen (Ray) Mon, 21 Jul 2003 19:00:28 +0200 + +debootstrap (0.1.17.32) unstable; urgency=medium + + * [sid] libldap2 now Depends: libgnutls7; added that and its dependencies + (libgcrypt1 liblzo1 libopencdk4 libtasn1-0 zlib1g); dropped libssl0.9.7 . + + -- J.H.M. Dassen (Ray) Thu, 17 Jul 2003 07:05:09 +0200 + +debootstrap (0.1.17.31) unstable; urgency=medium + + * [sid] Follow debconf changes. debconf now Depends: debconf-i18n | + debconf-english; debconf-i18n having Priority: important and + debconf-english having Priority: extra, so we satisfy the dependency + through debconf-i18n. debconf-i18n in turn pulls in three additional + packages: liblocale-gettext-perl, libtext-wrapi18n-perl, + libtext-charwidth-perl . + + -- J.H.M. Dassen (Ray) Sun, 13 Jul 2003 08:52:55 +0200 + +debootstrap (0.1.17.30) unstable; urgency=medium + + * [sarge] + * Added sysv-rc for /usr/sbin/update-rc.d . + * Added initscripts to satisfy sysvinit's predependency. + * libparted1.6-0 has replaced libparted1.4 on ia64. (Closes: #197957) + + -- J.H.M. Dassen (Ray) Mon, 30 Jun 2003 07:05:22 +0200 + +debootstrap (0.1.17.29) unstable; urgency=medium + + * [sid] libconsole has replaced console-tools-libs. (Closes: #195722) + * [sarge] libperl5.6 has been replaced by libperl5.8 . (Closes: #195588) + + -- J.H.M. Dassen (Ray) Mon, 2 Jun 2003 00:40:54 +0200 + +debootstrap (0.1.17.28) unstable; urgency=medium + + * [sarge] libnewt0.51 has replaced libnewt0; it requires slang1a-utf8. + + -- J.H.M. Dassen (Ray) Wed, 28 May 2003 07:42:14 +0200 + +debootstrap (0.1.17.27) unstable; urgency=medium + + * urgency medium to not hold up .26 with that longer as necessary + * [sarge] added libtext-iconv-perl (this is the second part + from .22) (closes: #184539) + + -- Rene Engelhard Mon, 19 May 2003 00:08:48 +0200 + +debootstrap (0.1.17.26) unstable; urgency=medium + + * [sarge] libpcap0.7 has replaced libpcap0. + + -- J.H.M. Dassen (Ray) Sun, 18 May 2003 23:23:46 +0200 + +debootstrap (0.1.17.25) unstable; urgency=medium + + * [sarge] Added libblkid1 (for e2fsprogs). + + -- J.H.M. Dassen (Ray) Sun, 4 May 2003 12:44:00 +0200 + +debootstrap (0.1.17.24) unstable; urgency=medium + + * [sid] Updates for new whiptail: + * Replaced libnewt0 by libnewt0.51. + * Added slang1a-utf8. + + -- J.H.M. Dassen (Ray) Tue, 29 Apr 2003 19:04:51 +0200 + +debootstrap (0.1.17.23) unstable; urgency=medium + + * [sid] + * Added sysv-rc for /usr/sbin/update-rc.d . + * Added initscripts to satisfy sysvinit's predependency. + * For exim, dropped libsasl7 in favour of libsasl2. + * Added libssl0.9.7 for libsasl2. + + -- J.H.M. Dassen (Ray) Tue, 22 Apr 2003 06:56:25 +0200 + +debootstrap (0.1.17.22) unstable; urgency=low + + * [sid] added libtext-iconv-perl which is needed to display + localized po-debconf templates actually localized. + This needs a second step later for sarge but that only is possible + after libtext-iconv-perl 1.2-2 went into sarge. + + -- Rene Engelhard Fri, 18 Apr 2003 16:25:17 +0200 + +debootstrap (0.1.17.21) unstable; urgency=medium + + * [sarge, sid] Added gcc-3.3-base (as it is needed for current libstdc++5). + + -- J.H.M. Dassen (Ray) Fri, 18 Apr 2003 08:11:55 +0200 + +debootstrap (0.1.17.20) unstable; urgency=medium + + * [woody, sarge, sid] Add devfsd on s390 as that architecture uses devfs by + default. (Closes: #180252) + * [sarge] Removed the dummy fileutils package. + + -- J.H.M. Dassen (Ray) Mon, 7 Apr 2003 19:59:42 +0200 + +debootstrap (0.1.17.19) unstable; urgency=medium + + * [sid] Added libblkid1 (for e2fsprogs). + + -- J.H.M. Dassen (Ray) Sun, 6 Apr 2003 21:43:29 +0200 + +debootstrap (0.1.17.18) unstable; urgency=medium + + * [sarge] Added libgcc1, libstdc++5, gcc-3.2-base; dropped aptitude, + libsigc++0 . + * Debootstrap has depended on binutils since 0.1.17.3. (Closes: #184304) + + -- J.H.M. Dassen (Ray) Wed, 19 Mar 2003 06:55:56 +0100 + +debootstrap (0.1.17.17) unstable; urgency=medium + + * NMU + * Really drop aptitude from the sid script, not just libsigc++0. + + -- J.H.M. Dassen (Ray) Tue, 4 Feb 2003 06:49:36 +0100 + +debootstrap (0.1.17.16) unstable; urgency=medium + + * NMU + * Drop aptitude from the sid script (base-config 1.51 dropped its dependency + on it) and libsigc++0 (which was only needed for aptitude). This makes + "pbuilder create --distribution sid" work again. (Closes: #177221, #177998). + + -- J.H.M. Dassen (Ray) Sun, 2 Feb 2003 20:41:35 +0100 + +debootstrap (0.1.17.15) unstable; urgency=low + + * NMU + * For gcc-transition, libgcc1 and libstdc++5 and gcc-3.2-base + required by groff-base, and potentially other packages compiled with + gcc-3.2. + + -- Junichi Uekawa Mon, 13 Jan 2003 15:39:55 +0900 + +debootstrap (0.1.17.14) unstable; urgency=low + + * NMU + * Remove debootstrap-udeb's dependency on retriever. + + -- Tollef Fog Heen Sat, 7 Dec 2002 14:53:52 +0100 + +debootstrap (0.1.17.13) unstable; urgency=low + + * NMU + * sarge: Removed shellutils, textutils and added coreutils instead. + Verified that the result works for "pbuilder create --distribution sarge" + (Closes: #163789) + Fileutils is still in there for now, due to sarge's debconf versioned + dependency on it. + + -- J.H.M. Dassen (Ray) Tue, 8 Oct 2002 23:17:47 +0200 + +debootstrap (0.1.17.12) unstable; urgency=low + + * NMU + * Fix shell variable quoting problem, to change $10 -> ${10} + (closes: #161468) + + -- Junichi Uekawa Sat, 21 Sep 2002 13:39:47 +0900 + +debootstrap (0.1.17.11) unstable; urgency=low + + * NMU + * sarge: added libdb1-compat. + + -- J.H.M. Dassen (Ray) Sat, 21 Sep 2002 00:37:36 +0200 + +debootstrap (0.1.17.10) unstable; urgency=low + + * NMU + * sid: Removed shellutils, fileutils, and added coreutils for required + target (closes: #161332) + * sid: change libperl5.6 to libperl5.8 (closes: #158606) + + -- Junichi Uekawa Wed, 18 Sep 2002 21:41:36 +0900 + +debootstrap (0.1.17.9) unstable; urgency=low + + * NMU + * Added "libdb1-compat" to sid and verified that the resulting package is + usable for "pbuilder create --distribution sid". + + -- J.H.M. Dassen (Ray) Sat, 14 Sep 2002 15:09:10 +0200 + +debootstrap (0.1.17.8) unstable; urgency=low + + * NMU + * The "it didn't change the way the installer worked" release. + * Makefile: create $(DESTDIR)/usr/share/man/man8 before attempting to + install a file to it (Closes: #139543) + * functions: fix race condition in smallyes() implementation; thanks to Matt + Zimmerman for the analysis. "Sometimes, dpkg finishes executing before + smallyes runs, and it loops forever while echo fails repeatedly due to the + broken pipe." To fix this race, we simply swap the loop condition and + body, so that if the echo fails, smallyes() exits cleanly. I further + changed "true" to ":" to save the expense of an extra process for shells + where "true" is not a built-in. + (Closes: #139529) + + -- Branden Robinson Thu, 29 Aug 2002 12:50:08 -0500 + +debootstrap (0.1.17.7) unstable; urgency=low + + * NMU + * Forked "sid" target from "sarge" target, changed "libcap0" to the now + current "libpcap0.7" and verified that the result works with pbuilder. + (Closes: #156574) + + -- J.H.M. Dassen (Ray) Wed, 21 Aug 2002 11:01:52 +0200 + +debootstrap (0.1.17.6) unstable; urgency=low + + * NMU + * add dselect to required (I found out that it is actually required + for pbuilder create to work) (closes: #154527) + * change DEBIAN_FRONTEND=Noninteractive to "noninteractive" (closes: #154794) + * add sh* patch from Yaegashi (closes: #155142) + + -- Junichi Uekawa Thu, 8 Aug 2002 19:23:04 +0900 + +debootstrap (0.1.17.5) unstable; urgency=low + + * NMU + * mistake in the last upload, sorry aj. + sid points to sarge, not woody. (closes: #149971) + + -- Junichi Uekawa Sat, 27 Jul 2002 17:22:05 +0900 + +debootstrap (0.1.17.4) unstable; urgency=low + + * NMU + * add "sarge" target (closes: #153957) + + -- Junichi Uekawa Tue, 23 Jul 2002 18:03:01 +0900 + +debootstrap (0.1.17.3) unstable; urgency=low + + * NMU + * Depend on binutils (closes: #138489) + * Sleep is optional (closes: #150468) + * POSIXify a bit more (closes: #150487) + * Add support for --components (closes: #116801) + + -- Tollef Fog Heen Thu, 20 Jun 2002 00:13:06 +0200 + +debootstrap (0.1.17.2) unstable; urgency=low + + * NMU + * Make sid script not a symlink from woody script + * add aptitude and libsigc++0 to base for sid. (closes: #149971) + + -- Junichi Uekawa Sat, 15 Jun 2002 12:46:11 +0900 + +debootstrap (0.1.17.1) unstable; urgency=low + + * NMU + * Add udeb support (closes: #143874) + + -- Tollef Fog Heen Tue, 28 May 2002 14:15:41 +0200 + +debootstrap (0.1.17) unstable; urgency=high + + * Includes changes from NMUs. Thanks to Stefan Gybas and Eduard Bloch. + (Closes: Bug#130764, Bug#135676, Bug#134306, Bug#133882, Bug#131768, + Bug#117980, Bug#133298, Bug#130668, Bug#111175, Bug#131147, Bug#95143, + Bug#130482) + + * Don't use PIPESTATUS to work out if wget succeeded, since that's a + bashism and we're seriously not allowed bashisms. Duh. This should + help with all those "Malformed release" problems. Thanks to Phil + Blundell and Chris Tillman for spotting this. (Closes: Bug#136729) + + * Apply patch from Matt Zimmerman to get rid of some irritating warnings + that can show up sometimes due to sed getting it's output stream closed + on it. (Closes: Bug#131478) + + * Don't use "export foo=bar" on a single line since it's a bashism. + (Closes: Bug#138187) + + * Made the "smallyes" usage independent of --boot-floppies. Too much + code duplication otherwise. + + * Install ipchains on arches that have 2.2.x kernels by default, and + iptables on arches that have 2.4.x kernels by default. Some arches + have both. (Closes: Bug#134478) + + * Don't rm malformed Release files, rename them to something obvious + instead so people can have a hope at seeing what's going on. (Closes: + Bug#131756) + + * Error out on missing entries in Release files. (Closes: Bug#136886) + + * Fix basedeb creation to not bother building devices tarball. (Closes: + Bug#137243) + + * Workaround for ldconfig no longer needed, so removed. (Closes: Bug#135819) + * Workaround for /dev/initctl was never needed and stupid, so removed. + + * Make sure devices.tar.gz is gzip -9'ed. (Closes: Bug#136687) + + * Use any "main" components found in Release file, eg "main", + "non-US/main", "local/main". (Closes: Bug#116801) + + * Add parted to base for ia64. (Closes: Bug#138246) + + * Moved the "successful!" message and sleep hack for boot-floppies from + the woody script to the debootstrap script itself. + + -- Anthony Towns Thu, 14 Mar 2002 18:28:24 +1000 + +debootstrap (0.1.16.4) unstable; urgency=low + + * NMU, needed for boot-floppies 3.0.20 + * Added cciss and ataraid device files, closes: #135675 + * Applied the patch from Matt Zimmermann to fix --include, closes: #134306 + * Mail suppression fixed in previous release, closes: #133882 + + -- Eduard Bloch Sun, 3 Mar 2002 12:21:19 +0100 + +debootstrap (0.1.16.3) unstable; urgency=low + + * non-maintainer-upload + * require newer makedev, fixes build problems on m86k and arm + * unsets $TMP, $TEMP and $TMPDIR in the beginning, closes: #131768, #117980 + * added gcc-2.96-base to ia64's required packages list, closes: #133298 + + -- Eduard Bloch Tue, 12 Feb 2002 19:30:47 +0100 + +debootstrap (0.1.16.2) unstable; urgency=low + + * non-maintainer-upload + * added modification suggested by Branden Robinson and Matt Kraai terminate + cat (now tail) better, closes: #130668 + * provides options to install additional packages, or exclude some from the + list. May be needed in boot-floppies soon. Closes: #111175, #131147 + * --verbose option, closes: #95143 + * added additional devices to the device list, especially input and usb + needed for modern device drivers (Joysticks, USB, Scanners) + * added pppoeconf to the packages list, better choice for DSL users + * forced remove of dev/initctl, prevents breaking on re-installation + + -- Eduard Bloch Mon, 28 Jan 2002 19:14:41 +0100 + +debootstrap (0.1.16.1) unstable; urgency=high + + * non-maintainer upload for boot-floppies 3.0.19 + * Fixed list of base and required packages for s390 + * setup_devices(): don't fail if devices.tar.gz is not present and we + are using devfs + * disable handling of /dev/initctl for boot-floppies, closes: #130482 + + -- Stefan Gybas Thu, 24 Jan 2002 15:17:42 +0100 + +debootstrap (0.1.16) unstable; urgency=low + + * Include NMUs 0.1.15.1 - .9, thanks to Adam di Carlo, Ethan Benson and + Bdale Garbee. (Closes: Bug#113265, Bug#119314, Bug#119251) + * Many bugs were fixed in the NMUs. Closes them properly. (Closes: + Bug#89673, Bug#97174, Bug#99229, Bug#105980, Bug#106062, Bug#106102, + Bug#106106, Bug#106134, Bug#106711, Bug#106877, Bug#107262, + Bug#107404, Bug#107447, Bug#109670, Bug#110312, Bug#111001, + Bug#111065, Bug#112778, Bug#112795, Bug#112842, Bug#113444, + Bug#114056, Bug#114653, Bug#115467, Bug#115481, Bug#115557, + Bug#115581, Bug#115699, Bug#116061, Bug#116424, Bug#119769, + Bug#119947, Bug#121724, Bug#123958, Bug#125954, Bug#126018, + Bug#126630, Bug#126799) + + * Informative error for people who type `--boot-floppies' when running + by hand. (Closes: Bug#107548) + * Create dev/initctl in target, and setup a cat process to dump anything + sent to it to /dev/null so that if init is run in the chroot, + it doesn't try doing anything too clever to talk to the real + init. (Closes: Bug#120597) + * Create awk symlink since base-files insists on having it available. + (Closes: Bug#127934) + + * Use DEBOOTSTRAP_DIR to work out where /usr/lib/debootstrap is. + * So, in theory, to create basedeb tarballs, you should be able to unpack + the source and say: + . + fakeroot debian/rules binary-basedebs SUITE=woody VERSION=3.0 \ + MIRROR="http://ftp.debian.org/debian" ARCHES="i386 powerpc" + (Closes: Bug#127546) + + -- Anthony Towns Sun, 20 Jan 2002 21:04:37 +1000 + +debootstrap (0.1.15.9) unstable; urgency=high + + * non-maintainer upload + * debian/rules: new 'basedebs' target that makes basedebs.tgz and 1.44 + split images for base per arch + * functions: better return value handling during wget (wgetprogress) + * repeat() had a useless eval, removed, which simplifies some silly + quoting + * incorrect error message in in_target_msg(), closes: #119769 + * debian/changelog: remove obsolete "local variables" + * additional progress message when validating the release file after + download + * when the downloaded release file is invalid, make sure to delete it + closes: #119947 + * debian/rules: minor fixes and cosmetics + * upgrade wget from Recommends to Depends, closes: #126799 + * depend on binutils, for 'ar', closes: #123958 + + -- Adam Di Carlo Fri, 4 Jan 2002 20:01:58 -0500 + +debootstrap (0.1.15.8) unstable; urgency=high + + * non-maintainer upload + * Fix progress bar hooks to enable proper progress on basedebs.tgz + installation as well as actual base installation and extraction. + * trap signals so cleanup is still performed. + * When in --boot-floppies mode echo a Success info message to stdout, so + it will show up on /dev/tty4, this is so users watching tty4 stop + being confused when things just stop at completion. + * Replace $TARGET/sbin/start-stop-daemon with a shell script instead of + /bin/true, this shell script announces that its a fake noop version so + users will know whats wrong if debootstrap aborts before completion. + + -- Ethan Benson Sat, 3 Nov 2001 23:14:08 -0900 + +debootstrap (0.1.15.7) unstable; urgency=high + + * non-maintainer upload + * when reporting errors in 'in_target', don't chop down to the first + 50 characters + * woody: when in boot-floppies mode, provide more user-friendly warning + messages, using new 'in_target_msg' function + * woody: more info messages for the core/required/base package + installation part + * instead of 'ln -s' we should be using 'ln -sf'; this would prevent + running debootstrap twice in the same target dir; closes: #111065 + * before mounting proc, umount it just in case; normally this shouldn't + be needed if on_exit is working all the time, but I find without this, + sometimes problems are caused + * woody/i386 needs psmisc for pcmcia-cs (critical bug!) + * --download-only mode can be run as non-root; closes: #116424 + * tested some problems which I couldn't reproduce + closes: #115699 + + -- Adam Di Carlo Wed, 24 Oct 2001 16:05:39 -0400 + +debootstrap (0.1.15.6) unstable; urgency=medium + + * non-maintainer upload + * smaller and wiser version of smallyes(), thanks to Herbert Xu + * woody base includes pcmcia-cs for i386 and powerpc (closes: #114653) + * wget progress bar support (closes: #116061) + + -- Adam Di Carlo Thu, 18 Oct 2001 15:14:02 -0400 + +debootstrap (0.1.15.5) unstable; urgency=high + + * From Ethan Benson: + * pipe yes output into dpkg runs inside install_debs() this way on_exit + works in --boot-floppies mode. (Closes: #112842, #115481) + * Add libpcap0 to base, ppp depends on it now. (Closes: #114056) + + * From Adam Di Carlo: + * Potato installation on non-i386 was broken, need libc6 + (closes: #112778); however, there are other ways the Potato base + install doesn't represent quite what Potato boot-floppies would + consider base + * apply patch from Tommi Virtanen which improves the 'smallyes' + function; apparently this fixes a console-tools postinst loop, + although I haven't seen that (closes: #115581) + * get rid of some line continuators in potato and woody scripts, they + were obscuring some problems + + -- Adam Di Carlo Mon, 15 Oct 2001 01:56:16 -0400 + +debootstrap (0.1.15.4) unstable; urgency=high + + * more fixed for the benefits of boot-floppies + * add telnetd on s390; yes, it's gross, but it's needed for + installation, to connect from the line mode console + closes: #112795 + + -- Adam Di Carlo Sun, 23 Sep 2001 16:11:03 -0400 + +debootstrap (0.1.15.3) unstable; urgency=high + + * Fix deficient command line option parsing, optional arguments no + longer have to be declared in a specific order, for example before you + could not put --arch before --download-only, now you can. + * Add --help option and useful help output. + * Stop using dirname, basename, and yes, they are being removed from + busybox. + * Fix many many quoting bugs. + * Fix debootstrap man page (Closes: #107404, #109670) + * Add ftp support (Closes: #110312) + * Don't waste time downloading useless non-free/contrib (Closes: #89673) + * Path cleanup (Closes: #97174) + * Add pppconfig to woody base (Closes: #111001) + * Remove syslinux from base (Closes: #107447) + * Eliminate useless warning about creating exim.conf (Closes: #99229) + * Don't use "here documents" (they create tmp files in /tmp which could + be very well be full on boot-floppies). + * Don't use echo -n it is not portable. + * Set umask to 022. + * All patches from Ethan Benson, I am just the builder! + These have been tested with boot-floppies and work properly. + + -- Adam Di Carlo Sat, 22 Sep 2001 12:30:02 -0400 + +debootstrap (0.1.15.2) unstable; urgency=low + + * quoting required in one place for the new ash (Closes: Bug#106062) + * s390 support (Closes: Bug#107262) + * remove some packages from Woody's base that aren't needed: + - update (not needed with modern kernels, Closes: Bug#106877) + - syslinux (Closes: Bug#107477) + - ldso (should be pulled in by libc6, Closes: Bug#106102) + * kinks in mipsel base worked themselves out (Closes: Bug#106711) + + -- Adam Di Carlo Wed, 8 Aug 2001 12:04:40 -0400 + +debootstrap (0.1.15.1) unstable; urgency=low + + * add efibootmgr on ia64, as per bug 105980. + + -- Bdale Garbee Fri, 3 Aug 2001 14:13:23 -0600 + +debootstrap (0.1.15) unstable; urgency=low + + * Do progress indications (by bytes) for Packages downloads and .deb + downloads. (Closes: Bug#101886) + * Don't use seq. Silly busybox. + * Add pppoe to base. (Closes: Bug#102378) + * No point keeping around the "sid.is-broken" file. + + -- Anthony Towns Wed, 27 Jun 2001 21:29:29 +1000 + +debootstrap (0.1.14) unstable; urgency=low + + * Make in_target_nofail kill stderr. No more "/dev/pts: not mounted" error. + Yay. :) + + * Refactor woody, potato and slink scripts; do away with + woody.debs. Change the way the scripts work. (Now they define + functions which debootstrap calls. Much nicer) + * Support --download-only option. + * Support resuming downloads of Release and Packages files, even gzipped + ones. + * Support null: (Packages files assumed to be named for a debootstrap.invalid + host) + * Always use the deboostrap.invalid name, and use that in + /etc/apt/sources.list. Remove /etc/apt/sources.list after the base + system is build. + * All this should be enough to support basedeb.tgz installs on + debootstrap's behalf. Some more stuff would be useful, but isn't + immediately necessary. (Closes: Bug#102217) + + * Add ia64 support and fix libc6 == libc6.1 problem. (Closes: Bug#101829) + + * Be a little more careful with permissions on devs tarball. Hopefully. + (Closes: Bug#102308) + + * Don't worry if md5sum from stdin adds a " -" after the md5sum. Should + make debootstrap more usable on non-Debian Linuxes. + + -- Anthony Towns Mon, 25 Jun 2001 18:38:35 +1000 + +debootstrap (0.1.13) unstable; urgency=low + + * Add symlink for sid.debs. + * Fix the special casing for hppa. (Closes: Bug#101604) + * Remove groff from base. (Closes: Bug#101173) + * Retry partially successful downloads a couple of times. + (Closes: Bug#101476) + * Minor wording changes wrt downloading Release file (Closes: Bug#101705) + + -- Anthony Towns Thu, 21 Jun 2001 12:08:10 +1000 + +debootstrap (0.1.12) unstable; urgency=high + + * Split determination of base into a separate script to enable further + innovation! Come on, tell me that doesn't excite you! + + * Add groff-base to base. (Closes: Bug#100112, Bug#100123) + * Remove libstdc++2.10 and some other hopefully unnecessary debs + (Closes: Bug#99708) + + * Remove lilo.conf special casing. Change some warnings to info messages. + + -- Anthony Towns Sun, 10 Jun 2001 01:22:12 +1000 + +debootstrap (0.1.11) unstable; urgency=low + + * Add dhcp-client to base. (Closes: Bug#100083) + + -- Anthony Towns Sat, 9 Jun 2001 00:11:26 +1000 + +debootstrap (0.1.10) unstable; urgency=low + + * Don't abort build on devfs systems: the makedev we build-dep on should + be recent enough. (Closes: Bug#97713) + * Check for malformed release files. Thanks to Martin Michlmayr for the + patch. (Closes: Bug#97707) + * Use --force-confold when installing base. That is: if you want the + conffile from the package to be there at the end, don't create a + file in the first place. I'm not convinced this is right. + (Closes: Bug#99025) + + -- Anthony Towns Mon, 28 May 2001 14:43:07 +1000 + +debootstrap (0.1.9) unstable; urgency=low + + * Abort build on devfs systems (MAKEDEV fails for no good reason) + (Closes: Bug#97713) + + * Add support for mips and mipsel (Closes: Bug#97711) + * Add some support for hppa (install palo in base) + + * Don't install ldso (Closes: Bug#97708) + * Don't install libopenldap1 or libopenldap-runtime (replaced by libldap2) + (Closes: Bug#98050) + * Do install libdb3 and libcap1. + * Install klogd too. (But only as part of base. Move sysklogd to base too) + + * Setup a dummy lilo.conf on i386 only. (Closes: Bug#97710, Bug#98052) + + * Trim a trailing / for target and url. + + -- Anthony Towns Sun, 20 May 2001 13:33:34 +1000 + +debootstrap (0.1.8) unstable; urgency=low + + * Add adduser and base-config into base. base-config unfortunately depends + on perl instead of perl-base. (Closes: Bug#96439) + * Force LANG=C. Need to work out how i18n should be handled. + * Kludge potato install so it's noninteractive. Thanks to Colin Watson + for the patch. (Closes: Bug#94441) + * Get rid of dh_testversion. + * Make a sid script (just a symlink to the woody script). + + -- Anthony Towns Wed, 9 May 2001 20:33:00 +1000 + +debootstrap (0.1.7) unstable; urgency=low + + * Don't worry if umounting /dev/pts fails. + * Add debootstrap(8) manpage, thanks to Matt Kraai. (Closes: Bug#86238) + * Add a blank line to the end of the faked /var/lib/dpkg/status. Spotted + by Richard Hirst. + * Added console-tools and console-data into the base system. + * Move /etc/exim.conf to /etc/exim/exim.conf so that sendmail doesn't + give errors, even if debconf tries to use it before exim is + configured. Gack. + * Add fdutils back into base. + + -- Anthony Towns Mon, 30 Apr 2001 15:49:27 +1000 + +debootstrap (0.1.6) unstable; urgency=low + + * Only create stuff in /etc if it hasn't already been created. + + -- Anthony Towns Mon, 23 Apr 2001 18:02:55 +1000 + +debootstrap (0.1.5) unstable; urgency=low + + * Use "head -n X" instead of "head -X" to work with busybox. + (Closes: Bug#94575) + * Use s///I instead of s///i for case insensitivity, again for busybox. + (Closes: Bug#94579) + * Fixed typo that would have stopped debootstrap from falling back to an + uncompressed Packages file. + * Added libsasl7 and libldap2 to woody base, since woody exim now depends + on them. + + -- Anthony Towns Sun, 22 Apr 2001 01:47:00 +1000 + +debootstrap (0.1.4) unstable; urgency=low + + * If we've got a Release file, check that the Packages files we download + have the right md5sums. + * Build-Depend on new makedev, and don't hax0r powerpc devices as much. + (Closes: Bug#93836) + * Hopefully support arm chroots. (Closes: Bug#92592) Declare it to be + Arch: any, and see what dies. There's a chance that nothing will. Not + a *big* chance, but a chance. + * Fiddled with the base system some more. Added apt-utils so + preconfiguration will work. + * Added permission to NMU to the README.Debian. + * Mention file:/ URLs in README.Debian. (Closes: Bug#87099) + * Add a --boot-floppies option that changes the way the I/O happens, in + a way that's hopefully useful for boot-floppies. See README.Debian for + details. + * Also added a bit more output. + + -- Anthony Towns Mon, 26 Mar 2001 22:30:12 +1000 + +debootstrap (0.1.3) unstable; urgency=high + + * Switch from debconf-tiny to debconf, since that's what's now in + woody. (Using debconf-tiny probably makes the package unusable, hence + the urgency) Fixup perl, lilo and console-apt to cope with changes in + the base system in woody. Added ae, left nano and nvi. + * Add support for m68k, sparc and powerpc, based on Christian Steigies + patches and Adam Di Carlo's NMU (Closes: Bug#89883, Bug#91221) + + -- Anthony Towns Sun, 25 Mar 2001 14:29:02 +1000 + +debootstrap (0.1.2) unstable; urgency=low + + * Add support for slink. + * Fix support for woody (no lilo, console-*, different perl) + * Re-download Packages files every time (Closes: Bug#88438) + (Should this be changed to re-download things where the md5 doesn't match?) + + -- Anthony Towns Sun, 4 Mar 2001 19:42:29 +1000 + +debootstrap (0.1.1) unstable; urgency=low + + * Initial Release. (Closes: Bug#82245) + + * Called it debootstrap instead of debchroot, because it's more about + bootstrapping a Debian environment, whether that will end up being + in a chroot, or as a standalone system. Blame Adam di Carlo. :) + + -- Anthony Towns Tue, 30 Jan 2001 10:54:45 +1000 diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/compat b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/compat new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/compat @@ -0,0 +1 @@ +9 diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/control b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/control new file mode 100644 index 00000000..6925a63c --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/control @@ -0,0 +1,26 @@ +Source: debootstrap +Section: admin +Priority: extra +Maintainer: Franco (nextime) Lanza +Uploaders: Franco (nextime) Lanza , Daniel Reurich +Build-Depends: debhelper (>= 9), makedev (>= 2.3.1-69) [linux-any], git +Standards-Version: 3.9.8 +Vcs-Browser: https://git.devuan.org/devuan-packages/debootstrap +Vcs-Git: https://git.devuan.org/devuan-packages/debootstrap.git + +Package: debootstrap +Architecture: all +Depends: ${misc:Depends}, wget +Recommends: gnupg, ${keyring}, devuan-keyring +Description: Bootstrap a basic Devuan system + debootstrap is used to create a Devuan base system from scratch, + without requiring the availability of dpkg or apt. It does this by + downloading .deb files from a mirror site, and carefully unpacking them + into a directory which can eventually be chrooted into. + +Package: debootstrap-udeb +Section: debian-installer +Package-Type: udeb +Architecture: all +Depends: ${misc:Depends}, mounted-partitions +Description: Bootstrap the Devuan system diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/copyright b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/copyright new file mode 100644 index 00000000..b34963b1 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/copyright @@ -0,0 +1,30 @@ +This package was debianized by Anthony Towns on +Tue, 30 Jan 2001 10:54:45 +1000. + +It was written from scratch for Debian by Anthony Towns +based loosely on the code for constructing base tarballs as part of the +boot-floppies package. + +Copyright: + +Copyright (c) 2001-2005 Anthony Towns + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/debootstrap.docs b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/debootstrap.docs new file mode 100644 index 00000000..e845566c --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/debootstrap.docs @@ -0,0 +1 @@ +README diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/debootstrap.manpages b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/debootstrap.manpages new file mode 100644 index 00000000..d6a5e4ac --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/debootstrap.manpages @@ -0,0 +1 @@ +debootstrap.8 diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/gbp.conf b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/gbp.conf new file mode 100644 index 00000000..ac8e799c --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/gbp.conf @@ -0,0 +1,9 @@ +[DEFAULT] +compression = xz +pristine-tar = false +upstream-tag = devuan/1.0.85 + +[git-buildpackage] +upstream-tree = tag +tarball-dir = ../tarballs/ +export-dir = ../build-area/ diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/rules b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/rules new file mode 100755 index 00000000..23bc4a61 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/rules @@ -0,0 +1,47 @@ +#! /usr/bin/make -f + +ifeq (0,$(shell dpkg-vendor --derives-from Ubuntu; echo $$?)) + KEYRING := ubuntu-keyring +else ifeq (0,$(shell dpkg-vendor --derives-from Devuan; echo $$?)) + KEYRING := devuan-keyring +else ifeq (0,$(shell dpkg-vendor --derives-from Tanglu; echo $$?)) + KEYRING := tanglu-archive-keyring +else + KEYRING := debian-archive-keyring +endif + +%: + dh $@ + +# need to be root to make devices, so build is done in install target +override_dh_auto_build: + +override_dh_auto_install: + dh_auto_build + + $(MAKE) install DESTDIR=$(CURDIR)/debian/debootstrap + $(MAKE) install DESTDIR=$(CURDIR)/debian/debootstrap-udeb + + # remove scripts not needed by d-i + -rm -f debian/debootstrap-udeb/usr/share/debootstrap/scripts/potato \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/woody \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/sarge \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/warty \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/hoary \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/breezy \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/dapper \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/edgy \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/feisty \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/*.buildd \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/*.fakechroot \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/stable \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/testing \ + debian/debootstrap-udeb/usr/share/debootstrap/scripts/unstable + +override_dh_gencontrol: + dh_gencontrol -- -Vkeyring=$(KEYRING) + +# Specify gzip to mitigate #770217: +override_dh_builddeb: + dh_builddeb -pdebootstrap -- -Zgzip + dh_builddeb -pdebootstrap-udeb -- -Zxz diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debian/source/format b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/source/format new file mode 100644 index 00000000..af745b31 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debian/source/format @@ -0,0 +1 @@ +3.0 (git) diff --git a/cdist/preos/debootstrap/files/devuan-debootstrap/debootstrap b/cdist/preos/debootstrap/files/devuan-debootstrap/debootstrap new file mode 100755 index 00000000..71c70540 --- /dev/null +++ b/cdist/preos/debootstrap/files/devuan-debootstrap/debootstrap @@ -0,0 +1,703 @@ +#!/bin/sh +set -e + +VERSION='@VERSION@' + +unset TMP TEMP TMPDIR || true + +# might not be exported if we're running from init=/bin/sh or similar +export PATH + +########################################################################### + +if [ -z "$DEBOOTSTRAP_DIR" ]; then + if [ -x /debootstrap/debootstrap ]; then + DEBOOTSTRAP_DIR=/debootstrap + else + DEBOOTSTRAP_DIR=/usr/share/debootstrap + fi +fi + +. $DEBOOTSTRAP_DIR/functions +exec 4>&1 + +LANG=C +USE_COMPONENTS=main +KEYRING="" +DISABLE_KEYRING="" +FORCE_KEYRING="" +VARIANT="" +MERGED_USR="no" +ARCH="" +HOST_ARCH="" +HOST_OS="" +KEEP_DEBOOTSTRAP_DIR="" +USE_DEBIANINSTALLER_INTERACTION="" +SECOND_STAGE_ONLY="" +PRINT_DEBS="" +CHROOTDIR="" +MAKE_TARBALL="" +EXTRACTOR_OVERRIDE="" +UNPACK_TARBALL="" +ADDITIONAL="" +EXCLUDE="" +VERBOSE="" +CERTIFICATE="" +CHECKCERTIF="" +PRIVATEKEY="" + + +DEF_MIRROR="http://packages.devuan.org/merged" +DEF_HTTPS_MIRROR="https://packages.devuan.org/merged" + +export LANG USE_COMPONENTS EXCLUDE +umask 022 + +########################################################################### + +## phases: +## finddebs dldebs printdebs first_stage second_stage + +RESOLVE_DEPS=true + +WHAT_TO_DO="finddebs dldebs first_stage second_stage" +am_doing_phase () { + # usage: if am_doing_phase finddebs; then ...; fi + local x; + for x in "$@"; do + if echo " $WHAT_TO_DO " | grep -q " $x "; then return 0; fi + done + return 1 +} + +########################################################################### + +usage_err() +{ + info USAGE1 "usage: [OPTION]... [ [

ZT+0S6Vb=P!N9S$qx~t|zN& zJ>nKfv+L(o9tLJTC}g}-r8W~*Mh2cUWL6^z$}#UY+E)aWwfZ}j8(dikBZv828(Mya ztXHr1tZl3=C@6(=`Np9772-8oLgZ#e(rheB zbSc`voD^FtWYfMvrbp`7=UwjyDfjcRFwlV_M0H$;g9g=~!iAy|_)26v{f!5mjGNU` zl6R4A86iz&ENpmC?P6U<^+Ve)cSB-yWKpXyX}PQ0@!tt{u;-Rv_^3z^AqS2*Pd-{F z|LsE#7mn#y3XSXaoHruQ9EXqIaWqwa_L*Z``J8t|l-Ddu)2ng0DwvbhB(I+(S|ekO znDZFCi?`1-<2PP1FyLOitn{BD@yj!({uCuK09zGvupv;p@6>I#dYt?4488#(+ihX- zwr+Azitq#at}_1M+k})4I+BP!XQdW-YpWPnw=#V8zHX&<#e0^WPu`l!EBM}}*W`4q z`ueU{B~xObMRVPyC}1yp-thLyEdN)LxKwX(Li34Ar|~sM@AIL-lsU@n)ocSos8k(9gCh@rv$nZ1rLA$;P7O=AMhska1*=g>y^`hZHO5aXE-GiimwKT5 zn-wl!bJ-5YD4notZRGElwOh8~iOyS$=X^?o=ZVmymDvponIPdSMN(&_?YY=A@i?w) z_3RfD6P|q#axeK;P)qGLr7Bsm5X+d4_%Rp#`#{V~M^Vu>b9);0_m-V*8+TTtc{p39 z9;o+(-bIB0%$?e{%YgGzL=ec5b)H7X8q^(T!2!u zl}+99_^n~lH;&!eN6vk6>QQ%doP_Hwv9%jDmQx1bM7y$14e6WkfaTD|-swPzG}T*t zW0YbULqn6uzF)R3ad6H4YxOG2NO^&x_epn+!(`bT!o;T(#8!}ze5f$sJ-g}@?*Qe} z50KiNxCcXHn5>II#9?gkaaP>&y_(i`eZaD$Uy`())NK*wQ#OMPYHK6Zy?P|06-l6g zg0vQ#=wXzN%3CT+^poTydCp14=xoe}ckm5L?aBnfE-1;b>H9dwLV%d^9<%2?JXb%l zXU<=KFRP*do{kPRz**g)v$IC!246DbEbGNW>@97Pxlh5)8&a1zWbLSb7u$dd(Q}%LE{mXj9AlC8nI%~?BR>)O;Bkl^IY`1Elb!{BD8V-)uG56ptX?-6b z~JBDrzbuC`kyx83X|MGFyyb)tdNT4s2FL+U4D2okIO&kj^>(>zUQA-7 zF($hM0YL||xU3U~Lu5rWmz!9Ng?T|qAF<|EZ33pnqDjOIw()mWQQ<|PBDZ3)(ftu( zjt)0n3_j@tI~qiW4P@5+ny3Q3wGdqg+p7>dxS&*KaaGr|f_(3&u8AslCq@3v{mtTX zhZBU?-o!5X;imcL=WTJ&H{tbP1Q^GZp$(yliBY=;_Bra5Wvf%)yBGO;ZG4yI5L$-4 zkqvkw`a;2AGMBlwXGLB5>Ok$F=&H7cf@bNS(GSBJpETb6&DZcqAD;n}_|nhZv6vi9 z2_YU|>f|d1Gruh)+&Gv5yIwny{|yfBg+XPYSWVl?qs;+n!$cY(_dF}8_KrrS#nBn> z*ZcxT`21N<#e0|Z6@3=)@wMBD4pQiqS5mH-bn*K#v$9~T>BPoGvvaJEw}(fEIEDU% z>y3p>FP`}rDvO+d(Wb~`!N;a7h+!J6r_JtzQSw)d{H1vrwTDhDfdxQH#3DFd^2QlV=}19v45?f}?WPrJpq2exb8p7JeF<@9Ngv6K-wT)lmb@$Yp!M`0h!gCVMd5Bu5Bw(X5A)%XrSJ+$)J>BlP36RYg^PAhCA zIx){=$o5zXsB3}x@Yfr*==Im1T?8!FADfJ4Po!IDd<7o|aI{QBe|sctH&pV9f6k~p z@ya|*P|3fSedY!HLsp{zyJos9e^$S+@viN$yErl7Ev6F(n+dh@$6eM#;yffOn+-7s zSztL(1j6^aauFpyD?onG@{iLcR<|fa=*nZ}`%K?P%swQ0Ca-=HJU|I4PfT_*PQ!8O zi3NkQ(5KU#{%|j-?~$GDs;yt6;_@k4My6Ea*%q=%n9Hz1MW~=jBSdBS)9~lHhn3*C z#orBm8fe#}XNcYSTk%O+qS#6=fN9hk91>|Y1SZ~=bp#%OeUi&ENxdx~t!F&2MCnA9 zTkQwgb;n^UU^lRtQ0ee!H@iu~J!@JzBHqpdxHVa6kYLdaO;9j=Xg3!JFRA$ayF3Q& zoR>#<{5|;vJ*CGmQ#J$!O0na?JhCf}Jzvijk}izt=^`jA+H+3Y>eeoOi=u{o5k+>> zW#-NOH%E8wOOvzy^A9E;a(iM^frzyK@)_U|(C}Z-o+`fI_X)|O|!j}X` zr}R6?cJq(0GH$&56*_vxeWyefDSvj@x^aUp$gQkns)@;N$Ng4TxChczl&jp@9Vewl zk^B2Q4XxCS&HBe>-25O4uv*#G>%u7F32YhV?9+%`y#)3|%l|wKrc5eli#9L(;Pxtt zL4_N0n3gdHKqV_|-H+R^do6ptCeJGkAFU6%`6VMMgTvv8dnP^`8_PN0ZOWtoZ~!$s(Vm5a=h?;H z_wgxgb&C6?`{wyY@@`S@&N`Z(P9u4Qz>#6Q?NNqf?7iNG`eP9wo0)7X(ECI(m-ZrY z52J2xo|?e7BtG;(ATQ-rnVbRK<|VFA2s(BaM0T5i<r(Izso0)olTGX}*}i={5KsH^1VZUw{Zjq1LN*c? zT5U7eZRUf`aQKLgGF0;fOJkIg0<77^_d5GY`!j^HAF|;wKi?Iv9=|FzzlVYiREP7> zq0$EvPezmj>AZkH6^3fn7F>gKEo5rjO_%b+tfqoZUdTgeX+S_TU8`MLY=`J~OU1qc z7XRA#x^wIs&+{r;kkO*FFp*FvY0~b?XT87$V{S`z>w6S_?dc@BI$Ks4*ZTyt* zBvT_?(r3XIY3+$!km*Q1C4?B+2hM&W?H{P-#$16dS9%I&HnQGxe%+?9Hwg=*CN@(b zzk+<>zx&ewTF&1`P%$R}nL@)L?}6{vPD}Pzd=%EYFlyg)2u<-1w>b9HmLARbWCYCM zDD2=Uqr^l5x1qzAQvtWwHW~`gu;G1tysMocXaa0C=@9k^fo)zIcol=Fhgqq;KB;mg zh55TgniY)-o+Q}J+BHOVR%$&(7Q@uB-h7)Cmi!PU$R`8@{FOl>Q+nmRnvbW~ORkQw z=wd}Y$&>%;1yt#DlDSj`nr$z`Sv+vFr=iP5{<2?S?g4x2i2Bv#!RV_>kFE@lDu&o7 zPc%A8L6M*mA*z-C(0cIM)PK`1)F{~R(&5F-D;GpLa0nBiFM#>Qi@8~&8FlvkeAZG~ zdU}X{IO#E4`s$0bJI>EGf9h}&oxne0_?sz>7&fl^J_75(VtyJGczSzIXfqc|Rg2!z zB-9k#x4Thw1OPCYDs4wQHSdqfxC7%HoL-Do@C#|o;_IRSUhvcN#mj^6+DtDem8Y5_ z-xMq-8FpDt!Yg8A@%aeD%cj)}@q7TGI&Xu6jn7xJuhm&%3|IE-ms5t8P6Y*XA=Ye% zLCJ4d9&G`8GNq?sZnjw;p(O!|Idb-3bAR%x>FvV~34lGw#r4Jv6mDFKP*%_$jp{l_|-)#;n`8qCtg;4(YI6??>w-K?+#A? z?H1gS)?hd1T(M>^3G9i-fx(HN;0b%20TJWY&y9jcN5Et7`uoO+l^0&2?Cuc<;Q;oI zj%XEw)h|dDU`?}8Fhr>4WMuq=C3&436UCZ<|Km<-uR+scG|j&z1dcb5+m%=v?;BrQ zPr>wZ2YkP8KhEe+AJ^Nb4X8ZQp=<9L6C$VshXr<>(Ez9~oG@CsDdIoWIHn~tF6{~^mcu+SnmATacUV-ZG_#`+|7me2hjuV7Qd zp`)(lse;X*(jy&1l{T=h`bZC4Y(IhZU7y&unp=lbwjf;!Hc62>Fc{(331U&c3eikR zi@NX+SVKZ1BhHyM2R>c`kv)zNF$NGVd%4o;(_OWZ>!3dMcMAaPnx`KFKm}#NaYOks z__GVlH|h2k7Li~d5M?=M?-IYDcg>SYW5OmD&j3yoj)DTpZq)<;$&`Yq)5Zxv6kvmC@ZZ!K>xFByVwn!X4dN{L=<(+HFm@z;EM0$PgS2;_?`g+%F zn$Nq8Cb0Zs&c8s(MYR;aVAu5ewSh|8YnSgXIV~<}C`tWg4=L@Lg^kv9#{h)#6%g!Z z;xml9*6PJhiU18^+rg}3nPNNK59~+_AxjD9N`O4pKP!F_m1FR~JZu zGkt(G&2;*y+ts(g!8!s5R?UTelYL?0k|5LT2k6=J-yJr@V-V{ko0n>WuEMiWf@^xR zVzoDQF`$(+F=km?pw)HJ?Nr}Ad|!D5cxN6?gOm9MjskNCvVknnCxEW)rV+La4JSKs z*Svs@4i1p`?y|f>4FS%nYaLodCaizvgLUctamLTYpSEbloE=yRnfj$YC$i=M@+a^E zu)MeE0w3;ds3DM(fG(=uY|<9$xM$J5487DQKR7-B?*#i&yrN4vQlH<~t~loYy*rLL zs!sO!A~+{H4|3(Y#)=M=$8S;uj=5!?V>?L}=)m=oU#e7c)zqmb%Hb17pgI5!A?y~uQTnj_w~M@49`mtIaDi*l zH+y=1;N(Y1FD#eB^4((D9hvBLV8rBE#~EYTh`#s0s$iz32I1_P9p5(h^JgeA7SSDg9&ATzJ%(l|~^Z_^yVQ#0wMkvb?XA zFe?85&dct$9zlqLYOFy&SWI4&a0omORQA#EONR4{%dhYt)axU5KSK{en)?6Xf;u?L z@xxJWUf3T-n`Dq5;~R{s-Ez6>#jPa+&d<=!s^FD2J4B(>`gSRCAnjqe6{k19!eIsD zn;JP8b}ulvKnQ`s2SI?mmCXse@n4NA8=m#l=B&>&nKjAWCzaj{)IK)%lF(Hiao77S zJuO%}4TEl24mJlh+otT2_8#N`=?MF=`jq2vbr!a`dC#LCNx}-!V5bH`OOJ)?9vDHN z%LoUfjlzTkGcF;>DgSDkwy-*T7GkYn)4R*`PTxPdMbi<})6*AO(Fa`422H=CMj3%) z_`4AsW=dKLiM^ho;W?FXG@7(e&aD7Uggoao+Lv_2O42h&f+oj+5D^G`uv!=|ONoGU z0GyotyWIvSTMk>ti>!mwl33g}Xc?^mQeESy0&T%PVv0xL4$smzzVzALTCBU(;X zt*U%Gg~$RDTEEp z;JbxyXBrgk?3P0LKJ)~kI$*~%+%`$Wg80>eUVTUNV6IFqCCd~P(yd*z0dxbOdkD;i`P`3ZLGwKSMXN5UC4 z#(4M;3f;Zmb2jl+b*mwvZ=}`e6sX0RfJ0RgAWJWg4vAva`)}eRNeWv8Uijl+n|exY zw%42$BvTZ0OfR2BFp6ms`rfZvB`mOlCIH}M<^(j9_$OYzoBm*{5%=G1T|}ZUL;Q*y zIVh)e=cqd@YhmP!g^`nyNKynNha%GC7n>Qk@6}_6y7K{QFq5F9ix1}5WdZ2<1}@KB zOsKBN&w?`;xZnX3g+pRUhfwXeQUK}`Dc+*$+1?*pc*ZDm?(arQK+*FwytRWqEnc#|7A=pcy%B8jXyiaQ0(hMQ z9K&ZABG2HeRy+HHNWpPN^lf-4fla!h6QAHHT7A@(yBba^PmBgE3IK%H&dY3EiKm80 zy-{kGd>k6`=5R?RN1gbu{vgN$oY|C&WJ3`_VPc$P})Kyf7Od@z15Q}4C7Av8Ce zep2!^S8j5|>T3mdJX8Gz?M-cN)REBMxnmW}nh418uXaobu-~Ul=eCDnx(MF_f|q(W zahOCIaVTQ_Gmk?o^22+PL45GckU~IyYKe+$X`oy&4VN@AiOyDGbgN@QTaZ$hNdvC1 zOiqJC_tTi-{_^W!3G9;y2I0EHN$*fxE|0jSE<7&XM47Jz*di4U?j@a5DbH{v%&qRQ zzYs|P6$Ic^kiC5=ta-ZNX4SRN!3=48E>o*ZU`TCGe$99}$Ufmv7~lUaYWS{C2Y1+J z3HGn97d2sdE!R>zV4l6Iub7;m3fCGAM;YijKJ=kJJZ)uJrl*mLpI-yeq;a`&PTM=D z*N_^{MPh+L{%RAju{_V@w7G6Z@gu#p{Y^In!xxso5*-+Gq~(lDmm#5h)Lgj56>>ZZ zaO8Ix-j(REX>gOPw$mT}iJ=9cs=wMg_!1kMLc(a63n&$RYe(`!+5}V6pxUBryz=8h zzK!xO+YHWlNzMI;M|(!k75>g_{pJ5KJ@mtJ^cYv_^QH} zY)#Gu)a;PO(**p?;v>zyD=@%qK~5}UXnJ~}LZhZj=)r)YA0+9`*Z+Ao*rn1qaWX~B z5J=(Fxb8E(wov7J==1x$8QS|SvnqtR$(}2_pr?v8S$SCK12(7vxyYZ8;5EXRt+-0fW4mYtC`MDQm zd`%UC4oz}yH2*;ZLInhqYXS*lM_{s23UhABdl9%GS=qNq!6;X1cQdT-3MyI*a1L#V zx9nd7)2eh*&gV#a`rnNq^caYpA5~I56vJq3)CZNdzVF4+dKE`)%|5~fNmss4#&Fp?Z=T;?+D zPJDKtnE%CBKpLi81*bP%j8V7qas2H1htVg_QqaeBb#_hvfPy9qIvRF1v8mMO-qFs} zofw2gZ}pD*1r4^TQ6F2I=7cfII79QizZ1s1*h;sI9KAKDaUFXR`9`DJfbc>^qg>wP zV`|79d}T;?1XQ>b@Jb%iPBPK~BkNu&er4EBtc$We7MCEBTH)YXc@FXrivp z)<(;=bShio!6^_(%sz?(OD`CW zI>`ut`TT*9{ZSiJ&w}QjbB5@X6zCPt^Kg19foBozZ$9+EAUn%+gVSwdb!oJ^qD@74 zDsf$NG&zU!%?*cGr=Jx$^8Wz}LJbtguGNFWDi9ClO8&ga9K6_qwPmBt*Ji!-{Sxsq ziU*F5HHId z(m;IUM)Pgtx*Sy^|9(|w-feTMNAMsBPPe7oz|L7Sz!cWB8m$G!}z%A1W6UGNX7Gu#g^BTGE& zgs&fSUTqjj0jy)odQU;nthn!flZzWNFP`W*w%`e()C}-XBx|R@yF}om-by(4S$>{^-S}##rMWoQS0m*~-Qm7a zhtb5n1lY09f#(3AseIO^@nE6^jTyNT;Q#$b>#~c_Z$O56UZbXUCk2WdUx4}+#fDFg zFsb)++zhnpN`6$bBH%Vsm5n^UXr9gH?1@j80|u^twlw;9{(wcv-L_|%WO`Mrc%7C= z^aF|E7Y(;`?d3gMuj_^K-wCZb!!Z9?yzH(nY0T+VX1Z&UkH{q{_w~_u(~2LVqALv) zXz3U{V%gW!BlP^n23*v6pm%GF`s6H0E zr`q@&BqAa?1RweY4Q&M;<(o)npM8FnSB(?qA7K5%$<%&2*LB%%e6CyYGB7e?LrXr) z%3AJ;NQv}}^@U0wZhKfQgb-NEtr?g7WIgEL(%`k|fVZh-rLdCnksCp41bwf3nO58| zJwxQ-t##Ah!xnzIbA_Bvr%rmc-{t$fT-s{J6UdB*rrZ9;59D}OLdAH<1wJvVjWLOW zu%GEQ%7ThWY(L15pLv5~;(7J=+(qhRHjk_$9#(the(E3p?Li&b|K(X5tMCV3rfX22 zUlO6UMU;=^HujkYPXg9B6s+p#(rml2$hBI+ddY5W{${J4G#74wbI3i&cJH5gr?A9{ zVo0!VuZV~`Pejz{xKL{&#bk4($Vxccui+X#LLi7eK{&~3{ZCqtTBV?F3E~+^A}&BB z3b@VQZ91^|$04gVap-&O64Div72swsc?TtT-a$Q@*}O30S7vH~?+aeYd}UP)Xyz$1 z_8R#A2(eh_(U%EP_V$8vi-QGkb5t%F404BUUXXLuj-EVv$c?=1LE1j-OhbtpZrFu# zpA~&|#ad342(7VQy-=-?v8?E9M#9wk)bY9LGOk(Mq?_2jP~X8**YDl6w#>sxsCdVk z=1uUKgmQK8Y~JZt+n#R@b-!=$5v6FX3OZKC&qfwbI!28J5rjV6Z-vb6xMX^kBoc@KtUSuz6!b{fb_Rn*OQtAd-(dX0j| z=%SwP82-}r%?c3eBX}R1vS$-^-!TTV%v9ghPma!5dVma% zpGfE1>z~fm4bgqjK1Ba&s9BN#MVtcs&sv^6T5kJlUbUjWOZBMwO5KZ_>UnA)kAfSL z4OZ3>EB$z!ty(O?O$?4?ncnYsa_yDyr`oI!Cq4`*UMT@Dx>0?xLv=wP>*soY6fJms zB`Ghg>8-@yR7xgzQ!aUz!0W2sO-&9FJdi3Ep6^_VZDQ4{Hhgn+;>$ZZC+4#!o_V|R zLbfd1=>Qd{n78biU_IW)H9%WUyh)_#Mr9+YMcxU2><~!CLvOl`vaK!_c5F;}5k%fO z%k)y`ic;5HKO=7p%wt1`CHJ7D&fBnVuP0~zii~I9=PJ*6AX0uL57U$X;P+wY#u7Y~ z2zXQO)5;&=GB}a78@<*Y!5L05Wdsd4_f22{+NY!X_N@g~2=jzU!)t(HzIlW7f=J zFPT^d>;^V$8Y%)>b$vHHRf7%gCbhBVF8vy*_R3p8-r)j|JGcM!Uevm$OlW)jKq|lx ziFDgI7Uyi`#f9w>m3JMe<~ckg><4IZ^<(yzSE{OGR_9)v^bt6lIFk7#nd9two8zGW zZx}kv_(<7jReS=XpFy@(V$W7xdfmjK>5NptWUK}MM>O=esIb8j?+%GIgv z?qRtwHGGmNSdHK2BQJIw`2Q%W#N|YZf}d+9PYR-l3ftUV3Gw02pFHm3jJ*$@Ur;JX za0U7vmNXZ-Nl4~3!QTpH$Bzii*Z?WKhqInPpKtWb`D!3zpslTakwYZ+OTxoau{+7D zznvJ3V?}2a>CK?!uZ&)i`jPKN<1IU)HrU?$39OLm8Q5Lrs*SpY$C7#~>t1fs7M22v z5@~Snv&<#H!Ja$S;2_Al@B>H=EGwTj6kJV zQ{)($L+lL-n^n*F62ddWHecX-UadJi(yEK}IL|E>+4#+c#^pC4G{7j}en5@Fo^bfDoCooT4{L2sW|WZm#G zxnDJj+yEP?Rk#V&CY<_?gE-3ej*NHTrboz%pA;IAqg1(UNyk`#QqmwxqiL!k@A$x__68WXxXdcR-Zeq8h-d45BHHc=}`6?D&;dQ zabB%Sj@mfWaVIGXyt;R*<$rp1U^G~Db$IfJNA73bQLkw8!HA%3}V43$bwYq#h;IW z6N1Yn(goeHjkg+jc_`9Jd~ItT^Xh-E@1j_I9~4VAz*L zR2sd(4GiW-{`qrWBJYdHjQ|98wg``dO423syd@WLSSRmrhM9SvEpss(9OI@uCmwgA&xlqHRY*@cXx|? zH@m+k%du{`*mt>$81}DC-|K_0grRyz+g@YCSLu0I3_JS-@XRI62a2~l^VO;Tg3?JV_xTd16 zsBq`dr3?U!&@?y$wl7M!rF$GQ4W4BUEVIT=`Qz=#iYG+5sT<$(?^%#T>G{QOHgBYk zuMaY4Tg=WeHc?r6XGV1m-)>DsY6;$$3MR{EBrQGOpT}g z*d9pocZNq3s9u}h!g+4a2f-@g5l-3AEbj=HGr;<&W3*~-=SPMLk{g}G>)@eLxnsq{ z3n`M1(gVQ5wXOl*y`VZ%H0@i(|EU5(#&Z$lfen08e2Do+1p)L_?vAEF#Jb*N_)c&y z8^9<0lfz64!vH!Sg-x9?+1?CVHx7b33dSI$3D3?Rw$?AD>e#stouiF_afj?uP*LvW zhI6EAHIx;ecqnG2bb4sW7)%&>yW%2*Vh*qaliQ-D76TN9rPHZu-3*RravArOIn|zM zrU3i)tCnrwI*JtD8*v`4Y3Dk>Jjpq3$mq82~ehR?QyUsJfkzp={YB!Ob6X9pNCfo z%s?%bY(VkP&hG<;;vs_&H-IC?P;yiq4cf;|;915DU{wXw zoPQr8El?7^&NS8U2*1C9VlPIOT*@?9C$CtD9_=^VfIL{`t!qK^G6zUEVA1vGd z>XglT7%z?e6AUDY(+HrPzh=%cZ0WQQw-`Yf&eCGY#Gf^jYpe+vD0T&tzqO226_0&- z!x?}0ykqU_k+jtn<0g@rA=kq7n}{a8D=RY<3Swd>TJ!Y9!q>d!+iD3=c}9J6y=@5dtbqbr5f8o3Vuklb3lv{ zjzD2^xyqEIPhCmV031? z^!X|;!=M}?VU@+k*JD)ASd{|rr>KxJ4;Zq196;zOTiC${mrP zpqOa%L9y5c}4HCR+|mOiu}D3g}}8zLve&*896n98|+jHaUQ#F z)j{bp&7-ll*!QU?^em;4+UZ1Mp3H$qU1rtz$gY(Ecd0>{N7?^l6o#cTqdS3XqFWO= ziJeFdKR=AXLDiMIToNV$8CA21*pTyGyp6imqg5~C*BJ9wlfovewbY^6B#oSPm-F`y z^c4wl1D%rs+M3n{n<7J0BM9&uT%{TCt);DZv1M*X>DIDh;7a=OrqJEf8d(#s@-8q; zr+L25xVcFCY@>6dy{U?i1X`}Gv7?ojc_gCrZ#8XYgEpAA*FwlPjCIEjowF81oqZi2 zP`o^$Vr>$b(f5wXd9aSvXC1+J2wJ{2%uf4L`q9Hu6^wPw{-<@(V%S8+@(GMibnJrI zLW;%ZVp5`;0avZ(E5?s4)lRI{m$NLmh#yBlPTE?dvB0a=N%x<)c zjNjyhmcLC|>eNyVMa1;Oz03U{y^9%h#z#xk`f|e&E1>{ZyP!jlY2?i>)>xCaPOJxM zG;^8Pf2YR47C1-FXwgez!w95+neADypAA8--~TB+qnVaLWNg2=7nuep%`9g5W_r8% zEsdL(fk69QQ&;O`s`e=`=`8Dwz@srmLj^DEx9!d@`P%hubU4Q^hO}l_IrHJ6@JFyG`(zGz0S;_#0%;vudOb(5I{QQjoYNU zofcz96-ZXD3)PeZ*WvRL>oQ+s`M~re;SuaRNDnH%4<`o=@sP4VX05XHgW(VRjvGn0 zxy%r8=KP+txC|#Mu{rXpHZ4t5P5rtsDJ(aLtu?6>RKv9Y_0Y6&X~sDktUmJp)<;F5%d0lgk9RG(k@V>GFzkg8!lbf zn>oQSkSn{s>__IfJWo5(Wj^O4vj@^#E9i-w@cvL9obB9}B<3kW13pBHLMZ0}QHvcU z`sSwQf}xj~hFw##7FK)6Ku~Z7FF3z`Ixdi|%YIsHF+)RfgJ|tjq?OB4sS9%g5`{# z=(7>~f>HXm>YUuE&p^$Y9fY(dk>W3>g)&15!TZnvTn{sM@(_V%id&IGp|4^4YzZey3`x7Ldp$3aNZBv)H$HV#|>WW(**dFa4s z-12mu?F#TFUjT|24MCB)iE8KNb4%dCut3QdyZ@`?G_#40y_mcWeDed7FTQ{IBQik$ zp=0#LWYeNoWD-6XzLp@M#&0l3>}^;fbzEz|`9zl@r=$nG>R=i^*#bfDV<&?%hQh>} z*?b^qOcxWcR`!4=k8g$9QA|o!RoeVL`FL`I*1F{E=d@KRSEv*P+~4JzAaKu#hAd59{{z|%Y^SK4M%&H@Vh{VVgz*Vo;JX|>xpA~ ztQMaOcm-aWut=wcP>$d+65u(~)B7NV4UkqR1hFklqv>HH&wmF%Pj`u!Zoub?PiG4F z2KhN%OkdqmCaXOIEc0VBG9SbQ+lj%0iSc0{h3o)y!MCJte3d1KO0SAmG7n ziW0$xO2Od>mKK(M!0$`+))(|w^Dk`m3?f=gTiC|ze8d%-8bLan@X*I;#?T#toF1A#IQ5RM>j62t zYPyXLufW0!(02f)??85+v2?*c)mK9rqzm{EIv#Kgcuzb79@Iw)p2&WR@kx}oqPWp#dyakaSY;8TcemNzmnsrZC{jk)$b|D$qLWN&^w5aV8M*^JWj-#%W1Sc zE!c#@)nMLxZ18LX0fNlU(iX&ciOnbh>l`2u)v3D!&k5FWXh78;{RSo+%WN{f< zTZMZM+}XP`)&x)f#Fd`Tj@tHip1pYQxe2Y8;Drn7;Z%DXqev5#El<{kmD=a=OFbGd z-T~RIj|Crq$-BlWZlls?t(gk=@6g9fLZjHB3U>~rE(`mwX~AFqD`<#Qk)6XtxsQqM zJ&>a?D?b0c-XX@AH{E=(nie{IGmzg{nb&RfJl5QySt66fjCQvk1pz`18o&w+OIGe5={f_^KvlVUs|j5upk*1Ojf zxGyo)hT9km>_brUXAf%M*KU1NLK*=$3;FrUI?$DhmKLwoDj zRN~eX@w4Xp;ruZF+BpvZ4?8(c79YUn*&!O^5X$;2S)O>KJ`Y@uq`^hsn(%W@)zWR{ zBQzhrjO*q#=Ccn39`I-Shb_ecf*~wbc*W;Z zbXb)0yF%ymD3vc5JtG21)Prj0g=2EvMq^ns5zpzP@R0J}FT7MdM!Cy$T1&uM^#5xV z9hgBi^Z(ej?0p#TS>}KHgktW6aSko_8XKNUZtS3O_K`KCc1zuMN zT%Lze;~(;GFo3OcTd_Ql#C*MKqH-o7>z9cJoQfqyY`PxmBBuVZw;hYvsRo4)4i8&& z$&o58PyEONe}Si=rP;V_2tOMs?d$CK56)aT@d`qH`y?Haqg1{%9kRcargA!A#YJo( zkAyW44{Fr@ls~?z?QxI*lboO)VG0I&o40ZkNro1!eMpIB+<>1y`R55dIH1$hsUl{v z4nnl*krU8CuKVZ4w1W;qI;0@nXM*Y!pu_2Ij9Zi*%^54A)j0j+>k)vJgI}kn*xeIu zgyoM+>6=!7$&j9npn&hD`{s!k<4HdB#-!^CkytL-&XoH@)Iz5$bttspi1f1G_~Kvmt=^`?O-V}A)0&JiU4hSXOgg^eUI{a-=T+P=Q(Xa9xtey~B(;e3-et*>1xSjhbU zdm+JFP@3T_6{h_PPG1TkI)&u}%%NRKj;1N|STvHnUyP{-EvVmhBO z_a=6t-sd!hS}<1kTA#uF=I@DLJp+>I`jx6AancV4hwN}VK0-iI&0dV3Z}+S@EGL$w zpgpQFfp{DwJ#2u`pr0_MM3CYwg?1nL@~hpj{^@&fk(~s(@!!$0q8%B;m1F4GXwVI4 z2nPyOgzrWj0u8C2JmzX!yPld&`cq zeof-<>(f^%ShXAt2vrdZDT~h1d)`c;q;&*x%+?Wnj1cpmlIs8X70~(syCCr|?-Yq% zd6K<#G1q<9B$`O)15gre0uXdV<8zQivSNl$&Up-2C!-f6;ih_8*50%OVFel$A61Oq z?srqX>4JD({gG9N8GmNy1W*2!TeU_1_6hOrdpX`q zYq&|=-s8Jv-Xh+#18RDNMp5*n&{ohXp_|UmlSYmfb}_&blYhQMzLxURNL(y>LUHlj zW}FflOo%TjR7aVHvm_o0vT~83rxq)7{a3vq1NLN6P4&}YmxCJP^Zd&P;I5gu| zVB}Izos3K(3yOG5kox zloJ#3ja8#M1pvSkU^g@BxNZ=8FDR$t|6u@bG0nKVYO`0nk`);??5%%IEQyHT&)}v( zSVmf#)3pTC>!5!87Hfi=9{|qBx#_#nGco zgM<1U)T8t->k|7bb+fW$XQZ5}mCIKa45$GqJ$Z~-Zcyp-6~V%w=2l~v><1+wV;6aI zAWDDILF^bX+4{>_N~XAy=P#trDvh6RW+IkJW5oKBgOvS}YJ8+Z$RY$Y=*0V7e^}@#JIH{ElFybzn>Vh>IeA3yl2HG=1b&?h9r# zsOmKc01KY~ZRNFD^X}!7g{TT-YG~sjg2Kz<$?*&7A?VQff$1=bUfIF!yVQNxQ9BX| zBQ@iw6EcgNI8>_bL2F=wGSZ#guR-}2uv|}Qye z`&BI0ufH5N#@x9c9kf(3VnT@~Hg&&GYo0 z_4Pf@>FJ_L6A$qIzkXCm%}{nClOlvg9>JDwY6^akA?DA4d`rxj2f*}6AWM{v#{F8? zc!0J$7QFvk1dkL~SD`$)W<^<2JX9P{x99hPFKHT|@^@6)I!}ZG1CUY&Wgw`FKy{Np z+BT0JKatLBReqdse=XGkJ}mpc<3=3nhXfF9xh3KX0nw2mT+foD}i6EiUv<!?!ti{=!o6v0RU*?S0!BuI5jx)BlFHG5XtbT^`7(W}2@`XReZ%UIAT6^Y({Q~a+otdOF#iZ6C=>;~aQj9-Y>s{R0T zE6nqX?(;CG6#XZppkG>L@!M6Q@m#Z$f`nfH(mFusCQ3baP~Xw;$c4F&%0&HOK-F1y z2%;23j|HO*XHp#OzV~cOJrnn?aawA@=|@@AexpCSYb!!u?h=ph<}Nlx9a6NkM;*+` z?$mDA9*(RM8tBk|*)??fZoD^_XtDLg;TTzCKl;(5n|sWmjvvBSFgNorVg1}{gXP-0 zV#^n&bP3fQpL}bft2o{L^+suu<%Q*5Z*d9Me9#NDY~06G#013Q&PiO{P-W|PPaw#P zV!n71A9qiCu(G+w(#}j&f+P@jyZj>qR-=194FruGjf$szsN`@Et$FX6BlJKGcdXwe zhbA>n9fO%}ak8<}X;;uhVWd%XYXYlLY1Pk6U37!>!4I#N6=eg#3I}N`2B?P|wL^xb z$MyKW+sgLiYWpvez|HnAl?^{4is-9_X+BbhAPRrbpg8b&?dHzIhL*$42~T*$aU+<{ zSe|-FWZHa1d*-^Q!jCbZiAQ-iyvZQ<&Cz^)V`QqFSvL?#@n1Ne?e?_znw?udkGHe~ zJgmm~qJ7;7A60=e>hWdyN{~FrLgI9V+kzz2VJAKG>)4 zEFpUZEp49+U=VFCC}z9_5DXsoC)leRA%O;eMkQ=~O^BQRw%3deVfn>3s)6UqRhTK{ zXC!ZGvTQ2-h!;=vXz}w{9v=}5Mz6lT z*$=X33@`9Kc?d#YrU_`W?7!E6x(h#Xx#tj6`BKEQ1j*em`?X%kjHx*0+|g=Vi-)b0 z9)3ziZg%3_r1OD!3WJYUNQv0#E02wAdCx$`oc}wHhJ&XnK@~<&kPW%WQJIrt`uEI{ z`ib2RA0>UuP*hV&ZnV18clN+x-l5dz#S{WB-E-Avcm3hsuBGF_!Y?|Ct^yISvElhaX(Q?d{OJgGvs?|TGH?2zea@YBX zyE{tE+04AQcD&EuzEJ?^8!o-q%w~@FIJ_qE9(X1rqmnlo6bkF6KZdC%VDuMJio~o= zp4#9FDV#H13S`DZQfSiolwEfu`LR{lw=83$IRK~jgaJ${23{>w!7D{+RF{4D1tQ5B zFi}%8b2w4$rCxg^V%_px*i*YKRDZLvmQvt=*CT zn_m4A>sPvtdtAN7+n}4+(R2r^C=jhGF~CM*I#vZA{xr?e+*gdsIw(~l z2Vl?%79MNP`$F8yk+WEve}b3T*N^ z&{3N1e*M$j3Sea;O>2@&si7nzPc!A!yMOTYM=fH;bo~>R!#1lP-phWUC#IWe(k!tQ zp>PC#db1ym?6#Ulo~&FkDMe%?Ue`->g10KSi;9a$2ci}gnwqzh%QU!~6}FqrQ;SOL z*|A(xykBge;Ug#_;7fN4EE2F$HDR#vJ6gsF6;F^wM^0hYP2FlCj(%V zPd>PUla|d2E|=8-t|w^dO)dNF>YS261saM`Is%Wk*SGTqkzF!ew7}lpb3n*WT?_-t`3lM@X#9AsaHIHCp@nW| zu-ML}@cT(B#--w-k@@Dy^$pkkxEkqis-yf?lnH?{CSFJfJ%%n*E5SiKxM9*H^ec3#-8>n`U$Proe2#o~KCKetpY^P5a z#;?@jSRms3t%4_sfHtprX3=!Mi>zku#8I85fK=Y!~3n;nwWq zXR7GCVk24Nuu4&=|4^y5gb*g6_vGT-3-mgMiO1Av25Bl!$iw87K=Mo2{Pt3&@?7nN zFk#Pss_8oGhWh$o-_@j=YI^xTt&PwmHs`2)w{hRkpiNp;#{|Iy=D_I@+gf|nG-|u) zb=2vQe<04=<&un9QDIFg&JL;4sUoDBeNKHG{#VHQMdYm>N1$grJlU1^7-%yM+E`CF zwQ3_K!B!}mWZ)7|SeA^jVD-dJ$4)V`Deqy}zk1_D!@(085LT>eXY%rSy@Li_WE|ZFUAWeyny>wj_cE;bwK$k1ahTK@tFfZ=%kX)>wA2)SvQpTGEhaJbF z?`%&yQV!VkR~tqf52UV?H?YhnpEpmKnHAs}&Cbawdeaf1qdP}6wtsnQ+2|ijy{17ea^JAD*%|GG#Fu(Y;nWF!b~4r!0?WqoJfBA|k@UMXHaNyRO>C z?N51?&j$PPF6zqHx-U&kc)ylvM}zUD)a6zql>qTHj`{cU_0T;1ZHC7aPjjY_ey1y> zv|Ex-KY;~%s}IC$L;cKVThIE88g_6b-{gf_jFdXggF6I$rL^*dl5K-dDfLbyKIchw0W6yi7F7j z`8}O>AXWcXXO5iSBH+GQ$hqr7 z#n~Rh2Bq*oMu0OyzpO3to$hh)9RS;3=I+f_bd*|*^kvJv%Zn;Jxg*DuSibE&q75Y$ zCFgrVqz8FnZdq+CKB~{jM zXJ!mSmMG&Vmcs*Grra1v%K|5!-lUT&`$!mkQzHmJrIq20oSEa3iWAqaV@^+%GreTy z+wc@?m0ggHOl{P_huzrMpSsZBM5yWOq7ORQtIAssIKSU(KBw5Ya3`fR_gsq=D;F`A zf38b@D8gv^$TS_ZOouMyjf<;xBz~S!u6@2YF{M0h6n;=}R+m@(Eo@vHS;oqUj)*eH zLwT^Y*W^ULa8%oxl?!<=y{Nq*68kB_V#nqH$vz{0PRy{Zn}EJnH#&|;`z3SAB-aPQ zXUpIdivDlluPfJxolJNKnILHVv_Jc&fw*DmpBnLG#0W)r?T{07Xwe(q~!)jqqOKt6D&|68{!7a4$2+4!iwD>YX5&i*0Kw#ujT z*RvOAUVE}4vMEA{Zf9@@HrB>M04>LYF{SuR!!q0Y@Vv0!OehMf;odKYP|C7-Tw#=?F==z~6DFz$77-lj%@ zM$$|67AZ#c%{_QotqS^RwJukcV0jI1E7EVuvm_pVD^+E&OrJ+z{)P+p5Jx8`S%0rE z>1euD(U9GJers=~f!((odLFqQfH*B*vJG2(p!>bc>eTm)nD>HfGVq1@;;umh9#KNi%PK|FOY84ymmrr}pp?6TS z{tpYQn8mGXGbOGx8WT9B3CVT2IHY(fI;rGDTEsZ6!5IEHwwPTQ9n-=u*c$^?#wkAI zZhlIp5Aa7eKD6=-vhb>a-Xy(k5E?!ah?#*mle!(p;Y*PS$B zwX{q>cxy;y8~Ke**H~he{SNuyWveXABJn&I#!Kac^>Qrj4b-(1DF;@<05)H>ndwg? zj|5yT+cleaXMKW?TEu}D9v{{P(iO^+- ztJUGaVFV2i)Bx8X)h4_e zcWL)e#bUf((A*X_034aTv3}oQ=XOlGgDt_#jVV2<5V7uzPj`S74FvsVaqnh^!p~?{ zxlFwb#a?WHZTwE3P|DE3o0c#RH`~cb@1z0lLQu#^4TdWa=Pxvh7%2lI0SWd zt|4n8>kxstL!)EnsLg~_nGvCk*OX_a8qb0lJ_J)-L8E@@iqmnqEn?uy1tGx*(|Ymm zfIij#o?RF^nTs_@&#z+YEA6<58Z1w%b#J8amJvE`o|&qvjktUAH|+pl(iP-*4d{%?j`@Ql zHxqtl%a7cAz6T87aXYlx{mc)wvU;^%h}Qz{Nyhrz+IG^D zP^L!gFeLYbcrMb$Yomd!x;pPvuaJem=O^vr=F;jP_OAG@an18)L9xzlc2#}WA)KTF z6=M<>s{*=r+kt_LrdBDQx0*z_1JEmN-K1}b9mWNf-*JHB#+Ke;BUMNv`d%lCn|Y?GSV!@jScRbg-134@u_}%1 zz@8eX-uqkYrkn*%9oM(Ezh*)`!C@TY(QzUhsv#6{&j4M>Y5SKz=b%wUJ`_4w9|bLT z8r=SyCXEv}T>Ta|dIK+wCu2iCONZS)%T=gQ##!(p3TCLC^D?SVrl{Q+=KcEos0OEe zZ@p3|1`~3~h{Y*A>90TCF)K#RWRHM31GCUOxHhGJ9-H?1N6&(fho_2BK4Jry-8Xhg z87k2|CEMM%!JYs{Vh^P8D}n1k>SSf3p{HG=eamXb zvkct8JelI5gXaBk=)M*>lGLuY)OaJXs-qoeU(!T&%-c*E=c;5`orCIPoE*IN0~#KJ zaWYtE@0Fju9AqaNs>fh<;ul{?cw5IMp5pz%qt!DrI<`4Rmn&O7Or>G+l~aYB@E0zc z&jvXJ6nlpf8!MGur1B{o4!pFv32jr4!B7g2J)L=EQ{@*Di$XFs$Z`j!VrkoJX%yv^ z4P*`3Kd@`vN|mR1hsR^(^MReIEB@{Gr!}}o9qBIqD(FoYiu65hN2b}V?#BZ7rJ*fG zXtrj6R+-dO104+H{uwa+UG(;BkJZ3ir%^C(R!8N2EZdnJ$e!pe?78(?6dUc;C1Aum zP!dC1c}7Q5{b|5Byzz=Uxe={(b$48wd%o$xY>Yzf{tmtU$ae=PpdN)mrAJNmU6p0| z*~UZ-`U9stT=WuAi1l(IjkCzpe^Y(p&;FhkVhy6 z@KyRk2rpicC$F&Z!nGot>O_N>%z}*pgr}4%wR6c@2kh<_Tuh|mT1mN z4#FNj-Skxhhd7XfAkFBw7-}*(CN2DD`*Jk~1JyllOZ4+c1Jwrn+vPTEDH|v?>8Ytt zb8hK932_W-ezu^}#oyXts-GKpF3>c^c&tnz7ym_)tQBu&&Ta+ZwA6S@ceqJ&1K?T0 zoGnw=tS=gPF5hNPZ*m47WqG>NNo}Qc22b~XVoOf`dARrVJzRl5a>{gUkUS>QaqVe82wUrP5Am-`!vZ4FBHrhQh+=i(>wq^~iCnu*WtcqMHn zZi@K<&HUAGO~uK2&Mr`=$zQh09hb)nb7-Iu;L!b-NypjuxK#p~bPqbX1u}@Z6ZbP$a8E?KI9(PFx7YtIHICzN!0T@cW7mo=#>4|Uc#z83dW~orEZU)a#5kMl9a1vvR zD5z4H+^gT;*ROpvyETM^J&Umy+{OCj1D-$@_P01Ip|4qpqC^rlG*=Vce6Juj{(II6 zU%S<8WWqf|_&EzRV~RQU@Uw2(RyX(gVOKBgvOyykBsuy$#+5Tl2?IrVt=g+fRj_Ev zCrs0-^|uc*qwZB9eFkFFEh`^nMq)U>+sNuJ@yCbiWDZl$@o+t>wxUjjAOz2lm&92u z$1&}dJE3C_H5ei0S5T!VB_Mvw4o7jv9&v2?xGjC~y6=0PtJRxXa1qzqZM@`1A6IIc zCt0m6|M}Icy6F=wd7ykrn1MI?QiC2*E<2w8vlcUt+go1-r}X@@jHR+tz8}UEUU-s6 z8E(IOozoz%B&ZNKA72VK7FJcN6KJ8)xa)KALWS?vp3Fc;CZ@~Q1~==KsuF&IK-FVxvpqE(G+q2)DZ-QcRoU%yl$6v;K$4cEO8{<$WEH`qsS4Vf6T($ zW2E11lHuYwMzTj==7$|bG%j{&%RMkZJb$fO4%~A;FSj_Ga1EmD+CP}`08q=0In=~b z$3;-@vaLf$K9+O^Yv`<$?iNLWs=z~o_d#viQZw)kBz``AS_hhIhmDM1dr=zsd(Uz< zY1zw^Bcjs00`ENu8OxvhR3o-M{f|1UNT?Roe0Ip+eI&qiON~n7<-&xg?>rIwv8ih= zqi9b(+=vBD;&6UE$3x^_HP_?{!M3-Qy@**G*mC#V$Jz?KLfJ6u0v=9Q(*>F(bWolW}U)+;w)ysraSR0t!K3%$!CYmHzA zlm-O(cRRf>Y-B1m7_a+}Z+ZA&@oFaJu?gqkk*E_|-(B6Ps^uwhF|JMv70BOP+Aiw6 za68BF4vhAZ5Yc50B-g?d>#(nfO^8eblrFe z@x&r`8#f8CAuZheXUed#W(_oLNtQ+Jw^oeqk6wwx8{WsR?xVRrg(}w<)nH>z#63xU z7{xu#s)}7m%YZ}@8L~m%=;7-|SizatE(l92d*N!An@D;$e8dLcCe3g7Z#j73)32a>xbym$scMBP%cLdG zW9i5?ms;_oH3OWw=BSC{JtmZ|3c_)DfB+Oi(Uvk?Fv27%H&z8|f0{>G7L>uHV6%3wTL}4G*BgehhF4O{BZeQMy>V9v)p9p{I4-qw|PK;kDckY7hP%^ zpBvg(#=&g7iQ&EDHhy$Ystpa+#q-|;qK!HscP{$tXb#PuPE%fU;cL|U<)1gME-R(8 z^>PiUYy}>58h@bB0+DD-lz-QdeG3|!X9t_6Hh#DBorTjBi=uTclXTGg!~Q-$@{Er} zm~h@Zhp9Sy8_NqbL;1VoTi)UdUTkOIA$8`JxQ7D3Aub2y_n6YvDeM`uny6}y{kJ@m zkh->JNQ|oH*H$W#Wl>&9(@U3*t-duPK6fSbTGoeIvzG4@{kO3=!>MRXg_{_ycxadx zWwxtwS?A@9$=Ab}zHS!RSG!@kA5#(nNhM4$y_UiSfY)j3bL3<(}9huNhq;FMY79zh_8!$5vP63^)_B@hb3r zhzODjbRp7y!=%EHuN~KJ1CE~*BXr^O&#(+%6?i#Tt3<}NGr&zB_hYJAGjB$|J}~9` zfKM=}h;jd>BL1~3aM>2j6YuF-%x)io~ux8Cnf-L&_dGz@t~zR$O#@?LW|N$!J94uVhJ zhh-;Y>FkS}ug#m(R(bOP`4~%^Vot2m+2R4moqukeD{U=bOoC_%3B);B=Os!ojRwWO zzu@qojF%r#)5rrrqv)@op>tQ+X|tv@Uh}E&Kctuehf+}?>)sBGSzqAUgOpnH{dyh`t>-FH6&%IXk{#)en?Df=_|BZi=4xb3+O2jo+^(=6t3*|{ zE)wSRFTtU-lc-YB}Wk6J8MjFD;#5q+_N7)mqGK1jP8~Xd71Z1RV=}6%X2Ake$OuU zkeXx`!F!o=bUHXO@4f0%liqzRD0|*CUW}x&R`D_7*eaa|XLu{VV6dU7es4-8yaK^W zesj;VfaST_uzSJw+PJVtr_*{?_x(!uzG2Oqa&=Ri9BO z;lbyk7qtv3NB0MY+`h-ufRmUC$oujV1pYZXDp-I}@7y`T#y_Rl>}iU@+Abz9_tosp z+&h0aE@oA9@v?1MfHlLeo4Ct}!q`KA9hViE|3pHJT|gAh{Ur*QJU+o^pvtByq4$q_ zyzye+v3i!jqT&jhdDbCSu#gitzExpKftQazy#Q4*Z=JV_jTk^a$!;dD5sQ>k{)j6& z6*lYDzbUDFKfF*})LFc#V(;B|$)Rj{o~L`dg9;lB53O&p7dw>r1#i7m&;$X9O^x%Z ze7$?@E11t{`b|78KM)s+qPgK+DG52lewMWRkFAr}-|nz4d~FGY*Rz2l;9grX2e8$+ zD4^}rpIBqgXCCB_zha2!%O4dNjH9;qX19g5hdF~gJ8@&CbmbfKZ{*>TvpuVUDq}U! zT$ScoX1&z?7rj1_P3t0L$$VpHq#`C$k4zW5%qv*qF)}o>NRVuAR4?mz9rODb9)FVd zGeTx8;W!ikQtdN$MY_6>zl&ls(PuO_r^Vb<6dT5c^p%&mZxtCOn2rLHzo*w(kX~sQ znm5lMuV8R%f;S1P-ZROi3UO>%2#{59m%>h}LlRtOXC<=WkB#|UU z5Rim8&1NSRUDd6n0Vfk5<$lwY=;5AWhPvFt!%xZ4dJchQZ+s(n!m2Ed!s(-p76ppF zbeijp$|6COO>Q8^_E=&W5!>eX)}Iqgi|Mbd#ysyR_@Zv_oQDm;u(y5WB?97Z2!LxZ z{OiXtLh?flT2>V;ER|U?C2&xzBlsH{OfE9f$NORx zOaOXA;KZY7i!dt62B>D~k^r0kLwzNVZ}!-H>feDXZ;o$%wR*~y|KR43O#^+C3=W8BBQdv(O(b$Y8+A%vdYkjn9k3MD!8!F-w%I( z?TZ-^o`{fJGbE+M(%6ayQ$c~iX*@BZ;tA+PfY5&uAsSwEo-fLV0Ssj5UQ4j-v(aM$ zy1DJfgPQ2ryvOYtkDtMV#xn-N^K&9t3cYz1)Vm!iJN9nk?>!qYK6<>8D!y)dKvcM`KmB2RsPOn1HFVpJ`V!N5p?IZ*)sE8^!o=o}v zgUY0e<@6vw^wabgxuU4_*buFc z<;0=2DDPI(&hv|m>X%_$ioKI5wyD`uDZi#DNobXIa~$5{GAe12^bSb;UUPzN~GN$9~?ta<8rO-TZc!#P_QNA)#GvFB1 z0O1auN`U6lbzjS?H@qYnA<8z!VozZdu!d-h@#;2)uq-Fx#Lg>=?Y^d65rY0>4s2bR z{t^ULKALL!z#RYnUZHn%dZwsO^G8AOq!!|;GHV(pB5d73gTyH;34E*>qspdZ{??+M z&#*L;+d@R5VtP~?t0=P?%(5F)JF4cqu%YA^)rsdwmKxv8qyw$3Km1PxJfH37LPI2* zzSD%rLqs;vuDCa&6-R5jPS;olcs>6Z-V121GKnMERs|;GeDM`h0jh;shgI`|d)1gj z0(nU~`C9qq|$v*m#g-k2!xxaqahh6 zkDr31tvc@BaPlCAJ!LTiGxq7C<>yG+CBwev<3MEr|5SgCyJ#e{gQeCXlJ3q;HxH@< zr`e?V_m5zAYYyuKDXDjojk@!OPUO_Hq> z$}j`Iy{G(2;l7a-?*_RwJUDj+tzJw~K?BJA;=k2f2=R?XPm~6X5(sZBYhS-j=xj)4jQpiENd5!H zqvE?5sx;AhldHE+RX9Ny^t#CKunL#%HdCG5#{Sb?({>L9$sGDXw&DrzUijTQB$<^S z(@J*5;aJp6gNRj^XQV~>VI5c7Re0si&+m4S0L$TF>}d6Ni$!1N06+WZHJAFi<`T4@ zlYEDaP3K|a$Nm%UPj7zz@30Vo-LA0c8T)5zW=zZ!cZm`2M4-O zMU984ez`9j9ja^kiQESxei0{y6cX(G2_(-)CNtYEptC9xf8%*V1K}z~E208>@~db| z*Z#PZ*5z*n_LxxiKOs1!wj1tTEGd6onMGeudvL^rG_BR3M_SW$+1ar zOH{$1V*Bt@=J)gTRZ5J|5dTjk2~fAIG&LlPHScTKN>(DchyzK2Cq(ft9mf-K-C+8y z@ZUUl?AA$8kEcq_7B%D_l2ez}JWzQ(*Sj-=HKb$+;F@Ai^NmU&htR{)uIhWS-0#u# zAKZKrvnq1`(SpeN=C5ZPtKPk{F|9R8B8HMRAFz=~$6B0#--8o&pX%048v;r2{6rAk z>C8EU1)gnl@9mBjf=fX}9-bt-gvtpk+1L=tW2n-73CxUQHJCO_o!Z^ZfV$iQZ4>vz zdT`+JUOe-4@Ch}-{wuj|*-ZotX){R){04hu_75_k%C<$8!Ya#KZ1r13#Zeii%ERv~ zvhId>>s_8SMWM8$Q0=D1qmNfUSSIi!y=_3m4%wTPCn-ZP@^#}N25hTYY+`8g+HV7q z%LIA;U6``>nqVNr!1}8+5)DXvliQoS26)yZUCPGpLo&Y&@!Btw$`Au7nk$Me!teu{ zo(G?rzDnR7eu;jlx>;Ds8Weds5X`=jWLZ6TG#ymPBr?uD_~LEY*>Z3Qmiw0YYv#w= zxb}?f*jYUd2)!)>?XrLck)(4YUwP33?q_aViRIzZ>NFJU-w8rsLlRwC!DZ&(#nZmr z{5ZkT6_oo>HvQvUw8=2hz7y6yF6zdL-s5V1&Tk^{>{0hJx7WtN>e0~C?-=$Yd{$^I zwpz3y6Hy$*e!kKI(0xZgimvjbL9ENU$JcXY1)lfJz}63P4i&@ny^d=}?s%7$cIBUi zwyGcKl?3Z9n`?Q+W}S@$A?AZa5zqONOT&vwJenuT$cR{HzNyyMu z|8zt}v0+)RLuN_dJhvJCW{vudZ{AuOM$YPNHxYIiMIr*5HHUk;vE`q;_!81Zxs^VK zqJ}rBR#zO5MvHAszC6I2v-`v3aus)E+x>)NuZ|0)W@7gn9D_G2Tg=K98KFsAR5?Jr z^qaSi01b_8?koonArY5~JiH#!fyr+A8&3DTL+f>=Zb2}HNQ@=lT?4Rx!{7tIl6 zJb2TeKS?`qCq}slOVgMyW7C@hO~%isOPK>_NL5)}HBdE^E@gXD-(7v=tySUW?ssJ9 zTNB<%Lo9mM3W;aTmtYr_wh=E5j|%*Vp`O^mJ7;h&Dh)u;B-JT4dLlm;Dedxlkj?fu;aKvnzjbH;9B9XPqSkOYLH zcIg})T_R==lTsGp(UR9dw-c_swK=*;{`f9YBM*0p`JpM}8+@*Nz*A^jeRb4F7{%5z z9(Qx(%yLbQM<#BUK&z9_HAq51TKNqf)6*#Ex+C!_7afeOl%`AoeCFs_o^jsJ-g%&; z4UTHHDU^L%@{{{4=4tKm0k$pdwo}>Gd&w_{q^?3ExX17iY~F3LwU43$b=S$LUV{Cr z`QET*IRGVd+PN<}A9Gu}c4cEmfX?Ib$I3To&AAs2cKPHA-(ASpBh=G83)^NdHE;wq zxXB4-;AEn#F3?a2m_5Y-0|&F*j)oUC+qssFeMl2FRw?e9>ZvRt13Ft*?Go?((b?*; zd9F?-ycwHbYxfnY9LC~x*Lv5Ik~wDA+~AExpSj-s>k5IE`Bwfp(W``WEgQO?*XvfM zR}akt>9xgQXHZBsGX!xMDUwr+3Kh@pGZ-zsFiE`1@A(y63jWH%T#snXsN{%Fk65OX z)1rxi{xeb|H61S0mBl=^ZTo&oEiVNR%rBDo++$Qa*L9D=?wmZF3PyHg=WyE06-msF z$cr3 zW2u`J*{)*8y4v^&5HV$2Sf1{4;?l(5) z?nsfi!ur9hx`tivi|!OzH9A+NWS}oKk0^5ltKo7ogaPP_mJfiJ$cT3vDCqbD#VlUp z;46PwZ$<^6%cb4ekrpleCnL_6p!9GsLMYyh}71E5ZT3 z`BeAYvxX676Q%sl=6G$YKV>r{`4u#Z65ruT2>jS=38fh>y5}&+$Okbz0cN0)FMQ&? zv^$CyJf;t58r||tu|BJbu}1$Med)6Z(<^XVo2g`t2LE^Esw?t(aXc$}j2IozHcF#> zt?`KOXEr-6`MHWKEEhRPj5cUdne9rD;TG|Kzh^{~NR)rcSG?fW%ueW&Qs3|8v#ByZ zrmr&sCF^1b#nAf3$|m$wu=F^)a?Cje75h@y_~DTv=fm)!o^ygdXH3}?u-;(gFNMHs zG|xh~D}l%BE2mUG?i+AM0iA?~@6UR@^c2Jv;QMhN&>Wb-3C%$_;hkm#C3lO-W%JL^ zA5uHK{;f&7X08!*C*2qE^3Tin8Z`3rdDj}ii!`t#qjRmsQ=rQH!%vsbq%)-YMlP`5 zHGMU^nFZM_CtRJIx?#*HC+d|p5OA;L?nh~|3tTSj0Cqyg_0QmL-Q3VcXDFYk`_Q&D zkf(wRJ@#6gr@w+u5&(Qol$sv27#Z-J%VFb}^4xLcE^EN#`LCXM^?{%2#X7Fs0-PZ# z&k-wsez%Dp=FGD$m~UoE0vLf~3s+vcezgAjSSW>5+TePY(O!oZ<=~bm)MWr|f3wy8 zUhbxTU))Fk8Mkd#sm*~*XHW>ZJ<;3s6$CTRbziHS$fTZWfPUxF1yZ$N-rV|UHL=Bn2= zJ1IJBk`7EG%0Q2Q`73b(?$)1E&P`s#28K$?ng2UkQ9bw?N30>jKK?Zk5?LCXiq$s(Js6301(c;y~gP z);g}|me@mtMWcH4!h^(z=9_sbhh{qOKv|-*->zWgh_|C;-XYI1QFJJplKeO$dsS|f z4?`kq(l*qew&8BKow;&lW|MU12h5f9a#Z^H@K4;0-mgD8tGv_S!^Db+v zoq?c5Ua}3L{sast&ULKDNEH)$T)FeQ_O_T?i!3Sn6I3%5<&->-7U)qXgAGth6aBT2 z=L3BJ3i)6Bbksx*FUC?KhXDNt1VO%CAlA({0frZt@B0G2&65RH+SF{Ft-me}?^f$x z*b46HO-j(O)4jV|+NbfJg_e;f`$hZJ^-$P82Ux}4kidhkr7B=`J57(rh2!`gFau^? z*0Q=+b`iQaeF{r3%l-b^?R%D*DO8|~y}m)C$m0*Z%pUMlpyV`(-o-?LE()bgCU8+G z^=FsiWcuJ6)=+wenw#MwT?$rE1LBFvV{{!Rxae;qu0VsW$Pe9>>LbY(2%0wjTZj8v-Kc~!sc_)8DSme_9vx{W&@o=#F= zqXu~x{-kW`@BmIU;pQv!e}Q&F?{+$2jm<8 zH|5x>a?^u4YM~45k>K7}#XDZPm{8rVu`=ZB_j>wTIYtQAZe78R4P6EQSG3ZdOm$>I zpjG_j;9+gau{ri@42Y3(lrHMjs~@rSn_Jc%5kd!(9R~lBT|H>7)%;g9N=C@TzK|S| zlSs?G*=Foww(|k083f(<=ErNk_blU_9XhoZK+p5TUXAJ4&U4dtS8OJ#eXhXzyMY%R z-mt=+UrycFLZ^y3pKoLDU40QE8C_wyb2;h9q%9uWm*$^=NOh9uxOTyv&g%FVUU;^e-arDd%ZQKYo*L(B_KaPeE z)+5`mwk0~t>N4+@ksE4VUfVna)tTkjLl0J(*GA(nO2`^`Ehm28${v490%5`{=ZIt= z>$#s1$`mtRVQ|bl1=wP-R8fz_0D}{f8f^L>4~f#OATZA}S&wNNMg77nIK^ zbktWF#@BzB3>}t?A~Ry^^&_O{(YUDIG%)EVoh)jQ_diTIqNWGet~-Fw8#>3=FYgJ0 zW=!$3Q)P-8Ci|sKVPq$6oh&8j&R>c+FE(iiraaJ>o|r_x-Jy>2T*fr5W46y5H7Ze! ztjKrHq-YHg_-ISmp|;vllHS#-FAu?*k#q83vIt%RUy-|0yQqYRCgA{@6q&en(vGKj z(qn$t&FJ3bg!x-b`Xn_hV?HFc_;yRJXEm_L>nx~7>1yqZ{xHZr!><1e452TRaCMmOM9#Qgd(xAuJ9*9-XO z-{#Ik$qR?&U@imUGR7OzN^9Xs!!LQSm|I~ zF{}0hIylD9K@G8{+@+?kvWc=jof^_VwXE%c{R_qqQL`F6u~6mdh{madJ;rxi4QVgU zrxTlV&yzpUi!}FrHT?e=`^tbSx2Elz5(E(>1PL)nNhPHP0SReDL|Q?l zyGu%tP`bNSx?4~hwty1SAl==2e`^DJe9m*8_k8@^{8{%}Yi6#w=2|m$3g6vLU4AOz zqR8avM2F=7e7NSsLUYY)v(ZwM82VxMi$nO0!^lM4HBR6+qYaH*6z(6nqW3TXi% zi+#5RKvzo{tO*-*g@|-YM)!-POMuk>57;GsNm~_J%AI>vH+mqtnUi0c=ej>26YmD! z@5O_aV}BiW3Q9bf(yAGSaxZqU>H||(WB2AnQE#N>(2^FIK zWF4^s1c6C|OZ5bw&HZjc#r@2frVnM8hd+W~wY#TrkqGLfJ6+FLeYagYP0l>*_f-?w zy_!$aQg|IUp4IZdJ*ss(z5(bSE~zM)KdfN9r)#T>hTUzoY@@&0G*S0HQi&iAsN~=J z>PYN-a_Ve&P-e8rxqz^A$sb#8m;kF{<%_y?`{B&Q+Ya}#7Av?x(mK1c_gVz{2qX(9)WRcG__C2#zedxW*;*xa`w`VT zXX7SfchC>O7d{v+gxDYBLMMU-*mUk#oL<86lNeEI&`4?ZMdr@-%$N+o(>MQN!Jhs) zNA>B?)cAT-Pfhq(Y$#7{A?6;wYlOQ`o~{TFXjGG8UM7}=r#N4P{#6mlD@E5F5F_K* zEaJ#i40XML21au=8Mr-4lwAlLqDZfIzjtbu$MQ__L7SoHU>@|3Z1TX z3f`?->x#|g4g)eS`v2TK;^Pl-(ULywa){Mm1v{{eU+U{xkTDTU8YU38UvB@*=9)wZ z94J~H+|_%48pZa5SVYFFuQ9fr5dc#qlV@IVX`i?17u{$JjX@ z_=^taHOaT7hCcPA9a(bz9Cdjt}tq2DzX_eX@MzQ%n((`6?4 ziVBqD6#NoDixUMJzyf*@C(hF-h71;OsfEJA`NWTR|7r7X)tl}nx^%c=wij{`v-JL4 zjHJ$`>Skib`xs~8aG+ua?u9$V_ef8i7+>i@#~nbc9&O7LZTIP_3g%zAu7j6=+5pK( z0<{6ij)WtZTYOm`gl>eu6flsl1^#Bxi3gs$nWzR?L~8n_SJ)I;ANrTVt4=Q?#6QG# zX%xA%`Y-%pbgwPD`Gz19tFz>C2q<+=HBP)|K`m)Mp?Z==E~jDPGK~L+Dn^niom@i4 z`%gc=AN%Sg0i<(2)b9@@rD5~%k)}mOoy0F02a4@qj~dL+#jr|;Digm>f6$xKiEu?- z+9LdXv-Yp4jwByy+hXp4&Ih*0N1LFR-% z`mvmiuzX@q$)>PN^_}f2VA)@YbAp!(K&4qH_ZR9E?k6%F980)Z_HlakpN#f=+`V#{ zB4#EQvRinu*Xm`3P@cZc$WFk2HLSI-h8pv+SPngOsAyJGy|@V#dPrLxqzINk=X<8q@K`j3`+^8Tgm-m6>jo5m7RQ7Sl^b`IQKFP3f}JggzM145 z^5q@&)$l0;@i^muu41`Vzmf7dZOQB>LiK-KEIRgC{8yK>GZWoe7Skn@vGW~{nKp~i zIi9?GzHSUw3z{PiFR8l z+o@ZMD683A7dkW>JLr7LR-FTlk9xM>?HwvzLo8P<8-ZFHE6ESa1Q*?FZM(LOyKlBA z9WM$n59x4h~=Ry8;DOI;ho0x8y?mnT}y@2m3d%$?kn$ zWZrgm${B?f-Ezkf2)pXl7Fk-i)S3t{33g%LpEYxG*mm{xH%12cn~r!c%>yc03!!XN z3*F1CQkvTJjjRfj~3WfFSyiJDiQV-D7?kZNUm8Mk6H| ziv_^p&F3W^H0~bOFVYSC+?Y7b*4cG7yk(Blur&+f*gUg_Y=3C(m5Ay5%nKiNaE*pE zB7F5s=7p(W5y?I5Yk(_!eqCyR%Sz*Qcf1hr`XT z2>*WgU>yM&R=v*_3>Ikfp!1|K|D6st-jV8}0`)mjS#D3*4d?F`942OhzLP*^`8l%j znJIWLnsX^r=*;4CP?ucS7qzNIz^x1Ac(^f}*+?0C?2@o#BAM|Xs_I`>`t|?>JSqXp zxoN(01{j+VScPG8dqO3=UvQ`7eQu>xz0oyf^5Wmi$AUhf;j+!?e@PM)cFKZW9$)9x zeH`I4%@xy*naqqiaGbhJ?*;BXpp=@vii076sprXWMmd+yL4?Ade{c<6h#-fbtRZ^4 z6e?Kmv-qcxXdr8JYAi~@yLF>?%;m*W|IcBMH_&0 z=KsJT?xlm_xSlR~faV485(@Y;qd@Pn_Fb#YkPe4#-~&?tOLLc0#0FEyUT{pW4_x?gEoJAJD};J}NY%7Xqt8G;_{Z2LYwk3>0;F5dX*yRexx zu8syvb(DH`AZGx`%w5%3|WlG{R1ZUX$BST%JM8zmp`XGmY~ zF1cGBdDOD2jFRMn)I%e3cbA4X-|SMlzMB96Xd0;4-v6L;ol+G#772%hVact0%+CKhYk2H9p?7(xb|j6S^iBuku9`G0=7#0%)xW0uCAMP1RTOXoZHXl z$8U4ly}IhQQgf)agM)yh2^kC1g9gUHx1N8C0txuS(V#xshoMKlg_Z^#LLlIuYLk&6 zTb1hcLEHERnT$JA;TD!Rbl6UjXvYEh?aeRZV-t zx0x1j)gIjHQ(-Ge-K*c@oj!^*&xpTcwLxa`c)A}&?>dOqpLoOcGf*K8g$U~GTVR{+ zSB$+f->~d9z)sTnbC>+^MlvbfQ5!!^?)y&NbB8FHI^Q(d! zsi1=|Qrk&z4GnU<2p)=mSV?!NFna11@y{pr=uTMmCx0gP(2GqEziP=gd#e zA8eN{qEFExck0Q(8%4M7>IC_u+x1ozLn)p}lm&g(>5WTjn~(?2`WaH$102GRl~t?T z9=97{Nn@!`Qx7%2*?uyx*}2kCI=Pwe;~R;GM`m?T-D#nkt6+&= zF7q!xVCY*&aSN5LM z)$}*hc3>{i=gw+DkNG_Gb2A>Nt3X}jI1hAa= zg0F5+J%)PWL>E7Uk&7UBvvvF}&+RkY?(1I^0`8RSrCm9w7%RU8Mmx>uba70cdJ6q#~ljl4ti7#o>y zkieU(P9HttM2Ss>kbj zqo;u72IT%Lc8VfUgjJ8_HD!l)-~DnZ;B_=Il%IqEu+~Z$z|~W^tbS~LgIJKp?zVoO zeGd0#KGCc7qGvAXi^$d8Z9z|!Cc^FS}dP0LLgZ>rPP2&nM)xtX!JW`0f+iq#*WO(PwNQ% zOgPUCgRYoMs@*Eq2D)VL^=>W1D#pO4sB}rgPG3kWSx$J$33ZWF=Eh+;1gNU&Ao_zw zG0YH%_G_S%nQX1?F(asKjBCQ{5#bb7vsofgfZy3VEn-J)wnKBwqsee*uvMT3AxP)< z5xd~f+YRAC1%F3Z*Q*LTAhG;P2|(Ba{BK*^>~^T7ZX(~wv+J|M2hwwhFRYCD_%ujdFuqd3~r{dkM! zo;J5W%gyx)=<@QCTp^nZ{G5);KB_?Y09C+ei?~?oiA=o$`&UylV@ezL^eN{&?* zyn6dl?`3V3-jR~s{efABeB(aUoJzOZI2ZV#fK#22_EDVGpt?6COmnq%ShO_Gt#jW_5h!t*n`&YYF=2SykuY^Y~zXJZnxDi5zrSqrhIGg(WksO6#D` zig>Hb_ZYPvDRX<*Oh=c_Iw#kBSOXC^!^8q4e+MBv4y)pHD#Odmj9oCnEXt$_C>YVmyLb z{f?jchoG>5<6d>wMG39V77aRSbST5~PV`IAxC~4{2}jnc{!H4t9*YmQWLIyRI45~U@l5$brus5+!5=cFKmIP`1Bs9 zqCinc(Ya5=h$`mo{Y!evZ(_K2|0vZnu-3Mf#fQRjiw+&HLjl*htAl+4QBbrwLg15M zS+Yi}?DF1}U6IxiU89Q_ko20mB(-GfxXOCGCY^U29_eL8Mjn7Fd~6_rVf!69gvZwf z9!9lNGdDt2qv{dAj|PcL{twfPe5CN$DaQK1BWr^+IV;r~d#Meym9J({iF#@nQE?TQ zi#K6bQ~at@)YD_8;B;szTj3|RriIe@Y@x#Zcfhh*`I07pZA6?Rwslzt(z|a>QJ= zw`O57@@O;9W#R5Di%S_JF_c9IJ_zYBeHrrE0YKxC*H#rkIu@?}%}8WFun%C{!4FfS zw~5U;{CRUgmsj9fnj#gwThs0Fp$v5+hpGHr8%BXlSZ#bRrIOxO{tWIsgy^w*BrxHGi!hJ(YJyT$JY41L~s){@D(rV>+yc4)c zH+EJ=h7P__!G~s@r!`2bsg3uxVP!4b|@7qb{uzVcHmjC zq;=Zom2K6rz0Q7(9UNckhIMRm*JVf8b9EBI{YBP`vphlGkUZ$u_W!f|Bnrt0I>jVo zY+hg|1-G$2G`jkJ^k^ojJB{(CxD8qJ$3-HsG$N>gWkWS&^!OJIkGl+KS79 z+tr?lHG5?%D!R>n*s*~=R&gsTBz4rraGMFeu^-gn#(+-Af4?y`YtcOzZcZbc)F_bL z->lgBoWmvQQ4WbZYbpE}fa#h(|cLUZ03=wlDKKYGTJw_X*C6&0kGM9)8{ zV+<>@mPUnSc&BYHi17vTDMF;VKRL}Vp+e#1t2?m(80h@+Nf)dP5=y8sqGaO-D->6~ z_!MQ-<(!Y z9kO#12S?Cyb_85GgYj0LGri?&1!g88s5TriPU z7H`M=3jXgDH!YiAUq5xQsoX6%yFCxfKhRSkChltqVRyZJuko|1A__b3hS7s$&C8o9 ztlq7e+GJ4DRVEg;&qc322%X)pOKNUjz7EOzIhh{4#)oL5$VVj_o7^G!kAu$&m@#+? zHa!LS1oyVv^PCZ$T(i$^Hi&Cijam)%MQR>0vN|+I3hq=}Mb-|5V?#1m|HN z26!FR-xa~B8CeO`RiHsRX(tBnBR!$!QtaQMC%F%MpY=jgr~K5)v*t}=tR*wXNoAG! zZgotT03%s0sSo4tkH_pY^(oyQyTjT^eBO2yRT%W;c8RR8`ZDiZvN9mD5_HAzvgSG8-@G;rC zsa`5xm(|f4mf;yM=lL$a%66?xiEd0;w{5Y=E!pFO#2<)GlA|e!)lp}k-8)beezMF= zgPq&f=-h7Jo`RLmJ_xDq(Tztakba0Ef&Vj5jkW2=SXKUt2FZ;(x>{jE%JUCAG`5_~ zf_IiGw5}0@8&Q{kw0Lu9lqJBQf&YE5zQTZ2&_?hj2YnMa^helB5pKtMZq6laT-S&O zYPRhVR$K8@74oE_5kD(z6VLZEH>}s)#NsJH23`|bg=H{vuLZ>$|A?HTN`VXoQEX0o zs+aZ@D9}RvkGrBOX%;sZIgWYQ^1P+1bz{8W67RCx zDO&ez&Sc&g>%)t`^jt|kXCJRhX!;AfJmFbjlPQJQ3dBmRTRG7sW~|K`T4TNmA2S|! z9Xb57Wq1c_1s22;SI!m1b5FVn0?-Hpk#@Y`tnqLoB z!e5`duI?9%yV3R^`Fo#Y(j6T5`Iq)&#@ymBlxbBGfO*T8SvjQ}fF}%U`qxPy?TzSp z(v|Z%F~#RT%JTOb+oq#HVb5J%jf%~5s;>2|2f%f=28~>AR<72XVWUBNf@iRVR<%dV zT68FCVF}^;usdRtDjdCpZ-xI5qechOfsB%4E}!^ztCyO`_Qr9-2NXhJ!+Tn?{tc=` z@!LM!b;|`S!AEAnw+hkR*Y&4%e#1$qgSz+rJJ5rnbNguKB9s+!0)gLa-c+@JL@q{@ zt`Jt1`alPtMlg@aIsp9B5)3k}eU#w9n)7LW>?sP}-iE?~vXO6LwVUGmyNu_xLw!CqQ_k)D9e}(?fyx^Y0kW*ib9FKhLxb^YW2DHa<$7&y* z$AX&E#-gRuppt-)$n82oyb(%1@m+ zucEeHpPB(q>J8AW^xKdS(`)QBu?fwX7|BBZcc{;=0KDwotuw@t{KAo(uX;EK=8)l8Ld<0)>t7P*8lg$Kc(2AEvhW;7lhs7L0?ub#`Nu zD2`p6xKxkXFH_~f4eEJL0x>xV#3D?W+AjMq!M8-Ic#ezsSRL05S4VdAbkGXSYpta$ zTfVeGY`R>gc@dx)Hk(zH5L7R7=OIxmgv@cxz=ZQ#4EgU9P^&f=c;6>JQZ8qSyMsq? zhZIb61~59;QBspyG0Rsr!8RRgrc;8eBdl`yt-8c&g7qq<9#e9L5%f)2bg&2CgoJUy zBt(t~x!uk3Ra(%cO7s_&)}=HMJdn3OY=#TtL-n^U&fuw@j$U=D^uZgJ44>->+|J7; zRER3`mGOc5Do9+4P5#<@Gu?L#zCoqF_cO0<&!E<#eI8)y{y+duZv6Y_SlakkGkZH4 z&Z7^;8wGsu1mbG-sarQHHw0t|_&u`hL|7M*V z+VG4Wkk8-dsu`bTUwXfWu01V%`>qlHeqkD+LA-tG_rg!Z_YlzPQd^sPM(bOheIIJ69`% zO)*_@J7l)mA!Uk+sG%~C@P4BWG4&3;rg5=!hw&b~H zE~Vc3PY1m4hGjnfKu>79gM3k&ZKV-0hS)RyQfp={8*? zdm+H`2pc4p_5vq}zziC%)Clb20-c)*E@rw>{bV02k6Z zyk3-_zFF}5RHwZ#=57qcLU8Kbt}Ew{qGkpMVqn#*Oo)TJ z(i#m?@^1`1Y_ZRWh{yBhh~+#C1Y=-Tp70`qx@$JI04lO@IHlKlrO#hqE!nj?=r zm$KpQCcC4I&UjLP;4`7ZNKJAlbS2JzEj)wh7t^fg7~U*pPZVQ&B4eT`L@Az#6eXxg{x)fEYZ z(L`h__whmeCKt0C!r@-n2QbL#z6Qs}hwB(T7abNj*)a--TRFDBx3LRg>+?2Q ze11#|dS5x3_k4LkoE%{Bb(0?*0&;OmzLSjQv4p|ywg?2t{sNTdx+3osz6(v|nI3#@ z4e=@QCa9`&{t~oWz2vD?zSzTHF#3YW9EvpZ( zytawkpA+rI?SD!GVu2_!i81xZ)Mke9EK*U1pt7y3j5>=~FTS!Hr2^!M(|jzRl$Xw6 zm7Uq5lG~nH;wA_O=9&Y;%7E%rhBYn!MRi6=X80kA%~)`72Ds?Zqf@U*7&%*^@!lvW zKGTFDe?sqm1h2RZm{$o1BGm->;WW}zP5%@uF|M6_Z@r}Zj*c9g9d}8#`SF;rn+sxK z3yN!_XizMTe4zkTH!Lydq(174aJ} zi9Fh=$*VhPata@~ZLDLZgd{X6{>vr)Vlj=b{bDiWqil5=r+x^QMsM&^+yviqvg5v! z88L#nhLaZFdeMm+#WddYUptfzJCvl=^dsK0)AWuy0S+#7P!>I)GxYX~O+=ybHDFCI z{^s5rIaSZ2LiB;iv;@r8HFsulUQ&-u7mojyyk)YRJxh6k#x@e(h3kg!-z3ouzSWop ziUmH6|K}EiD{iv7=YH*08kqJ}Qgr{e%0utY7EFhUQBYsRR_^wxsW zMBD$h-PUK@ZGL}aiG)dVVopEwOPeXbvLiZqkx~18uqy~wb&PRJ^aXkY4YZkfh(qr9 zLs;ET_N)|0opk<=2azNXz=P98z}VkkwO^4=)q=+dW2K0I;q@8=YvuIV_r5)jFu1DC zWf|~5t53FPkv7RJQ7EMvG-V$(Razm0>4J2yRa*|TXr$*EbWbt zoY4LzbFFO4BUNSF*+NHUFo*e)I?GX`s}+mS0NmU+9@hL#J|m$Ym_2>UIrj-e+TYO( z67%YFb-@<};s!6~#eQk?n+L_wGy zZP0d}PWgSyb}Tp;LoO1ODSD!T?OqPxBiHT^*)9cuWbnK$W&B7#4hobNc6Phgwkkcp zL=b5o3H04%I7E`8!hjrIQPgeDcR^-($iz3ec0!uU3C_@ZeU%)Nze8T8`kU|9rj4fk zU9I2*bCyr56$zSE`D!-H(`q+0;BNQKZ}9r_(1J1Dz$@{&`o}JO3~!=js6VI_o8g>{ z!|AXLDA7+?Xo-?v=I1mxTfCmr#=EV`V-Do>;15y%PjS*s6gGpS4>%LP~aa zwK7!c9YRoLA|JwdU2d6PC0D|$UfF~f7fIX5sxM|&w}WQiBL8l23Zat2sO3V8>1LK?kKFa z`Y`{kRjFBQVN-B*pPx8{NlBAi=bV~;JZQP3AJ%_+=ZWEP&^c*b+&PG?<{w=c=?UNl zhN8VUb9L{aRZ)9@7sg|f!_vpEsJnac-mH4JB(iot$pC8HKq7!KpG-(z@c-j_xyr}T zRuE-~vP;MAgihI)Y%1?72c9OpnfUr9hb%WE(DiQk27p4MHHv8#XnJ7D9F4F z2tE>THPc%`>SDQcdK;rg{Q7`d(W}?H^HVMLyO!~8?>Apmh|T-2jF7h~j|BWe@awW= z0^WL@JtXzPMgHM%RGHe5%mll&Qfb%2QF+~6Bzlze(!nB6U;z{!On~O@Pag`1{@vg6 z_g}0vj0{X0KIQD>`Z|?%y=C5Uw13F7T!KZ?x2db8ROjlS(nP&2*6Ffu^zWE!k@Ac2 zN%JX2$tIWE+Pi`J}G=x_7W_*j=M*-rL)?WiW3O`J12w6vTbpT-8|Nvmxsed2=IhDTo)8*qm0fr*tJ>MgRX~IxH zmFLT};}~VBvuY|PFH;D>7CnqCBdHOO zdij{iO7}d($@x16=h^J`O(D;%kOE2GV`M$9oZ+grqcvCOeuv5Z5H!51PnVj;o%LWr zc%v@+;j3<6^%Iqmvm%uLZwvrn)@U)w0H`xfsj<1l7%s(_Bs`*LdZBNqM6jK4!rCW% zh|lzo%`ho#>4~s>x(7dc)<-MVOC63HdJCpF{kWH_jwE{DMZ~ymQVkjYgYl-KUIgAS zE1pU><)51tq=(!OPO>;;{c3S;sa6vUd;u~|MScOVG4JtG0#V!%Q+K3h;sDR$dztzxa2 zY&#}M#^!dLluOu0av}R6kh|sJzg@N1Ce*4MSM0|#AHVy-5|p}_R?zT@0Zd2-6|59` zSy8J{5%26UgTQnqcI`VQA`S+Of#E!sd(Q9aQxf!U5N1WrqD?Ba_d^U@ z9k+bjh+B`MbU$*KHiP=Zs}e64^l-U{R3MB-?Vwi4^2$5k{h~iP8sPFG`jH_)<_uke zW!H3EtY2?eNGVaqPJx-E&M>S*clHVJ)alhhPk=v2C1>sAaP*DwEKmIGknjKlqHR7p z>U%NPU<)Xp4hbrM)AE^H_aI2G6VxmwGVI+Co;a_(!IPSp>(V$dr6H-njks7@PTVx` zj-blz0JF^X7zCohf)GWQX~Y4EkR{-HyjT8&I^wt8jykwa?`jZ0+O$_Ne*14A<37E+*CB}T)9Kej8Q+nRRKSTiZ&`s7-1iPMkn#kbkXjdpGV@0Fozrh4zmxdCzY`Eyp%;l5@qrhK zzwEuOl<*7$p|;EnWX>t0=P|Nz=-+_TaJ6{ZHG;uNH|M8h97C86bLX?K5vYV#OwxoH z#Y#-o!QR`DWI$$a$y3PviIQgXR-E%?F`iG+hC6s4i3Yc)?o~%UKj!dfk^&iB^e^nU zy)n4?eJ*1$j~E?dyM309(vRK5TZw*$TEBN9qzDchs5wZHb|lbgoK>Yds6U~(zI=n^ zQ9z{PZw3W4h`sqOLm&#o?x%(hH3fqdbQU@J0ts7fSn}1|3hxaNUU z5Srl{{pUepm*)&^ge^+jjo$8gLs4hnh7-w;4K=fb4UDX3AnfgUNF2WGSyoV3M{r?=hT_Y-_2a!&?4aXYUIdm(_OxHB5e+;k#xT>IqzcZovO+Z%FG| zN(ADW;HDpRF)_@x_mhlM{s8WC+d*vxvd_oJOCkFRMce*2+Ng2f`K303WT?;3#==xV zmn2u76PXpB^YJqV$SD2|lD(`0@+k64T)YBy^Hp3ekh}lyIQ>7rYXp1gz>thFV=|jp zGA~wKfyHnBasnE=g_$@3pvtQ(ztz;U5NY`chza!YD-^ZF=xC`)${R=<@&e!?O+fLG z2NMrQEXkG&0*QLICDTPC1Hah@(s={5YJQ`+J0M@Wi$?V!xuqy8oF+axjeF<{Q&(Dz zr$V0)5$?H~;>6GE?-cn+cp>46zu?EtYNad)fA^6h0ucTn*Ig zqClh&@p;EO*3yB%Kuj6y6%~>)w_(m#XQ-7S(kd*?&ohoo$6m@xm*3$C-J(SB&`wn7 zQkgV8>QNQx*yZdgFFCqu;7U%oZ2k2eDkOZ&kmspK#A5tn+R$nLS+-N!H}cWm2vaw{-grRKI5dP?|Fs$MYVfHF-ddF zzSUmkSL^AIzkM#E#~Ob++ENm7XV8Xx2><}~77Gg3ttuAc3*F)>!F)3!Z{EK|_0soM z)lIFzB$9Mb&D*3~J)=n^yHoclq*fzB?DG|!BdKf9Bnz$CBriAi>&EPestp&o0@dUp zVtHfNu|aij^mwi4QEdbQTgYvH_np^djs4g5##Lsbb%FI=r=Ldp<}Z3>s>>CBkid;& zLq}((g%&fWLz_!Miu`=wx9=aQTjT}4zhvTcYwLf;4mw-j^4^{F<<2FE#2q}0CzkqRNTnlLbn2gw>d zH1^OKE}Ny4dk-8b)fW2g=aba3Df~tcUg;IMO)!H1`u20vx8!=3rG@Ohkg4d~Pma?| zQTblp=6i0~(?;-IF7B;t&+5euk?TZy*MptJ?1Ozu=(#99GOf&Nf;U6GjhOoo6fpev zn2|+u=2U6>GYsNaZj9>~xXM@H$an%Wg!OQoWTkS;pK({(YkLbZJ3=SzA=!U8D!7Tu zcIjWu%d7|KTnV^0za`jFgswfkf+UK2lM|m?uu~4aO_(YKUlo{m$cbS~&N+`^t9GY_ zSj&<>h-koj_o^XVHeflwD$g{E2YXBA5lU&Ne|iAJ00ZFlf#3a*33P}&4?o}qz8HP+ z+%Lr(*xRJ1GX#mh{0+O?4PdHgvPof+3Ls`0Cc5pJ9egx`E3p#e8vAF_O9!*z$Q@S7I%)`0568Z{vIfVm(M;|C_*Z=tfBL&ry_TYjk zG;$#GfGcixuI}N=rQpUC1EX%~mF-crZSe6z&37ee4$)Ths;~!ECH1POtE@1M^YtNi zGAW!Xa@J3mDM*4*bHR%fT~c{JB3r7R_Efj$HuTF=27PX3hg+w8NlV2(>OP+~P%AZ<+Rfm16 zx{iprV%nT*Wg>C!OH=IFI=TM^t`~~fOMu!bJCOFbU=ZV@w8m_`rsC63zL;r9F{3Lf zU-~G*I%3kJ!Q6+I#XpVnv7&C51%vU)i}(pj zSAs17-Oh%+!u6|bX#`dMng=tU1Sk;cUzFAVa-rnSs8u|Eq52W!te&_yG-B9G3sVm) zG=O9Dlr+2w_tP@2-KVTe?$GvZ0zidAD5jv0P%44Fr<@Wuf-G4^f-E2v9ME!Fe>l3z zy#9IsDxc5wuFbUXS{&^bA`N7ELRUYBWSP%A?kaoNgv=XgC9;D2@qddd|U({kadha!-id<=E+UbPr zIx(~p-2z&pH;dR`Y?LQX&I)NrT{H!^r=Dn&1W_exe^B^|8%&ViUL;Q6JD=$%Le#WS zPSRZSA^sv!ze0t)b|#Vkt?dZdtU4OaXJZ)vo^?7E2&QppGOlX@HdQ8UX26vlf_NVN zMWPrGa+Zv)n9n1CZ1FoR42}z3CW@R5nG()uyjo)$LrpXZ#h& z)4qr$lmeuaB5&L9Rv(m{xek4Q98(9Sf6Djn$-hUCxon^P{->Y9i*yS96FcS@=`;{aUcyV%l0cQ1~V-V@{2LA5zpm(4O@deblpww+p%NqX1p%XUn z5HFY&3c&k!4*_aBai1jz_@5joe*~}`fTsrWy&h7xW2QH%{+X8T!xv!iL}%$OtGb+e z(^PSd6Zbu+Wy}cPPW+fpirvN&1Fk#rTqExcC*Tr3T7Qi=mr8`4souU?rxO%;j?P)8 zeY1Ryl}qG$3P;w@$KhLi$@UKk=x9G=dzX~tH_?KAr;qfFK_56anP1}D0!=}uTCx%A zyDP*S3n|6|_j83xp@@KUNO~s(cCX#sJdJ`mZyU`-Md99g)(& zwEWtcPZIiRP(Tbp)xpa|$G#8{&8q*^3^l)>#O7}8>~5*4(&8(n@>yRgm~2Gu#RRrB zOAlZPP%;rqF<&X!QmG?2-ue=GUe^<70&86tY}jo-wxB2TNtC0JhiWqe&An9pJscNlHYXfz;`;DpmNabUMm|R~q-b2^ z@SB>^E+CYOL4n5o8vLH7E9vgdJgSEvtp9YX2QAzE*r-XgWMA3}U(3xVQM>IoBs%^K zTs>ZEd-$V=G~umXi@;A-TzBG|iL3ftiE)mkK|2ufj5&oFDLL|;g0OX~115_gB9JcA z4nA*%IJqU^tvhuIRx9`Nm5eX4+3k|JJVGjm2xDNvcJCj4E1WF{)m=1;Q<8)NGRQLVeZuz7Ebx)NSxl`3b^D%dk%rXC&kbTQ#aRHQ!dN!e~8B??hP)=zV*H-BZZ3V8?~a zRrZ8kDYlXH=&FdHcF1Qn2}4S~l(9hyliDTjltfMVVO{OCxQB7Q#OPt^90}r!S%jb* z|N7oL8qez3rjbTM!GH-T6M9new2=?pOd&fm!zN{XCh9C!aTlMfxzPq1R66_!KS!8M zpJH15?P2UP(`whxqQDHbL^?IV(a_D?REg;X=_zC8yr9*Lk^C`I{5{$*2G+;J&9ae3 zygM|)&+eAr^?uH;4zxeqzN~pslmomYDf&%&7P$4>0I3F#KTyNgX%RFMoBF#omYMOX zfaj0qy6}VI&5I|5nbrF0s6EVx)n)UZpA7QJ0=^q~OraTq4h3Yc2_B~afolS@dg-$s z`ovTEOr1W^;g|$I=N$r_aZJ9yIHv9KDGXcXSs_Fw-hJ3XEMDYB4WJuISY*dw#PB4!^?EeooS@ z0Bd$KFva|--p@x}bP=;f=^T^~rt;+pMy1b5^0;zubS#G1JZD6pK^X_tTIdjT;jdhN zDvovRw{s(7kuiqQk`p~P#@L_d4p-PTr(dl@r5%9zcNiuRw1yv`h z$Fst?6Niy3f|a_R`l%$ zk_h?kASVs)hybAXnPQjYSD>%CASOFvorE8GUgbXEG;oU~?mWH~(eq3jKJGUwm&{K` z#=Y12>32V)UFwPfL9^kiymfgoi>l9;flhwMTkIPIH7~Gg6-@E@U-f~3cs7-M9H4}$ z2t^que>Meq$P5 zl0{grP)j{)D^t|px1axJT+J~=kL`^S0A9VM#?vM6s(MW|OUpnI9}&LGgVC-MBI z1jX)#sNoN8PnpEEs676ic9=(&UH+9eD~XjHEi;FDbQBU6S)PO%0No_C*g%u zF8#`-DUBvNCOU(r!aIYi=Czyjn`KhKL0n~h*BY_meC=J}Jc*d|GeYZhC7Bx-wvCB& zkAkTj2(ZOe+u|CYPVC(a%%VxUjVHQ8Px&3UNVGAJxcBa2ey&2ZkOBQA z4d$o-Vi{DRc#B&@f#fSp_-w^7^=E-p+{x5>f&;4e1Fzc1#`caGyMTUyjrU7y<`>1s zXH+$tVHkJ>X;8N@=>j<0R$YMH2KkABw);;);m>=JY(5i^H(Wj=gk-1b4|uBw*Fo_A zCc-YQKJsZ&hMssnQ<8#fGP14Uyc%$NLP#LMvH+=pMIkq@}y>4F|FHe7qGvlGcPX&78r_rL0n5pu&Eb09Y+m>jRcycKnt3R+15&DQ^M%x?OPFG7Z z&;{8m&`DQL2)IpG8|~XnKIXm~W^o6%Icv?8vX8UDia#z>#`2wpeWwrSFaRc^x3%am zsjz|OuHwpqGBXN|zMye{lJW0!-l8kgEYNfe`4j<)y9N%e%x-lw0+r9bdp^-R2FE&h z5-{G~%!^JYj%zESG}sq<38j}t_kzZba&g6*8yUN_UN`C+fr?tI-oI`f)v+C4>a6SH zCZih_7yT-YC$+KdFz}5c-H~2d=_#*&NY;^aO$K91?w^qMTs{K zqe6~A!BB{UVGg!~=H%#<;3C^-srcjJ;GyaPeuzh4F}md}cl0Ktbb zs4z_^X=BQ~Pjua5d9DvBgX+NXG^4FEo$DC0*5M!{Vg!xr3gyQlt<4C`G!O|HjfdeI zVBYyk=zUIOFkAFJyKiCCgghAJFF^ycS@YU~ zxqbNlV~L0ghu* zkg|JC?tJxao6mQ|it6MG`_(H&4~{Z4e->nU9Xjgi(5T17M3Y_;Aj(ri*T0l$`{8CZ?+sl$&C@#; zz63&NgXDi3PtrqPT{=^L(KEhD%>SL=ScuUp$Cvw5!v-eNV*fnj_zY z_}YgAf~cd58+Jr^JIf{H%;X%ks`_bM@MT=#N=4D!1)vYJcA}Qd=Xg}FtS%v+Ak_Z} zZS5|Vb5)8NnKf=X56E(Tnzw%bCY2|Rxv7yi-Jsc|oOb!tg{;Ga{-*?R7tZVGGF&SB zpgB}~Ir>!IrNXp+XEE zf>D7ixX8;#PcVNxVsTOP`>he@@0|0OjhuO&c#ougNgJ4Z(=jq%l>fGU-~0Isrlb$w1N-W zAOdG4#DET${#V8P+^*2gVzIwFX7@Hk>MKJVHN5rUOYIw{)L?2)+UeXiV{_6$Qaqp0T^=>sCNu53c-(>#SNZdT}|FFt}W^b28*^o#(1cen$G9;W65S2cw;KS)A13 zu1LIt6A0labllEl=Jx9G{W4FGan4$|u)yg}oQ&k|J&vl1dwu4S^w)q3wTTC_Z^#YJ zA32e>ZtXK7*I=5VlC?jRRnni2FgV<+9W4^(7X&WR_DRZB$=_es@6Cb#ajN&opBbGrge<_6v{p<1@!pz_?|iMc^l4ka;RXQ8I6tKF7o!y^<|(<2)< zMuGx+y57WR=Zb4gKEh1v+l)Nb6Mj(Mp19^Rj@na5gDOg}1mfnMk{oWlgc`;E(YiMe z+Gp2x=tUW)%&$=v6*+`v`5hFFQPGAMKOBt%pV~k-{x%wcoB!A_l_z<02ZE*q*GNbl z*h99|(>*XQ>=TX**qfI4rdUZtuve5T2OqHrZ^+r z;CAN17eakcLGcayUPnZ-tdHW$xnL=lj4C73dkTtTyfc5Ry&ccj9WSTV5TB*m%9ru>;fYgp3G7F<)2L6+9Pm+9N`-& z%O?*~>T<)zJ$)SAb$}7wZEMl_@H!vg5Q9+lpap8hi&Z<@RbAaZR8N>kS?82X{O6;z zQtg`IFIYC0L-9W?2Plycq#+|K`O0c%%T7aPZtNYUvyOMbbqP{53~eU$hKA_Hnzu2M zTwY_oSgi9D$r%pdJ>>eXtSfarnY1X(=%B^Sp}?w6FT*0gJ8gxML%|iTdg3XV;Z&>j ziDqZFsRM-3)QNLoilgNFNl|c_uIcl0oIjO1HHS@NffJtqyfVD$!34;ySb#VQKFSIZ z%{_TjVB{{;*2eS1{GOG~XJJGtdUI9Cy!Gun@s?RJM$JD0w#$;9!bac1eXMZonM;^f z{ytLBpy?>SGA!+WNN;V}&c~9uc4FUU2TM0AT|F@#C7pY>bLxai5FQ1^poKDUT}`zK?cEw;*&B&o$E@#c%H_O(X$GF5ek^6N=xX6-6jE1AVh+AMTG zzFMQ@--%@neJq~mZjn3_(t%p~-t2J#>EoeNZ5liWZ{L}Z{n?KecpMCmTavPV7`%8V z7<8qbz!Krgq*5Vk%jUiOeCeycQ99e3hJx}-bqI0^^rKxF_mGvHD%2m7un7lq^9^!#0j#{;joV>Z!n zM%npSJrOQlB?WbaR|Uzr$1%bizDxe|vczmuK{m=n9(xGuvFya_j*1JONv0@rOS+O^ ze_mr>7WDI;irvo*YTxHEt^xf9<-fF#Ad%H>=@4t-c;H)mKm0P5k?AxU!T@j`Ja%*y z8tx1642{kAGU_e%D$CXLxD&oDOA;<9ak@~=gn@n24Z(=^=akMp7AjP(!j{!KvYwDL z?{+Q_V<|`$ps<@|l0Uab(l-S>%I_~86&r3>siW66>&;GdB%rKl1XseSQ}fE}Y~J?djqB^p~Tx?lmPbsGJs5;n)^ibD=@Y zsp#a~w;+K&FBKPtcISN>_pv=E z*}3tcJbDS4y~>!KSmA64Xqut(KNTX%=alkimX9Wn`pN%?4QA7W$1*(Rr>F7h_pe-; ze{FS+2c*OMs`_E#K2J%mbiQjiN)33jf;|h23Xe<@bR1FkC{C}uiO>ANZUNmDtvzB4 z&&{SvdnYtkYsFnl1UF_wpR2!%8?vvX>P+VAaLqV{nN|Vkj!ECf^^@?EO`E>>c}ioQ zwCh=+@BQOp@PIyO-TucpHPML-ijF1&)=UCdV%0~Nmm%?E;z#jID##P=;1Y3o6fekX zbNb}rxwSq?J9iP?@P(H{Ts)tf@4_YfxQm#L0J1z{bg>51LD7;EXZ!omgG^D($(^6Z zw92`?#a4WdMGqs^2LEVQU{M(0{^`iDvD#e%RNCm#jbp0m~C-BKzOaM;uZWP;_)DISR^QD`cCA76!h_cvnebK7%irolm{c`G| zy_lkubpII<$C>eWgg(84=1voHWJu5Ff#t#8Q*#IR0V_>+ErqxM>cIl8+rGX-<)ql`!Uz%^2|k63n2fja%%R=Rt5X~iO%u zci>$L)&#(T5=)nJ2s;w1qA%kDxRuO;ylvo?pL{ia$F-=E@C0T3?D&a1uoUp1cM${F zmw)tW!!0ujr}uRnxSU|Ud(Tn(blhyvYiaun?EHC-_RaDnx0}2Pc-+7d*50A_MJl=! zNLcZ|vzD=u?Fna9N<`U`7ywfL6aX4?Z62@z-6;A%Pddng%J&vbHJ>mxy>rh z%X5F8@ z;r-@!bpjT%Kkg|z8ESv`s*4K^JTRAY`o&?!yL1|RE2dXb&G5Ei##Ks$p|(Y__onvH zplS~#B5Y*i>hcnbhGkfSzaZ#{GQj1O13~S|e?o1I37c;OM|9WezZ}soTW`$IdmEat zM7-6Uy_jKoNwtm_3*qMb?K=@yW1#xKS9OFMSX zXy$W3FJ%$rt^Q1kdTBOl#m89nOXeC)WmlqPs1VaH|89p7BwiY#!LScMF&CA_8HvDq zmR;c12sAUe+zzHnDVE^nKIa|r21yvXs)={;#kBu9ckfxF~dYAZEDIXqS&!sSJVW;Xk``#11{n-obB$DZpB z%FkMP@q!?M5#6|%)>jtLC|+ofDGXM4PHnbf52*dD_*TDG@>4O)N{?1Q1!cx~u#Jz3 zJFJAn+f|$<0f3<<;y_POdbL4(fNx6pnVmjQB?(us5MYMvkP2LJUzx@nS_;FZ`j(PW z)3aNdML(7gIxH)7cgHbq$#;Q9?nblrmZ9B!sp^iq}rqS0by+sf7JMZ5RE38R0NC@tG)H-axbx^(@{=N zi{i1VS!)l8co0bsc5&|hetrH;I0>6r+`0F=%I!Z#%%rpTPIPJ$NR$@u?~iB=f7V6d zf9p2A{J1)7lp0eITq7>3{cZ;5ofbS@kl`(}fFc ze_6&5!DUpvI`#RX3G5mLV*2&p`dXQw$ODYvF;k?nF2rJ5{`pgqB*TK%^{b*qb6C7h z9PJFCD4ud~AnS}_6i7 zbVsipNUXyL{34lb{SqtPHl%@i(oJCpVombTvA${=k6JXK>fkqo0IC|7BeGr3%Advg zz<6ix5%O7KYUFyholmFhvE4D707Y8kVbKT<)62PYQ|BFf2H+Gu&Xl#G&r#~KqzKU6 z#&a;V>2&7FgNp#`w8$N@d%2!zg4`tksSwEP;FF_Zr$mUL2bXI+;%@BAF6UPZeCEnvJimwg`Irwt^K$D{{+>o#*&f@M-#b$@u}`jVfK+h6G2i zl?vn9Qa4;0`mxk>O%spT-hJHHJj06Nb^3t5;^8zHL+v*1)BDn8vcD)xdD?UsE=}oTPv=BS7AosAndT|0 z@K6glUiaa?cvY^Bu?_DyAH}~BBA`M~IeFpBW2+T^0faL|S-&-7nl-RFk$|rW(%L3O z1(=`cCKRhho)WxUS3p|*Wx?$>)EzSPIQ>%Q8l^L-)ZJTz9~^GM=?J$tPe%fX==%}$nrbU}FE4lk3D(dU$GzqE zXu2@Ru!RdYQ}GKG7W9c5k{l7-Av@f$j zaxb_#P*@^+?2c#mlq024C`i?T$upFsaI+B8D*%J~H#aQaU7r`(%lvSb&StFjq*ZV&w*nb7ny{JrQu{a*Z-FvidQW|HHdMowUVx8ET~Q-=U0SGRLi|boWZq3Z`TqfJ5M*{56fIJFEw(TX2u-{b9WNIb4}vIF6SxVh zkkKgS18*b8Do!3!W4vs$LA^~*5Vo=2oEZo*or{gW}MC0Q$ER#JtsRIz=~n8o&3l;^n`%Tx4d%li(M;+d zA!p;B(Xp?NWkA?i|1GfVi`vjbmZ!xFsf*NCmDr_7-INpeQCU%NXSU#(T`H+m+`-2$aiyxRwb8e7+U~7m?VmoH@ z@{T4klT_7R7suDI3*ffZSKd;7bhN8Kb&J(s=cv=aSh4ZE%s)2j~7FT>kCK_fdz z(3QSUCORnw_@Mg;I^3yG+!+ApYiHYYFj_6Ts%mP@To$#*1DE6Na>Y(}elK};j zffUH49~9a3RLj~bTsx2>*^W(M)|?M!M{_vigG%Dpt^>VlO6}`3m9}TTEfiC?5P&`_O$6i*?mu zJ4n1$TL)`(yvLR#nlW#_s&U^{%7f3EWK1N9R9h$nUkp!(n!^W)bPRi0eNO0QMLOWja(nh0ZDMN-G@ zG<_pT5g~x^SI!WDD)X<3seNz__ZpUJlz`uc?1nR-Z_g5mz{v3*Ft~{ma2?CWOGBx%+KL7co%V_R!hzfeZ?%quDfOCCA;%W-_jn(C%?CN|n zW#fPMYti8AwdSI{N z>K6@YC{BQbBtd)`0-WrRt+>L5fi@2a7cjq_;{E}|xL2)%UVATqQhs*x?Q);LN;G?$ z9#K&smmX^Jz0 zR#L20)eTqZIL{u6A#lBj817IHyCF+jvn#-(;NY2e4STuWyJ@33wYL$E`iv{zW~BMW zL;iE5;owQJz>PYe#|Fu4mSa+~Fy`$SxzjeQKhvBJkNxHRG`=l^aBdo;PkZr9PnW1X zX4Kb*;-H<{k(^`-ht)2n290Gb!KgT+JJMAitn8ZeSfD&@o?!w;HE8}UTE)=D)$Jv* z3Znj11x?Q3*Bc;WBnRCKNH*sKvNjG zKS)!M-8AavZK*p}Fphb=bk-&*{UlrDr-N;340>9t+BcepZV#6R&@OX{lXIT$A6T{` zwD)e@q@T;5u?4+MuLx;P1)={Xo&g%(1Ykn8(&QI&1+l5FO6L)}+=9p!Fx2h+Wb;gY z3*ZU$`2MVDIfdKKpe}QWCT$2LE}e6x<@wwo6*0vtWr`l*7|%X8f#;Qay4t?CwP1jEMG0x%OwYQ}`LZj2imhNRYQ(i%Rd{g}#5IvSt?##@x%acJwXhsB zOECN1kFAcEN(C%>JMpL)Iz>^FT^7l`iF5YjCPz08ub=6`#DN9$8C4ku?g{K0*HzWpRsmH@VD8?Ca@t- zx;#($Q31;Y|6EPX9`9-zd{h?m^gQ zZvE|*B%>8`Heh$i!J^Uu>aaB{0+$xZ`oIOntO@?juMdGJ2%q2=KJ=^hH!o5ndUa1_ z?H(dhLysn%xixZUcS9#y*bKT76YpmVqTkN@!61_?R{`=YZup)K&Ez~T>J<}Xn|&lo z=c6bkx7CYELx&1i+5MvNs{dSnKk8`k!(@Y_K*vDN-3d zvr*A`Up(wOB`LZxsv}2x2ck^6g?5z0R;RNlxq_d+(Xk4a_f&~ck1ou#Tzn>?PVK)v z-U>K+1Yxz&{afW_^%JaTPl3o@xd*JJkm$jzs*FMK${t{!p#N$gN{|ix&+A190BCzL zdA={Y@2Tr3DBR?>vVwIBCK|6-RVQ~vFqrCdSnA?*=XMlu30=YQ*)?x(bp2AK=j+IL zf7&V+lKBdp4GcR{o@wDjFyRTyzWA@kAR@145u&4SV&gu6?`2#}o>=t)36Xwq6NJ3P zYx^hElX0wFXLV3J+cH>OM}rBe9}Rw&5s6qBz@JfxZ`#ij-#l^nmh3H-C`5RMQogbJn@KiIz@AzAW~t6V876B0D_uo8r0swXEt+HWp*YvQ;3-f*N;5$HCD$jnU`rw@PN#PZcantniGAK>1l4_a#9O{&Y~eg$lhect-SJE=iEMBte75@A_+P zXJP#H?2M*mW_AE5))qo{vAl36V#p)G*-hnXxtR6a=iAJojgl`{&=jB6!9lN4`aGKox)cg?5tLt&XM3xeUk-QOW19L(8fB zzaKJ&1MraTK5E(xK(1k`d$|$t?}Kw7_LP*D6{zEv1msB$qn;Nm!5zdH%oHV8dUe$c z^k4X#X!Y@c`;uhuX_qgN@3)7Wu`%;j(3-8*HwH)as%wWGUDAqHdqq}k1r~)B2g+(> zCH!9;y>M9c?Amwwj#G;JohTTipQyKxA83&T^;hM7xTz{qm5FLTECuY`sOk6b-d)W- zqF48}+lmwOK&e(pex~s5Y@sCcTIMIcF7b2Pi$=+w3ywbuq9XWsxG*dU`FtED^Dk4b z$j~EhFMz*+h(Po=8w~UR=JrrzC8S?MolQxC)>wDJ(*qoG72=Rk(hCwgYtx}UnofsK z4PwM6Z)aE$T=S|r)_Mt3zG2+)WOu#FU-rL>Nx$SE+@pO;AG!cLS;C-k%xydAt8PmL ztszUK-}t~;gw9WHpjnemSU?dZ1E0jWHY2k*VQ|T((|fs9GJ8y$aSnyqb@J`RN24h8u*FU#(Yl%+cxwO_LNJyu^6bk5G= zN{;0DZ7^<}ax&~*dc3ylP?OWW%2ry5=Il4u&VEY;(a-c#(hzRLNaCJl2(1j^ZshzY z!{K^Pe+2yEom7+eQ;MgR2nL;ByyLtd*v*D?c9DEbjcIlp?T!$coG=}MRxqWr+i`9D zJAH;WLq_o8OnrrZ;ksL8nLBD$kM*|Za!}-BxuYxwo;pq~86z(wJ+zpOT^`NjSg(YG zY)nNpS<*f|DqWbc&;OYc%gFP1`wh-}Yac5kX$hq-`|?=v_!yQ?GW!Ia#dZ7cv-?M90@U`Po)IX1L$92x4m zbOb@)Q_Sga`3b(rELfPpq=xDKnwkR}We?hSQihQ}*A%oe#st+yC6FY*#5w%hZ<1Gj z&Hmn0&qDlro9V*Uo&$ST(EO5vJg&3JRn3kyg|B+^pAL?D*woMN?^IWRWa8iG*-{rA zVtifWqPerP$NG3K!DNJ_&kmeA$K!4bRvsrCU5^8@gZ*p4ZRCfBhUGj3Vd-%BZ9z(T z=QrX6^nEF0WtZ8}1}gcdi8F4O53?cLVi?-GA&UEvxL~_2k&KuSZKDjzQS$VBuIr;~NPG?;|3{^;%o-?o26601R~VCK{!WzBB3H zV^wx<3pwMcD5g6NK5&6D*jf6n+;3Ue1$*~FOrd>M_>0G*Esx}PlzK^NaxQK=+hX=3 z{4&>&v_^2y@R3VMS}D#ZeWm#Tx>%Xo&3pT++KGg^NR`xCQ&q! z{1{MoYM-Es`lxj}#EZBxOqZ?VRJ%|fwEs=Ii_t|R#tmbhMfVq0g| z^!dpgb!y}gaJfRf8EVZ!whVGQ#Km@jt8_>Krw2Ryx}d}V90W)NN&9i{+ba-RY_Eb+ zC;mrSyeO=PLnyG@l)A+9=n$y`uqaGG`_mejtG4*u=FC~{4r9obB8_1x^?FDQdQI6^ z_cvMfl-bx9<(REJTRo;Gp?BfaX__SS;0qFyy{5o9s%<r_vd>taBGiOQ?% z_arkgS~v7M%RWueqS_Khxzyh-dd*0dVqXO!ebu%e2WQrfRI5S(<4Np0l46Cx>g5i<=zyNtf**+P7akA0uGpi8F%Epy{MH<0I_fDQ zU2*c$1)TL%9)E-*a>lC8Z_vp31Y|$@bWeecY#QSsmO3nJO}ibr32t&E@-Au``Xc({ ztmMtj(hqGsflI@K?^P4JpNwy%bI+FF z?722XT7FuL7e+J_$z10jzdW}0CSLuh*?0c8l+~OvtnFIIkEM-#i`EfOU+sYYd(TTw zZ^c8Hhb&|p!c_G?Ef}x}KdY^H$R4oY8F?9b|IzqOA{;Ba$#nAMB>hz5m4sl?GbS-U^*#fU$94h0$V5f~E+ z!{&h~@!n5AI1WKs%7%LLPJk}%plnm=5cI+TEIKH6Busp>s9y@Yuzb)R)mm$-p-?AJ(Zuj2#~fjh6RTpzh&T-iLKb9M^U^W3)CdC;#NiO?;@CFix-)MpbnV z*5{}0sOeHj#lK{&sF;V-kMW;Djt~fnhj(~}O9%G-rzmg}hSB@S6<#pkVSS%ZgZ}Xc zE05GgZidp}HxO_u0h0uL!H8R~t5s-wE=Qf|=(-d@HDpmo8OFi~A+1vHSrY|~TiB1y zs8hD9)l}Q{phq{zEQiWI%`wj8Tv~)-g45&?x5=|l>2d>GqTz?|-WwqM^Bu}l-WVp-cic__riEq`On z5#)*r({4mc=&}M{H$`U`Qr1`eqQVP&S$n*OZ02(XRGU1r=ISeB+lTA;fa?sFlQQ3z zW^dj+!RjudINv(iQ7|g|l}tMvW>xa@E9%M{?WohxNmkW#T=FZ9;h)=&HP2{#n;KA+ zS-s9mLuglZw_r|?xv_M}d6+_l)4e}1GjZ=SDG@Y6?!}Zw7))!(&L6LF7~#+aGl?~a zZT<`WKm$srfNOSo|hl@CY1nVQCTZi@7`g;4!0m-hAp_tKWvN{INrBDf}a}t=g=@04Tj{PV;49k*DTz8_} zv;+2__2d!@-cL6DmNTPXYXHO*QH|BXv^BYjm)^L6>e&`iR066U__O@mq_dj7SzR(8*Q!$g_T!JZ0O#f(j-1acg?*J4!t9 zRbFzpYxJZ<-=J;YQ8Jm+UMSR9U|elsi*acK)=}qWX6s3l5o~0%jk#RU!)%XsEAt$E zYS1hKj3Jf^FoxhWrrW_~o3hc6`mwu052>GDY3;XIQN|T8|0y&y7L3vlHLD31GOcT2 zqaje#Y2{}iMf`VcR-T;H{r7#Wth7{d=`Us`uMV_|X&G*lGOv3avx+I`ToWApqG$g> zuQ{Q@Rl9LUBTN_nJTn+8?y$&>f6kpPU-$HNtxnqVi>miBr#=ZK%uG?sgH8%M1MDu= z9sS$>a{QP5wUIS8Z+Xggrdc#jj|xc}*}{vkf5I^x#lHh#6Wj_O%(~jE`X>I$AQIxT z?5p3TvF#vGR&}n8s+xKfy|utbbL7z`Nw|%_e?W`U=plp;%QtjnuSHpEx++%PmG6bv zLC0aFUJ{Al;?cmjKz0EMMPNQGQb8*FPl4h|DXfH6eus>pwF3A=sR4ixJW69G!!FvE zB%qCM)EsD^Ft#%@m$IP@(|YK21O)rL7V3N_^fFf(dWew@f-z#5Fev%SZM|9El2v#L zNAakxt?-lW{KhJ!Y*f+5{XBH8@2nJGbE|gH6fA2?av}cYAjWMr!c6HvdK*&IsM^z0 z8Vv5emmXm7@SBMQmEvG09AuW@O3A}j+<$Tng0oS1uDC>`WB{`b2aN8RFhpl z%daDpq1l1Ftk2)ihth^Mk9x1*ns>UFLzAAaz!@I>L+-{_5y6ETjH62vMcBuzIYJ4% zJTG_oa2+F&x&fTS(bDm^PO5jW&y&VcxtKZ3!`ZiGw-xvRb6OX zeJb-5ZT&}TCg~ID6Kx?Bz0(nyt>5vzzISX*nP*;Z=95j6!|$vJ zJZ3)+tDk?WE3QLCp-?DfkOjKE<;xsQfQ`SRrty3cW)Ft8W7R5BoR%{mT(whoAeXp# z48i+7KGj%4zyKk};i$>g+Tv@zDx5m~F+~t~$djUZ(gaRP{C4zv{=?Ca0)&G)VM^?L z%$M%XdbTeg@~r!6UfQXCQ`P}0w<970A@-jiEhzyF)s-mHyn7myJIc9v@DYUz5rsB{ zv+%epbRg_=_IHV(0Rk}mh~hyeKA(I`>`0Gu9q3GT3aK5rp{8bk+o)W5rd6&D7%Su` znZG&Xn=hNq(i%2Ei+??^Rm=d3-BJWj(NfmAim&JcWVIyH#w0#jij=9>$?#)KY;Z35xw`m3tRPcBvbOfia_k zUaQ~>W0ZtvA7PD4j~GXJy(Km>ekRk)fA+8`6Pf-V^Ci za4jIARrU0pE((bw@~z3uv^1eW<6KhmeY1`K&lx5xZ9g)v0Qg!`Xb$uu+_xvb;r6eg z8x@*`LUXWhnWHJLHF|<+w7xgfwLVB?I~!F=V@m?IS97U~xAi-*vTmX+**0I*K$wtbw$kV1fh6iku~e?hkY&@N06cJ2vWc}ZYa@qAAPp(p^5Nkagi9V znVs@(2%8cJ-(GrD^=^t~3ZTN4I&#&1{N7Dy15jwAX+DBIp;Hk86n!6Ax&72T7`#_} zShs`d2>amsC>Ap7Bw|%eDk}tT4qqAIs0`YfFxM7GT@}6gl+VO;-2Q-m^( z46mn=oCAhtg{HH~9qe0O1;ozx+jRx6f4jrIDT!MaCZ0>!n*R~gm_}Bgur!5B-mTnr_*XB2p{+)`Zv%a zV&K`GG1@Idf>v4pU3oxW_3WaWWbVDOV+ZmXeEM31pg||Nv)c4@kDcAOM4M~@q%tZU zT+a)L41+hs1HeWCtcwVl{yYJw_4cDmp@Zs(f4#X zl}G@<%Kye4Oi_iWPK2i1-a-nhUO!yY30_FNc+FthNu;=dkos@7&DxSs6`PGvlRKoU zoFzfMAJK`tMG+WVk@_ zhuj6>yZ|uc;{>$w!AEy=Zh}v<-LjYnRWu=zcA)x=Al!5wxMdgiAwRTPt#_qZMrmw^ zl0phM4G4Zdq@J~vSC1HgnqWEIRd3`$2FS_ z(YBO6iSyvJ!WQ^hP@YUuF`4>Gq-876Bi{;P$hKb!?5r@xO$7`^X=RRoCo*61Q~&i_;^>&)Qkld=h=7__u6-Bc{HC}LMh5UUH-JG9tpj{@TdV(#g^U zGWxMu`5a6yJD>K=xv9GrCr~#Qq8!~1k`<3?E%)h!sG3gaJ52;juJvk$TjU+GDCDHd zy{@JfJh)p8DAc&Ug)uPl~~3cR&-M=^6Oq#ekc4FR|2I zRnF1Yukm(%4NGhu>dMe;J?%a1^l2<%i;{fT5V>~X?c8ZXtqvQt7+2H7K^T0`jL2#w zrw5TdAHzGk3@{=0l^C;oXF1l6?G`6WzqSq{kmi`zOIk;O;k{zuf&4rvuCO;W9_eev zy=@!1FNicR629AbD9Ee;_OAIw?4}YIW`{{zSP5_l;sGiG8J+C4; zT4^U!wjQBCa$SmkuBHh<_E-TsP9H%SLgL|l1n8f!omjFb+}Vykr>bwZm1~%ZYdZPQ z)&(pK#Om$$^s8UUaUsRI)g@_((yk7sh7I4XJj^oYKOJE#6cNi=Dbiu_PyiL+&CYZE zk_A9$w54-;MkF?Hu*muqJs`F57vM<+)#z-OU>E%%%_7Rc`P;V?X)qb)PquYvYbC=V zy43zr-(*`8V}Z;coib5cbC}_g7kgkch&h{;YM6voy>!A&39JVeVG$>hSYE&!Lr4UK zMVqw&1tbtdw8Jb)GM4gxitfcYD6#avzcc8~_Rflyov#i-l4P@0feZoNSCau3n{oBSyB6CW z7VGO6Tbe*o!n*HMH%Xt}Q4v(FEcT zk<&aMv>-qTBt>VHm?!}pXRS$ZcXzaR{gYWoQSYpK(}egctKG1V&%jya3<~fb!yx}q z2A6Mw6k6Ede$Vfv?I)DDN^wgDAkHRxV%D$w?AlGTUv!-Vm}P6( z+z)B)=@co0Y$BBhx@(}aCP6sKt4}AafZhwW`O3w*5 zzhl(Mljy&mmr_XTyafD($N&BI7$x}j3(x|$l9KlVNJ2ZkGdjny5V!=I1_)jNY$ZjM zDRpr%gx=w6^%?3cZh62NG4taMipiE)UQ}N`)fQQP01o*i?C*<+={k2El0qXM3dH#b z$jSaWz{eWF08ig&)}ej)UMx|6x7iDYCl*|B!l%8s=u3@4X$DK0`QgP>^_cCA`+)XP zB(KElP5=GW*+C^{gii9`#;#@J@hq+p6(Of?&b)t1296-?!PYSWk%#rwU)Fbc&nVg9 z3ItFmUa#VA(oFHoFJQqSiv9T8!c$cfLbosD1JCzgP%Q`iJI}vb0y^vF&HGI%2-*!& zJpO2jrV&sMZnDsu{mMywlOSW(9tZgWC{X_2PT;Mni?JY`%tI-HRLws-0DtXf;z!VijC{__vx{WXuUB$` zX1GL#gRg*?^{uh`c;xL4FTo0LvR1W7PP&u^nz{1fSky-{k zZWySxfkw}W*pZNc%z4(9Bo{J%f8hgw;sSZ17GrMb_02PRf{79oD^Gy_b<6utXwTlO z9f_e4?L`$;Y(%}~d&De>qm{7U+a&VZ<7;f9Rg}t}LXp7ji1FVJ-+#%N{*J`oF7%JT z{o4x2(6|c`2WzD&>bSPcs(aZyOKq!{~cNYNT2LN9(eT=Egy9Qztc%%Y|9{Awr zR8Yh7st2z3H(M+S8{;OL0gIeC=qf>VYy!If$JTSOpQ$_3KnQ;y_F?~${C1$!?rsaA z+DOI#Z07_7TBt$?fbM`K`agLBD4!v(_$mS9Yw*OLAv(kPKRZLnFK74>W$&l%9>FRJ zNmc8^*KcARXMfBoCf~FzF?kILA$&L7iI5R{K)HZq_}}mfP$mHe#Rp0^!GoTJfru{k zpKajq%Lb7UAJiu43H{JUxv4FznV1*$Tn&4^=KG$pC_TZxKdoWb=;9GX`6iGZRD)#9 zu!Z#5S&3x9bj3wj9>XpHlp|FNgDD{>LIw|=&(&-Ai_j~NwEQU>Ksh#q`QTP5XPdDH zA){xDmO%sc(hH3JAo|5+bsh;hAghu5`ND@Lf<%(h*x>jzfPwyoslo3BoU%>^SPy*d z#bmSVlHhZk2zp2DR!888!*!OfJ?Cs@+|GkPcnVZRn>Zl+p?uWwJ6giC+8&djEt!zD z!sVv7r?A4N{8eHG2&G?tIv=rlrnxl<^=C*1mID}pyj!5|fp4#bQV?YKIHdT0IsRKP zU~(2T%^*0>Wd{LrJ3pU$%DlEm7r}WV^Lwbo5@f7Gyz71(b*(o2&cFXVP%mJ(Ka!!> zVeB0SA5|Oyg`rdyV1=OeNYBKTNTYYsbus?0$Bvsv2+JkTN`A9+S6XP5+5197#>BhC0 z50sdK>p+eNc0}G8eCrF;>WDw@rpgHEusux=b>5qhFog^f*q63ufWV4jIJ~lX0%+CG zv4JWUO3UYKL;% z3<|38q(lX<6PF+84@0sj4Sdf7&VWj30VUior2N-yc}}SA!56pLhf=U?toxZ8hL`QH z5VD9rQ0ybJbL^YRCAm1|qzex$NxD@i@01@((@5WTBECiWCa-;2@ZNT2ZpC9SK3JS| zIuh((#&UO0^+PTJDa99PlU!NOFHEzs;rk3JI=}8aAQoLa*A~$x5!4pF5M?(lUVrq` z)n`MJ7~b_&F|3>99Pr6qCtu*>)Fw_nVUVxL^6HN}1(FI9e4nYu=P)=mQetiMeR!RE zN6#U0R|iIiuT7c0Sk@~W5`*evlZR+q@O{zcRylU%YFdOzUrg@AjASM|?$qi1i2hj+ ztLcGB#2z2ohE!cD=93^1L(T-H2Tbm4BPo8nZE}DfTohQfZ8GiH=IKvj;sgHU^?FKc?t59ua zOChAV9k^$h(=MbycS-JP+eE#B#d$Ih`$l|! zGD>TXMnPLj8>Z4&8IsJooT z0e){HeTt7fI439eq*RB36@f=8wG2ci)1<^6vmH%sc{WinLnRD*VGVbHIHK&(O(+~o zNJQz-w{QwQS#I`Hf7%)~n<10!FLK2)f4*H@GQ%t(y`l8v>RBn*c2J8JI{w{5KPgu9N-a zW*I(#n#&o6t*FeGNJl(1@+lFFbl#@SlS2knnBeusH z$GTqqPQ3uyDpdP64jRr;?#E!29{v?K4#zH;Jv6iPYyBylC~B%6Q*a`;Y++hU0(|Q# za;1AGGE|GRffmvq<-AYTMWXNWn`71ED3F(O#eDF$yi+LV(}L~_9$cgah%KXu4U@DV zZ(`2JYn;vE{cvd0vpSuYy|8r2bQdd?=u<2newFuAAVbhX?Q4Bs%KOu@B|PSfXz^|z zW{Wu3cjxUPeCk^y@aE>fpD1BsE$AD#R21#nknlJNv(_xnFKNAA%~UJ7IyJ4%;F7CO zpQt6Yv5?Gkh$TjN^l40;QsMO1R2f~{l|EIwprQwN-A9VDSMO3F!9aSG6BuzkUD5Pq zO~*yB3vHtF{@Q&kfmB_R8(uR^?he}#6T5TzOvfcVO_*)iN%AB&BDG2-B}bjvk?T?5 z9E%bVwCW++Ht~hwL)pnf&vsnhJ{jnwL_bG@J|Vh4MSg=vVMD>#G!WfQLDBL^FMs`Z zDbX;Mo=)KVRnFsYv0i%2((eimwC)Gp*KZE_v%0(Bp{(M>iG8*z7!1hXo#lL5dL6)Yp%!^Zk20NsVo%%geW=dNC z76PUB;+)-F*m3mfbky|vYh9=M-lyp9hwwz3%vZ^r=JOaT(#c+Ur-xr}-=UQ!&llfu z%FXrvk@nRARc%e*+YZtMX)IDgDd{T;hzdxEN+U{0OXu+_AR-}%fV4;mQX<__(jX$; z(hbsazS#%$DsbQTdERgR0q4NpYtNeb&CG9R?X%Ckj%xdu0=YzK^I742z~e?fVA|{E z7G<->gv9SpfGy-&bV$-YTK^iQy}G(oIXoE>()noeBUkQJcwE}bXemj{<(~5g5(9`6 zE6kjyu~_8PfZjS^7ZoF-CpM$ zj&46Z;@f`39eZq{O1=@V=`PK_CS~qKE`ED|RBYj^4^HP9W$s0eyu2biuI*>`C3+i1 z^0Vy3xyL%A?djDJ7%{1Hqj(bzlkSfqpNDi81hB?oM+Q`N4np22mP&obBA)wBV9I+j z5;`9r!Eee=eMsm?oPO%+?q0)5fQ(X@yJw#yNypM;^cDI~v~Ty>a+ZYU0qEXmSKG^Dm>x3iuMA*a4+3Ld4wb zIHV1Xz)7NNA*4%gySXvEmA<>(ycs~CuOna^|%OREOn2-1}SKtxlWx%=_-d`e{WY2V`?TB(6!?2kAMQ z7tPTRYPIK_Z^Sjy$S_m39(8j5N(xu1z5dH#dgv5INo?;fn8U$HHJX9`iK}XK3|?T@ zCXwkbG^qOQ9POB*v)g^Z1^)PZ9^^r@PxW6??RyBLl7EC&Uay}t;FzA(6&KBVdL)01F~IZu8b2xAQE@%$eX z18;Umqtq>Jj%AV9ulI==Ub^e!72hQqjX_HBfY5g2MN*80|s$E!3Xi95C4Bmc#aM-_2hQ4s-^KM?G{L)_um1{Ef@idb zLM&M9mv8Eg*s0e$v62IrrFB#+S)E`q7}DndgEy)@#VFgNT&1}TL)rXeZ9GCKb*u?r zr%t)*akMZEYNSj5jggr5HQ7y;upYZ8`hx>i2cZz)_@&vqiW7L@CjubsBVGSB1oUbg zma2@}^KU=;^kjXV`56ZQ3Vx#NY{u>p5jZarSpDCc%x2|%?5@$XD4Jmy&7n$``9L4@~jK-sBnS)Ej?V$jh8x=fK_@{lh`w|msZKo){iAIehy-8*>rdd%{l z@mozD6hU}peyxBTB;cpsaGCZ8%R*<2piu#FKO=u*zvF^-EBAshct?IS3TvgS zxCgYp2m)q=K40R0_2|p_2Hiw?>fjeJ7;xYY|HbxFXLH$j- zPSWlMkDTcSW}XfYB!fYpWoVJ7v65%Ig4aos=voM!lB?5|ys9il&eMuKHm_R`=SzNu zGHlCOWzm)?vFw$2NKrkJI zW|KuN3(sAI*O>Q*5?#>-&kwQxgV-vIvq9aj9Mfv8N=n(Ri5lqG#Z)Np6iN@Gx z>#=ZoH}wse@e`UHe_0j69g0G4{^V+3s1W|w@QQ)O3;&Z`^mACBx$B(;?t*!SCM}lJ zU{46zl2BKGf3lUG8?pV5d`BM5268IDJdz$}DeCzR7JS>XP;}>?1jP0IkBIwGm&^Hs zsM0#WD#7=0^Nw}Tuc0s`e*S+~fwX+-y{cDiyO3xuKyv73>tQ=5Hn%ZyTY8w7hUou} z1K}f-{{PUk=yzL1kWViEcflb+ab^^axI1>ehsLq#FS*gLkft&Gzsn5)+NY8WeFFBc zgcG4kzW+zU2}SfyDJ2XAIpB{)Q>n`ALzE>Z?%Sj-y18AVqazxY-e%_0AXOa`3GIv^DgDpTC))CCS4&QCm}aQ*O;1 zgf0Of4M?n*^D2qX5WJB@>aEJt@(fIUiSCntVrC3 z(EuL(k=3mm{~xS02kc#hPx(t9SRSYrnx3R4;Gcf!VpPnXYwbbu0W2Q+;Jo7Qu0Y$Y zjVZ`(lMm@0!#_xo9%&YdY0fsBhaVrZ@-BT&#pxM%g(cI3LF3B`~2#lB3Z^ zbs_kk(2Nva9ucq2$BDlZy(cd~+rUQ9tfB~Ovp6ASuxA@6tW-0hutsQJ4GO z<=Je!!b_L)$Ne3sn|btT4g}&iU2s?0@S)Vb(QmbIuplRIE z0(Xhv3dgr-NtJ&x$?vzMhdF0ON!jQMGB4bu<5!hK!;Y*<4J zj-BaO{tOuK;Yze*xq8sGtg#HQjcBzeisaR9AS=@^caBn7PbywGi%e1g(pb-97y2ke zRLtw@rZOV82{%A+1WGLIv+tMMv=vabiH$(R`ohz3kzRGvNgO>Lgiwv+;xuk(j}6mq zF`f(0e}_3-ioY>I(<8VQJ9H3Q0(_URXFY+N%HD#3I$rLXn6RE*@=@^HiR^9a`|HnY ztkxY3weAgD1uhZGZX5tG98fozsPmz#+Xj$>d;%KFF|?fxUW9wyyf;^5AIQ-Fdj~C= zX)n!(O|kJ>dZS=7C1uUV6^))Hi|mN!o+MHvUvfM2hX>f9KLoXM5I$^g9QjQZbU0P$ zZiS$SzvAjZDI!c&1T>g$A0mA>xD@tdL94zHYeQrH*$4Q5hYEFKvrv#y{wJYulC3vr zpec;@7;BAxWztIljm|gjJL49|^IyzUjsq>vCeR+~{sGp{JVLvXX_})u07D3dafW|4 z@&qk|;m6NTu&_UxbSNW!l?ETI?6gzN(H@Sl<8QXxhT#u! z^#&2Dc%zj%||sg|AaSm>kGleppB8I zJ$gGggYmkFOQQhgNA~dDh{k5Muzvb4raAyqQ3mWiBuap2{w`GaIS@+gzY(hA9@wrn z{uiFRQyX@mG&2AE)PHVkPdXIDXMT0*0mMcC;;xn7eGK8-gGe8N)FFI5&Npg>WJat_1@d-gV5+{ zsa}r9x~})=tWJnH!Cd)J>-`GduvNOXXg{*_6C8qsCYGKYdvi0}&>~%b7T5Il-1i?l zDXbR|bgq8~y>PH#qQ>1OyD5!F;_wKePiTq!>BWDtGH^8*n43i-m}ARsi|tOxxBgF@ z*F?mBcXpZw|D?b>u=BDFk#htrOCQ!cfeX`r#A*$+Bid53=f*qyELIggVupSt_h0Dv z7TVTp`S|?)D<{vM_w7Rae?rHk_xGeRN`VN=qg%U|jG^i)Li=~{V=in~Es(bA6zbLIK|7I80h zA3Ocnq=zql`581|A0=TeBt+kTCqis9Fj+|kU10>7BesFZ(F**LFJNaB?by?&oM_}A zp#6P&S^8I^=A22o%IPves# zJluH}Rjq}tX||lqoKMe)U_UnPR!YQyt#Ex!!p|6-vvSzF1YK#@GHyCk$_2i6AIkTMI zh43~^tjr5xhm>Ol*GvFEPvIfieJ0=YdzGs%AkhcW7{Xk$d-S6w@h*hs3f&I#M@+ut zqPxB9&NR1rt)6M_#a&VoWe?D!Drg()%>EwaVVBnm)!BROQe@ghr`dALm8+;XAsFDr z<-Ngq*7H60ep=WVfiHez*nry_F<2S2dj2l+ZN*Wou2D)V2i@vc zDu==2-biRYrS;V7LbnmYIlLNqH~=Gww$i1~5D6^AEgJ6Q&Tct5&8b!0hF3V+ynCBx zc%dk4TY}@qom885qMLV)aF}+Pyf|Nhk5iE4*LU%(D@G4SC%$n$@L*Qv81Zx66)M}l zoMBWGG*XEZ02TY6K_ga`w<6>O1)bICa|b>ul@sJCEqA-;1&vWRLMGo$2nfvYk)jBg zd3+gI&0<#=b}Ga|bBdsf^U6Q7{Cb6%JNMlpgkvYtW##5Jh94dqPh`0I2}@|BvJ|iz zr@^t2zu)DCHQ(F!>zv~mI^AYmiG*soN7eZX zA-^te8=$rT?TK$S_6Fq5&a!0=FC`ic>{!3d&F`IjUstNW10y zrlCnmLF$vNYxLh&Cdq$DF8ptj58yUVOzp;A{-Z(if74*suJ)X9>cTs!Dr!rz@q%cT-kP^LaQZkvzejiCf6N8f4~ef^=s!j%bpM^rU9bhP}dY6eE#6%`zT zMdJHXSbkZb{TlRf&v8W!+;!UO5{UF)C&--(2V+JGKbEew!zrNz6nN?%438|OL`^I?-`^Kvw(YQP(N9y}gD-;YXf6<7epIhfY%Xg- z#+I<{b$-k#=cgH-oTpf-Ftj6UVRaS0tex{#YLv6#3$(PZ+h^^!LINgrp+X4zm-On0 z5W)1U06V$}n%&R-1vRx?Lbd~AT{%L{9FRp|u&ZSg?!9!^PIl|qvL@!;S6{G}kA5jS z+#{l1@-N=69h~+fU#?R;Sdrj@t`A|?K($fvFAf?ad#e+FZok%J^iT|`i)MEGEW=yc=G%6+e()0X zAHR(Ssc_ajAc!!EuAb~QlX_Gc_Qg}rW9HPq9Dnt$-MJ>FKzMQw42?*!tp!Fta+sKj ztSg4L*GyQOaU|e4dd8;lrmbYcp4Bpt6&^eSgWYtUr2IJUW8(YUZ)fj1zf%1^Gt-B+ z%(xv99>D)T>n>35JtQ@}%EzO}Ih<#i+53FAcu44ZqNY%h$naIMu50Aiu z5y^KLoDjHS85yM|jb`j8A^nwquj4?rWCT}n9nKgJRdl6h;&X0urC9UfT6?Z-z- z%GBuo-4UN;c($$SIm>Oki6Xp)aN9Kx0Z0a+v379@{?yeJr_Hm+dv8dsiskXl<%*Hf z*xhi*HRIpw#jet5yEa_iNij8Vi6EEHb}pL^Runw^C-*IIk|yl9;5|f+Zl?Vh2leiz z$c$7Fa(Y--PZpV;sSgq089qPTvv@)^bg?ijY3YXfiufZ#55ZN-#(G?~`FSS%9^4LV zntXOu_t)Qq6*8>uhm(E1W%nrK(ZeK@Gj9rC&DIS`S1-L`ZOwMDJ^dotew1P3Jhctr zpkY?L9H8U3NR7?fkHPkBGzUqls%wu=0HDJp=os>z1iX9=(n5Rm@EjMPpxG z2V$?cN%Dy{*f(Sa_xzON=kNRj$3SytcgD;o3oSa1!nMWYJgQaNGaPIqBX=UTgt2gY z9&#~8j**gosW)$R*U3C%~-2 zruSG?tzK_j+hvm`UCI~)8M+7lC~u%4fi5vcC3DFwW`3UY1uRE3+nUNc>2G~LUzM;GJ2~J7@(vUc~I1En; z|FzMF`*E*-|8ddTXjUs;#&U6Qznq|8~;}#rx`nduWD{z; zlHX6e1P96V7A)w=|5(0%j%}aI7TR{3;tf6XbM5Njzpdr&+%Gl>wEl;lYD>!6qmLp6 zaMOnw=~#)aPyemVmvsxJ34eywxAYik%Ag=SLKS$s39Yk!4Dr8nLplFk#K{0u9IAmU ze`WBWf^$5znPPofZkT6>L7T#nWNl164_!muc~Sv+S#&1MhoPDe*+TzJ3V%C@O39_F zyyk?0;PnxfGZUb*ixD?lk4eLUG`v#FCfC+M`$H1kFL5$}LF>2EkthrfjupIh{At@E zh!vUtqC5SwhicFSck*kwZbYgNr6GD#1PFfBeh;o*K;Qfv!UqAJE%y?PL{W7l?e~3Y zv5rXb$bT{C;WEp1b>a_ioJ_4(<2nz))Z%aUL>)C>M~rx6bA>`Miibak@WD%GRT}Zn z?vWAUB?wu1imIXK-MbsQip^6_XmHtL2y+iTN3^597NPkTQ^Zi2ml=n{m#|4+1d*41?mz1L(h+7n*f(*SWNx#ItzRq?1=?6SJSGj^pA_v2=xmOi>whJI`|nAG z9LwC8E#RyPaLy`#M@-;On#f?{V_ctZ)6e$7rYP#Ty#`S}b!0NJ=5W(BEaRddgpX|5 z+qQ2Yt{#hfiL%+cbc-HG51g1ZZZgwpp&gI5c}iTiChE|dFUD#iNXYWGve~%x3v@O1 z+leEdCISbMv9CN_q;g-m(WPc~e81B8!w9$o2PJp-f5rR;kvH%xIYN1OF8n!_Jr`da z&7rIW6F;9oqSAf?2N0TOgN~Ny7~I)qUr0VI{ib0I`gjU)Zh+&-S9Gi>x=d44Ro+=L z@u?_mM+RRwtb87N_1nd8li+^jUk8Ufo+QL`u=ByPvy>HZGI7dSt7=^LL(vrxJ1)iu6(MK)! z=MeUSU~;?>K*_w;PksUZnPhG~8#fO)>N%~ND~$%)P`lyc2Pzhug!I$~uH`=H&D>VAWF?I>+|5)m=W*Sdb-n;Hnx z@wkQlapGlQ8H0Y_cnMG8&qb0+H}!HY462|AAilCEJW3Zm`9mpK|lDew@J;Y@2etC zJ=d9!222Dgw%*u|Jc*S8E5o&`@+~vAA}v}Vc68;U0tz0DJ36b?b1H__H24Uy;=D%< zsSNy8+xtyb(6Q0x zF3?*jQJ**-O1^R&4x)TuJ$t4Q_A(ktgZ;SBv_ky8?USYQW;gzv4{nT?C5uF+JpHMGs(nY_8O|@PopZ>RR@U3gIr+OFK9HFyp6Zvl-wtUHE^H24nX;d zPy1U(HDjGysFKHUbwL^~5@8HDxbvED^n!xhP+xB2g=x;*KGO?NhA;x6rAG2s%q2??IVn*rjr=K<4u(Vv4wvk;aQbEMKaxejVQufdQcVq z2mzTbMq#w5`FMuIWjRsU{W-*49Y`=a%iG+uSSAJ6R>$%*mr1n4lyB=?xn6O-XPcwU zpz_f5+XwzW{MpM!GU2A5*yz*?t?|b*=O+%|H7F9R3FsBg4hS$d4YumPUf`Uy_Po@j z=FyY=mPd%J_s88J)4LpgEui+X9#__~jk)4e_|nl3j;irom0rX5F6@^(FWWb_7p+2; z6OG96?mTu|A^sr9N^0Kji!G}G`{}ml%HEqpi8vcSS5V96SorUT;r0>QS-L@{i_YlU zof@9Dj$7MT_%T?4?rzTy7B#P;VTmHE_=;kC?xxd2!_bSzkt9bwCTg48M+<6JH!iq@ zx4SW=Z894+ZgSWX;dG->$yZzz`b-wQ4h($ zcC?P%Fx-kPDWwldF0PuR4is);vP@^6$t@5cy%Ui(#Ak-1DFW^`rjqZ%^}v2VIkfu? zqZt482|D-VNe{yt`HXL;Pr27PCBP0631E~*kI5iwWYO%9);z;DMM4?a;M~k zylddEUHW|{89i%X`RsuRNKfFOfwL)cN+Umz?%ZOnfD+yEjxsGrK*?oP(`lwd!+A@^ zFWF_MAt=vQ*Mda(b+@uVq&OH_D_!4*uI!INhEnE!{MGU0kAFM5K8F8w)J_w{joo(W z_hJF8ib_-7jwWP53l1YqKwB(o`VE8ZIc|=~_ucId3+$*EoidaLR<>(ydD76#IO$!@ zABEO%m=oUoc9IGEH=K?j9LIrtT^sgiJJV)as^tj(S9xC1_w?<2d^67KyOCP)-CETn zD68%IH0oy^|4)zT*JNZ~AjQ4eK%2Yi_ts&z<7nHozkX*BPnIf}qE3%DrML^#$AR>& z*Sj7mmRv1kf(ic|!Y3eRefcozbN}PBW9L8=%eacR38m3_Q@j`;3Q|A zuZym8Xa@Up2#4clD3Ie)T2sxVfyl{`I4oU}`I4OX1$gGI8NUASsNWe`mY+`x`}16Q zr>%q{BF$p@R(A=XAQO6eCe3{1KGqh1Q^}SDZ5yZ^^Leb)IVgg#I8OB++maUfmHpBW$jbi60nZr|TP@A3cR2gs*JpF5%=z9|Ivb48vk@VD8wbv z??l4(lk`A~p#4PZ1nToUk$l7Nm40cs+CD94!|7n=I9S=RM9pKJ?rBa3w95FBG;Gwq zbk5fl9Cz||gK;Mw%WXCY2uMD8MW0FWus$6~^~ccG>?8Jp`ltkwYBZmXlo0p3+>wyS zU{l@?Dg&T>&+<>Lf5}tbd@c9Re z{*~IbZV&X?Ic9I*e&RUCGy`bcbybb=48)M23EuKfS^WUc%zsWN98UgxD)aNhIwj0= zAJv7@-J@^?Nm3|ic=%C3vZ}PSfNnrJ%WHfrh}qR!-2DYNdb5Uex76B0Uu764nNAO zKh|m6Oa{CR5$m!^#sc*M8Adp&1oISk{eCv?HJi#F4g_~*Kun=ojmrGnsQJj!BMlJz zY#TNhi@4|tWJ`;Jp8fma&zhTgTX~`bLJ~|S829?|W+R~__G7i#mlndq#=QbP< zP)BQYQk=55n6b4j@ziaT+)~yw>X01LjF(QelPG;qL;Kel;#c=VI@g;Df6RiLfgYVf z%`}#<(e8eCTr0REkGU3$rK<0KIF{BHOG!e$*_|-H;7(-jsJNs-C}i*xCW7o5SRj~V zL>pV|AIx`rPk+6+<6-0p@rd>q+?s)@yIZVpAz%m(jZ?FfFFh8sqd)>K=*Da}cOlL7 z4>8d1Txc)Oi-IKVk=|eICC<@eHacH%8xzBixdCZxlC&^aTR&TM<4E zHH+04P7Sc*-dI6xqmlM`p`5kKQ_8xaPHG(1vQl#t;PlV~%1dkV;|{oOxZkD0Gy)gk z$R5Th>y(`dTP>tM0vS~F(=L)Tq=7cez9Ai^x~{ZG5KJ%g17k&J(4p{&VY^0%<-bpY zdp*euZC#a@0QjFljY11elX;0tu2S|EJ)`!V0E4_?waNGQTitfUWe6gyRX;3;ZHmub zXKs)sL+Dn4B|10tT$GnRDif-d-Ez~p73!}y4i#@(Mn?Zi`vxB6?db6MU& zCn{27Bri#IV6^Q@m3j(m5PO@l+CNTm!(pln7e03*`7S9#UtV?q3z|or{7cqAb>_P( z|2Cg!XZA?paMl__r60R2^bC2nGZ|o4Sh}eRF6fU{YQDT!@dIv zmMU8a_y876C<~fX*ISPIxW{1m4QOuibc?}aQ@mEf@|SvC1}6YFdb>O=)Qncr(jGB) z+P6;Nh#}Oe`3HsrEbMNsHe-+7tMp?4WM_~5?RpeHwZjfuKfY6iTeCZOPIbqmS z#LV<2>INM@0kdJr9j~T%G2w~x-yakfTi6RI<>|VCfZ!LCWq7f93*RDT6|EumMH6&l z+u_@KP0oiGf-AJ&G}pIDSVnvDe~zxPh}S$trOQDVX^UKVZjeVaiInvdvtW&G+RdHn z#@Y|DiinjGUI*OL4^#z&gmjoMrxJK8S`)UdS=3V_q4!3wxRL9wh6|0PPs~sU#lhmF ziBQu$E9%76!NNILIP%-|#;@$muQ`igmb{{=s5-$r(c%6iPh>lC@F4K#;QAT@Ji)~j zqxC3J%XTAv)wFaxVBBsx%-0#ha>Qq*Fe7X;W4b>We!it%GF;;%Z_#!JmTYzke6bbi#8rD{g?`}`p@`UX=7yBKPIM`W549majSA7K}aP}=wx zEZb^N$yLFmZfEj)XNF{UAfapg)^qY%)dAd{wGf!3ADCn)84v8z-<`49w0j}5@klN~ z+4iNufy`j3)zE1d9?3q~m#w;G-`f(8hh57OQfmC%k;E#H8;!~vqtX}v7UntyBHf;` zVG?|Q|B87GyTK-bd0^`jaZk4MuHK)4wUxTL>gzy)VjFl_cn3sH8^wuS?9d*Pj?9Kf zYugbHC+E{?-`^=M4-w*~Htxt?Tr@i~W>C6m=KKQ^ZneuU5xdEhYqD7I@C45bDb0;q ze6+}2BMJ+@<4g~Eh_RtAv$9y9vZ4DRL~1fAv+wFtpB(~LCL?F>ppX#F8q!ZQv=QBu zLl7PfVAKlFL~iL~i1)wMqp!?4%k1~S{{W;@QG#$YNJd`P6R+Yj&IBm(^6|;)!ers{ zD5Dv#-!vH}y!WBlHc8|Ju$E`LMFFFhIbw8`<5||Ts``1@gvM+|xNks>qa65Pm8;-; z`OR^f2hBv1H0TV0dvP-`p?1Cv*72rVC>N0Zg03duios&#SGS?5OQ5_BqiYb1Ou9=& zNF!}*50O)8?mYShKKQYH-0@>AR(~m$o@jn+1xm7H@~BZwv75rHakH_kUrNHQ>=L>% z@+jrcaX|7m3zbB+j_(DU5U@+PeelM?S-jl@&hLjF^$Sn>xw>{*$NF%K8 zRTK3xmR`FeNUUN#mo%BTHZ}7a5?0eo<<<_qwZP8K9QChW@mk*?w$tSeck?nx{Ij z8!ALEDDZr99pn{C&rh_@iks`IzBQURSDJkwd9)4WOPLYCeXF1{F?H? zf;rDvYG#LOhSpOum`Yp`;{&5(|MBpq8CLjE1HbV^dk}yEBZ53~vkFK*9MYklWCHZRln>2^Tp~;K}l%`{PBgcB@4cghp(7Jo$P+PE)zK-El5Wg#;-oHZ3Sh~yC zfroi$&5G1^{Ox4ynBqs&adskX`%!h<_qQ$PxZE0;SS-*Pm=i>;vkT}%IZCmO_*2@a zlaz76ehVZM5z+6jRhzrU%k;RM-JoMOY;{S9=#KsD4BKQ|o-?J;Vj2$7u%eycpmCFZ zNnw^tDx^LcHIU+a*_oP85c~<))u4GpK~!O=)S9B+F+8>fl&5+NE^Z^knH~~zn8`Pm zRW)r@0VB1__{oo{KbQ0bmV~b&aHH|T()pZ*Fb`+VZAfSdT4W$jvS#Vy1yG4@<@BsX zC->(wsR-QThBb6&l8@ulSz!4O^En({$_yrA)x%!49JTS-y9=4*LW{u=)Bf`U>YtC< zQOXX?8I(y@k;g(Jq*}kuqwdYO;F6xFx_B6qhGuD6Igbq5Z!AP%cC*5ytyv@ap~_(v zQiB~C0(vbA7->YfFov)p$aLvl?w4=pmZrV6=7cyhA_mxR0pp>;S^kbX`V}=BhUm*Z z#Jjql9F}R8=Hbv*V2?LZvM3Bv|LB@^;kBV5{aCw|+Lw5T&V<5DLtA+^B-8-Rp;57N zX|*@1dKAyQdXSvLp(Qj7MCbX0vpWYqx;gXb$p19c6^7uulF(hn3$qTiA7>I$i_cn; z5{cv?E}0wOKh>50P(4d#En>1~+}(4+fgN3v5t1LBY^ihK;a+7^PtiI1D7xxr4E=O9 zqn-T5H#&jr^qiOmpA0yQ1A$AbM`xB<;k#4HTY%uxbbc5@q2MUTb@+6U*`&V$L91IV zMPs|sz{3H$>~yA+&bw8PrN{Dem{@#5*LjufBPWwWLuIM;bY-&LN3t)ulr_(qmaT_f z#4bSet2=fBrI14UOYaJ<&ZKM1eK@y7NbqHh%I3EH6?5G+b{FvFX!$*(l50gy)GYR0 z)${z>I;%G?f%`S0O_eJO*aq`LaL_*n+jI|cIU|BVtm5fb31l1NuF2*%nqQ)pX;fZ~ zN?7cqAj`JN(HN-NDR4l6-elt4TMvuQu)i+3m)Y+lo42ta_c<|_%Mu-kWhISF<1|+@ z{FMD+J{mhOHghhrHjD22#PY0qUT)IYJ3qCmF+08R_T2J8fA(ULLemCc{a~J0Lse_r zB;LG*XG-A1ZE^_~LTChh>2}Pf8rRW<$cPZWC2Xw9S*?&V^kd7Cg6R9lAhm)8U|`=D z`SPX_za!_>^|MIFMTfZ;J4&zfm4~p4nS_tb-ib5pH*#L+84n7RBekq(92&6}#3!I= zGRKQBc`ME6v%8nazOTAhb<8$?s5Br%TQE2T?M%<-)>V`Sn%))^P&Zj?U}d_-8=g?h z5pO!Uh|)5O%oRV@2hdO8jM-uCp|m;_^)ke?C5sy6ALuPls0$_#Dhu7t$O+vXy90SZ zZivs7>O@nNC0!~y267#T=(5(rUo71Xqv-1#G<)SSlQ(c6LQvcpX0 zs&6Nn4zd_fx6M$Bw=6po(wwQ@a;jbT4=tl_@&~)NU4V6wU8J})m22{PS*!2c__&No z!f`ZLS!tVGsmXAdnxz|fhiyBL%ap(cq8%#Y^(WeG7GK4YC(F)kHLE&K)aqHsBG)`- zI)_UH2;!;R%BA>%iJg2UZD8^<#= z{lYP|Yo4R+@{*&AcNsFY=-qdt6N)~v8=5Lc`E`nZOJMMX!(x1MP*9LPdh3^&=G5n} zYbXs<=7y9AbYjC`X|v3`qcY6SG4;A@w9AvgQY5^LEXBtC>6_M zUF{tkiEW&MBmW$j>xLIgMxN5X*WP7#LgIAnebZtde@364Xj8R^EKgsT_f7lBX;hBn z8prmUHk=SJp;n(xRDF<0F%Wx5Cc;F?ok_~O;aZLiyAOWfqZ1a$9!cAVeHrCCv=>E; zkKb|+kLE49r7IEn+4xECFrwARLCSgRb$?pMS#OGQqOk~##faf_EwiFzYZfMXNv)yb zWd;%^YO_FzqH3-DPqA(BjB~|xYpSI#!6fBnB&sn=?sw8sz@{x}@ew)Uv*VpZ?N-=< zj@jNSDGnyoc2FUGT{Ct_)Lj;V@*S-!{v4PVcIcHw5aTln%fHy$ck#WPMC5*B@uIhy z$DcnrSY~=$B5#GjpX}{KMek5ot=zQP1DR_HN@R?sA`NGvHQvfezP$2Qj$W&$$1{N_ zy0l(}QJGSajFC>pht4J4`s)=@AKzTtj@Vp@z6?bahfJfo-Wu~&zoUYPg(kw(T%ll;HC_gYAc_#GNnV^}2 zWy3sLNrB=7@~m`+T;zti3j-UXhOAdC6tsA~%P!9O45)A#SPTZfr1$l5kzuEl5ZR~7 zkWYSW|MgsJ07v@Oe9(+ge&t%Yl&bcUsSCxATT?OzY6wnBi}tqllpQagV)YcK!H~vt<__^j&f> z-FxeJTD|(?mreT#rAinN13LQ1ZPfvpu+iAKIhLS z;I~B7?+H$DZ}xF5Hi_ZT4n3r+WEL1t>|9VlOwccKJWq&lv4e+wQiGz;nNf_vo!^rQ zgg$V)@pEo(n}tehR-bC#!nh%}qEQOHtyA=6-Db`iEmbnoWpwE}{i$<~^gaxCWy-Fa z-8^$QT}M-BmrsAQobFX|c`4;)wwufZMa36Bds0$R8#Br>N1S!+my5}mUiCGqCb!>H zGJ4j3I6|7aRHRrY$&ZSy>3V=aZ-fchvB5xkjZI(ZApbjM^esLGG%(=cMHR4v!Z$Y+@J0m;N&?v zboH%YB|cY_%(c3Lk$t&QqQermj!Q%x95RhwiQ?5%U_4r0rV+-#;#>5vmx*eBotogu z=|vv7V9`f8ee|8wgoO1+m_X4_&qCAgX!>cg>^k2BTH5_M)4ac(fu_(;*esrx(uq9E+i9)-<_VuBLpAhewn9bdmbi3^ooq zal*a;0>J|H;5o0d^cMzHm2W-|(LdJYeas#c*u|vXK$~?{wvSG_{-JSok+k3;36aZp zy9NmyK}<2$*-{tZIR%#alDhmg6Are+2N!wbl^j7`p{L*7*XcB#ZdMr6vl-6ypT`!q z*8^L^-0}Xsm9Y4um9RnG(GCC>Pt6!5N<&?Vh_l!C4jD~`mdFWOxI~&}o_|xX9(vQ3 zL7Aemq&Q6c*n)naX}$CdgQxW_7b8s^LvKB=8|va2Xp(*^k|g)ZS(|=hi9FjejQGe> zZ?vI<_;)kkL#sBugAoPg2LKsRRAQDAp~069rCx~Y!u&+*`Bky`8e1F(0lMH``F_5$ z_MH9r>v)3Xm!lmtn|AgQj>Ell9NE650p%O&!Vr`-+c>Avu$Or&5YS-Q6`7gf=LGe3cqz+xS>pSH=65 zJ^)YKFlzmtHP-pX^j`DV6ZEdud`i3p}n zE= z1zFE!$-2Qui}MZT_Ke)CQEY2pj=z*e9mJM3aqRL2c>o{X#}dMmE?%dPNZxVHe@D1k z)!!U1cbqUUOQKa}CVaDhM{~N;K}RQ^37`5Z$E%SHL)i+dj3JO$YuN_W9K0WpnK6#L z9TEsKes812kd#17r{V>X2g5y6`|V|LVq(O=N4ysEtJu2LbEr(U(fD6C@fQT$_IB%* z4>ubke*ZT|YQG#Kc~pt7)BZ<&V6q#Jt>q=}I(hl)X-ix@#yPBD=68@}%xx*&VD?u}?~VEwDufe)Izs^_CPi|-C_=++2R%vuz^t#+4rU!exr zMhf9`7VTv-3K2I1lZ}^Z>=TX4J-CJH-odug?CX@(NP(*Qn(=n_-q!*i3h`K!#%>s9 zXV{etKUq?mF-hKi>T;FKK;mLafTgVe#p8$G_ZF(D8?jv{olLn<#iaG#G4iTxq)A=l zgA>8^UM~HXl?yVoLei3l_tZa?##3mXD=JepWH@a>SX8!(23RA0v=3?c6!$P1$0WjDy4oO&Mnib9&>x}z?w@kOS4AAYlC#?Hs-N&>jKhAtgGg< zKU-Uo`u%ba&Ldt!wl6w6DSB=a>rSR?}6yIhnXlP4VD=92HP7g^>*eO%0OoB^o1=mM%4Fk z-KsL32iCblc5A_<^}Vh!n?yuP%O4rbD3tr_(SmJn!P*k$I;wG zz?oEV9%Do5j7yo#+L&T}Zn91x&t2%6JZDj~HtYO$ZeY&ovetLAt3j>Fko~aFm^TQQ z&&KE+{cby=mhGNNe9Fr>!)jDo_PBbw%bn%h`)U2F-3b;~^3~q+XzzSp=g^z0qnFDo z6S>pyr1w>hBkz0ngm2qn9%#A4_{)5uOuyD@Uy&=yEZJ_OhBfd@(X@!BAW7}0@Y;=BKY~Vfy;lLr*B%vPYdUg@ZhH-wX?S3nj#p<`#gdurlOi}MLVo33 z>bp6b?prjEZr-f?n7`MGUFBTBElZtmeS59cuUL+?CsI|sWUhF2N==59`B0~0 zleMHyVls<+H)PEZLN8{ROJH@n+kwahzk(N?hhU1fZEb@{UE6V(;0@oW3eY}bJK zK!w0a;+UkIHZBIT*Hugn>|E``ads(o!KJxGj2{m?Q>B`wUdgjt3^#uFh93OO=zZ>o zrTYP_t6fr96|;r45Nw%{gVq9eEd-vQPJ)f9vF~G2ow9MkA%qHgw&<%Ox#O&!kw2HI&~zYAKP$sI;0Kzvdf2E2x0>UaHH4R)eXRbUE#? zQfn0wo)Ak6haZJzu2jzpc4p7m)i^8$)i|s+`ap`@FnA8^)-!pzlY2_8B~U?OEO~yW zfAKaa&prksomoBpw)|P4j?s==^6YUe&f__Tk98@IJQkauWnXLU92|CN@CZXcPKs3f z)4-;aN`JdW=a?YY!v5Q0Usi}s!qVux;BQL!dw9dO!E0sjMW5EvsxH#Z{DPX?VPLXg4+$C-~D3~YdLw?*;$KKzSilld;zg}Yt*)@c!mz+i;d-X=VK+n zGyfTZ8N~J7tYKuaZ20mG)VV~oMT~DaB+vB`VwVduOq@gTsaI^5mZz-0bVp%R)tBO; zs0*tS&ad1{8eZ<6R4h3hLmIXCs+Y7RETK|-r{sH~NZaSXnyOTN zg$pB=CbF3JNIP>Mt{R1yg6n(Zdmnyb=gMm6W68!=-R88!ci`w3TKb&3k}CnHvRP2? zZbp&U;b1$fH8#K6jh(IT_rNx^Vq1k4ODCcU;oBXo=i4o^YOq1nR`!eI10AljnE@Au z*G7A?xK(ejrnq_jp1-;nY>8<&{V%+U@z^P9SDHW|A9x`o-a)^UfogJ!>iOrehecsT zNwFHk^YRUx42`l2ZQaXFk?CtMu!^=*tI=GmllJLDPR5<{%F!i8+Lr9!+rP^n5g@WO z!&cPu#yHerBP}awOGss&7-zebQ#{yvs#Kb4snc#DXIWoJF9A!zdV#<6kpa(&F`nB$dWfLcFLEx04=tdYYyL=j>wz!c2J_sO~Vd3D6eWcOxJYoQw8AL z&dxiGjHxb0s9Hu|K#-`ub!b@6zEiZD@3b^bx7A9{SsAY)=~!!d zNG376t(%E$9#81%HpV*&j_tD^cN%yd9eFoGa{~BrhU)$RI)}&-*>l z&+zY%k7lNLMjdBPN5l~6s7ACA(Gs#3Nk`pu(6qnHEH5u5bUv#45%rjxbHc!h2Wmos z2hI0qxHfLHP!4et9MFxP<-S?66!X+-P_|=Uevt5fEXUOol|s4k5`BA93<*Y=kR(KaL73eXbZB!;LPX3Yer0<=jnagG`sbZf2-lMM{{qNfnQSi_ZW!@N~j>~O-wvvI5siCWGIRzhV+g&Z3)8@Mkitke4?{_3FIYq-0sUphiZtIjQyVJ?EgSU zh;7joH>OBN_<0;lCe@#m8$2806^^-VJX;`C#d^>;Sl6@rd(@(~QMvO&hQ8kL($rNW z&S!%q0t)mUHV5yHD$=n-3+dRV7F4`V^SSx-yJi^T$qV z*{=~fjKxiGhZ19MEtL(2*mib1H@_3G|6XdpVwIdZ$kMsmW|O31v8t6fzZh@zb#-$( z?G*yp@gPkGfR--@{5_%zIu6ZLE?tWuStvR&pIPy^JhhGI>ENT}!rE$!nL0%nO zGdF8UElEoUZEmFPW9i3HK~?!NsTJ-9B8QoZ8o`;UyjB14SZseY^~zVn?A2n{6{i|e z_bw*YMTvO(@hEIK^_qVO_S!ac#ORfMPu_Bf!wfEIe282!>-!NC;8*ph!~EABdB#h1 zsb#538S(Ap2?{yZPW0(4EX}q#6{dm3${ zNRaI6@ponX<<4XJtbd0Ld(5Wl*u7Ye>)2g7>X6al&M+VQ|H%68c&gv`|3ef9Q5{>P zlFqTSjxs{S$Oy-FtdKoUa_nPQipt)^A$#w25W+FaIJP6J5*eY)-|P5%zMtQ_xBDMG z^m32uzOLsr?(4qp=#tq{@XBc zjnsZq+V5LjTo=o@I(p#|2!e+q$8K_G5sU6wp~k13vegr9k>-h=+D=7-V<8XKxQ)V! zt9a@a^WjFWccfJ5jrQ`a`d`0+Xjcb~Q!Gh6PKH-8^A%>|GHB+N_xq4=H>YV_UCaA0z6o`nlsf?mS_eLe}6^irn$d^HA&CdV5Ml zqijbH;ebN=mPm|0JwSY|vI6fSE~0;LAx4f;^Qy6kzUAfVkqSa%;dc*D@b_QFKyDO> zz6mbn>r_=pyxDgrO0~YneJO~7^8rwlpdkr2$ex5?o}Qsmn;!wnK{b!Y2<0EI`~KhS zjs%M!e7pC!V|LH8+6n3;b24VP_u1+3`jVE< zOAYMIrt*hGM%<@3yo|JgEUA^J6TS(7KYpEwy&7YFeWj|)7OOGYr}o;!Bu|URD==<5 zR{AA&DkeD`S0_3ycX5>xfz-3CT-`CLrr%RD*)q{#tr?UpxcQ^aZaH83n`6H1S;yv; zI+Jl{dUjkRX|qc-H8zC(8xBub!}Z*zDpyoo0F$m_d9<-wE*WQdk$&LJM2}di;#ru-i4sad9;N7cvfeRle;l|6cI)7=Rg0xM3;-4Z9r$7!=5Drc_6m=|>z z*OeA*6Xc5(u&Y0U(sTTbJ*HOeUhX+QWQ?t+q8?;>q^EKrXU~qOhl=Yd3rlirUcV$5Di>8&4aiCT7hC4(!Dj(uU3Mn!ezlOFZGuXj^y6xLD>3fL4m z>hi`rqw|}<2eUBNFY<|pv%QaY*DnzCeiL&hnkL$pW6Z@5)NMI-VXrLD4)%Ln`jUa* zO}yY@nntb7aXNh!ODBRn54;|=Q}T@~Dco^Xni<}4uo{P*B0z6O!V|Ndw5n&Q=H@G( zB5HPnWc`m5#4xoN{vsQVDCL7JFXrWJn8=8yJlTb<+2s_4AK5>Xit1JN9JROhzGe{} zgqENcMNZXff@(}msOCeLi%)9v>OQaTIZ1XLWJ}~c8&k4kSsq^9mG*zfS{Q!a{=J)> z)9$_MiI=$(;6ig{``4xUdPz_QC9^^P9W^!gug;d`->d7V1Xqf6NA9k@;f(JYU0AF; zV;z9AxzefW=Ka`aIB#a9YRbHy_d^6v(QF=fw$n3Dxooj)hR<8RM?i_+Pe`tTp_e;|W zx>eZ{pEp^79Ga_HGDl!Dkj`JWWrW7pRgTJp{DmW8G)Qq4%w2}R2(>9m`QQP!p1a^( z+#Q6P;$nVszKNVe>uO$n;RjEXfeg0q!`XuFA``3TCTG}&)Wk<#-9EMG^0PS9x-nNf z(b_4Yek`e&&8u9p?DK9FT%3wm)w6&NPGjr3R?r(Vs!3nG zc1v?*52>C?(oP&+`eo9msApskBq*~4&%2!8UHtO>3iTJ4ScP&J;Dy~eCn6~gC8WA7L9@jVRwE{NHV5#U=%Ht#UZIizK!G9Evuu; zH4(h86=IgRFLRARCZJ;acjF1v$X(k;AAQNrw%sv@DaxBac#_&u%h(dbdm&l0;p6Nd zbhcK?^UJ)l&-6L=dyML7csD`g5qIMe{dsyxt_LGdbsp6#dB}wZzjMYOZrPKe2k|77jzEU`ALlnUM*Fu6Nr+OF^iXdrb|7o4?`k}6|24O^$#hL zi#uVzc=Je0=6?eMyzu|E_(-Uj727YPVxc*)bp5-?l?m>raY?oxMU$uRUd;QpUohb= zI~*`q&hL%D+G2Lael@CCX`bsN9-69=X**60kqbsvWk3GB>&6h+%I~EjI0yL%FO16B zDtj>y?RN2(SiD+~!nT=W`LuDET!Mh?vW%&Tq!k#?hWe%xj1rHnVju6xUrt3xI$pH& zjWF%}g}47+i#5pE{~_v2koES*SK40yVZ4DAK2#I>DYnub_7s0lThi7G4R(Ga>Lhdz zLCo?p5G;(l^GD2*>VRweTmP}qtPcZhv;W^*78Ty_ddbki&W7eU*WScR6bkJ%AsrDx z+9Gt{QWX@kH?_qhhS)6%fK5N!+dje}p+5Y2`QQot1z~sco>FG+>)Nl0Vo^GG0bqh> z+kspAR_?}=vm$~uwrjGTzN6O@id3+A=d5#weDxbEomCu7DjBrRbf=K>rM}kvovc&Q zIZL?w6-bl5q@$Bt;&3_9wzss~)1-P?nsN+~<_>9F5NK5aeeu5gDE>z_U4)8o4&9z+ zu>`EeajSL=t7#QO9C}h)t3@gM4PfUOb6VNs>xfKhq*SW^wd5Qq(T=TXdZcoo&O3gQ zztVm1Wqx(l>B}ewZT)evtO@D*!GY+{AGRh;Vm8v*k`0R=kGp^3Q}2OXjUS0?tGK64 z*O#3(ls^RthEgRF5*A;^4&PdexJQo_PJmXVx4`7#<+Q5az4Dea0c#q zVBRZ{l0PVl=lPYtyf&#d-q2JKy1k)-5d;EEq%}=73`2pHOb%fMWm$;2XP1T}?%p@!)Ycw|<@$2txf6XeAt$iJNA4-pXPW<9IMnfWUQT#|9XZaZioB^evGqtSye-)5V{Wgru@TL)7-L|zTL%TQj=>-c6jfsm)7weKJWL^6G;0Y3nk(f*&IoRx6$Dgnmi&eI6*N#v1U>rubMKj6^I~Kiy^H zEkCkPbIci#u&-hdYjp9xVBt}lkc!O(tT3S~4H20viCZ0Q*A@$Mm&b!dkvT=|^kr~c ztbqaFMur^w7t=h_K>@Clnv~1;soT~#UxGH z`J*;VjPR*cq>?S3*?F1KCR;uCqF$WWY2M1!nzOBffhC?Lm7j)|ss?>k#Nm;55%05I z%Cd(>bbNMq1v++1R#$Vpv+Z0O#ErhS0Rh&Oa^%)qUtIu%GXU8H?rmvYc^#bTFrVG~ zLP6L@8$PFLnB+cn;p+|kM{-J5b1zHR6pUP?0B>4-NpI1p&i2m2q`^8>X+v-{+ zQf9Gf%w2mXuf!O6eZd@@^~5AC?q<6o3!{cDm_jAL=TmaE=nCt4osGj5ZA4+QUVWJt zQ;69Hm2Z*MWKQTY(|y=6J%Ff4OeHY}=@m8SlrNO%5eV?<#FfhnEHCUD47DYDAxf}2 z%)p$x!+vU%DscpzIci{-pjkTA^SA{2e9kYE!6)x?K_K#@6pKo^s-n=7r?XEjE5}}~ z%fyi8&O1w4EGkAhiU8D8|NegS@5<_?quLiBvy@pt*#Ql%ZOO>A;qJ9aTY{^fgy&5E zlsyevTdzbizGLO|`BL#%u*wmta4jOeD|dCod8ISoImWKScb2RjjyyvMxm2^t;jO5$ zM(au$!~Eo=>=;+LOn!Lmpb-Rr)Gz-2dstnRqd0(KN;tfgRU_z!G;MPzr_)x zMWQRAxYcTshrNC5i39h@{(p7vI7V{deIFP@H-VPvqhN-`S;j zcUv+(u)H^Q~k)~&NsWcqN+tkUVVJ*iAMx1K; z&6Ug&`yj%1$YFKe&ykGQb(wmeaQc!)=Utu}LZwNuq&6`@1>XsAk{YpZ z3^*fBnf;w{^U1}lBhrJSXdO$u3DP8@)lF)A_kA>iVBAoAo?{SVTy3YbJ5Cnqg?qhXCI{DYDmYij>tP}JY^qy7LN zQnODTr{?Ru$>N8+E=@Bld;FRuNZl(cI7293opE`kIVkz2TTcMn- zUGd~ULKnZN@SwjSYZ#3?E#s}nLbuCy9y|*(tXA_Tk3n;g#)<9iVUm7sT%2srzq22i zLFM~pd{&xazN?n4p`=vbU%bPaRDuPBoBDfC??V*C=~^TP7l!Dyl@vD}GS4^6RtgL` zkTqu53Eqq$HZ6lf^dqtju&|DYJZLIFs2%H>qIhI!|r?MpBF>$kBmHKJZkZUmFEPnLtl%))Fi$^383<9BRXdO-7g}96otA z1LXGupjQ94P()h3C+IC2rG#C}d3wE2>cOOnsV+NV`$ly1_oj+gflqujG0Yip-Z8}K zy=OYxYW1Jx;0Er{Uh|_ze$Yt1jtsHobO!0&CLvy#S9=cR*#jH$+^Ju^Qc?%S?E3-x zDR%qWZECcGrPED>*|+b>_K5V}+J}^V!&@{rMIvCOCGL~(?Rt@><2(1DohyIo3eJ&u zRYG)`*7MDW1hu@tKRgZhx_ylZg$n%lCn{DT$rS%C)IMn1!{H==-v5Uq_nAf5=2H?f1`(2epNGHoy4!%5ni~N+Q~sOMlNyi3(9bSmaKgGN;M46T}P6 z4lgOAxIZ`qgc>^EE+%dVBi(iu&viD`72reWjiaqEQeZZ(C)ya9YfArdtZC%Pw()YY zm&{n;3xT&fzB3u#1`@V=xEmtw563;t2fJ84*g`VK+JB6Y6MbD47D}@@%`$x)e#3tmOf4ej)^)0=!ZWqw!CyGn>NSKBBm-@ zA2IO{uc(zUG!*F#y-M)Y;lX-=Wf0U(_KyW6!Zte|DD{=ji2F7+X;E`pe@fZQw%t;Q z$S$O3Z)TBU{!+PX>|8h%(R@0ATm$eV%nkv3eGD)D$S~v{MfuSDB5uW*i+k&CiAeD|%Vs-6Ad=o#R!23WJlXlA zKbbre5ol@eX4h#DuzIX()B&Cahio ze0||LnZ)yJEW0`l6ri+sU0p%rSn3QIR21%nVDG^uA}9zFTtL^V281DsfRq zO)x8dLlvg2JBpkg^i}6pAJnAyN)Ez5g%(jrSBNaAGZGgRHd66r5!E)o@EXkJVIedn zxxvTRgQUg(a^%-i0M1jSI$ev`jMBapay~cMp1mnk@&o)m#f6MVllP3iKLvjcSZ;cg z)C+l*c^;22ku>O^d%FC7xFa=OJ9atdC55b5bWGz6^(F^1$gIf$k9M)lqa4Ta4MBGq z?Bx@qb@Oohy05!bO=#A9XgSA89KsRsmlXZ35n)6XS{Ded++$>d5da>&VKTxFr^>K% z6RD4!D1^FYI%}#0usIG^fm<4!Be}nMPFi1dzqks{+1I}mdSelI=Qrx+k|CqIPyd3H zAPC1Vql`9@)0Ob2c?)14NJvs1wa7)^7#W||aYKEp4m#+^ zimZ#sBk1Mfq*zdV%@{kdNX5>rpslc_8X#K&5`#Iz_yvv~=A&pZr&YXqf8hJmr1mUc<`6pgvZ&HdokfK-xs=S zuOf)b^r~dXdrdSucG~Z+*nDrl4~UY70g9__w!8~=AvE$ zP^k-nf)hw{@Wq>JWC@-dop_hv$suAeqfvzi5Tjbzc_@6 z4-hWTLWWJ7+gq(vSqjcXrqHtU$dByyZb)i3!)%eoqOM#7b!?^8S=*1V_IT2yMe?$v zV-#F;?Q66EjaR}F_AND=fuyM$-kh1(qbZ(~$HtezZ~_veP|s)eARZo}MqwjGd`ZMTBdUn^29#So{j9t6{MqJi5l9He2zf&U z+M0~z|MlEpIgfa1mvuS6ThR;{9&_O@ivffEW;vD{IM=%$ZH&*K8>!QwEj3Mt4*a@_ zBVWC=bY92YT;|GuDe<_@bi1}H?u(+@)Tpy-s&}*T#Gb$wl4+qNHHn+B2)yTqf3|j$ z^JSbYk*+v_!Lek?*JtaFwLs1fY%1#ob<#nTOX6RERdQ8|XH$UbPWqU_2lyfjhyAb9 z$XpEtbj|%4rQF=W{W>1j<(OJqenVLAd+-AQRVYEIqVZ&Qgnst5oETX0L@J**a9d0G z3g86_`#uP)A=15s?qTfvIwiA^jPYAiNJJ0}Pw*?4%mfApsYn0K0o=h!#B)q@HwXCd zWYCBbmaH?u4W7;n3YB7kd^N>_l6rY1(Y}ftNy&yGW?e-)eV>poY}bvGLVEs8e^vy% zOY2D?weCgsw7C^)FI~$O5t@U?9dHnk`VuzDpOvgb<|K3{4qxD00TwRhm-$>ocJl0w@23I0d>aC2=nQ;V-F_f(_T!MyubHw7h0phT@#rc zzSpa@dd_{BlWee3)0iflS%C*1g_4{%L{GIo5vli2SuRygo$G7Srv{4j0A>;9J0u*2 zOLFKAeDqt2Mg^2yY{KYcMgq*qZu*0^qiv7lM1)!uX_>!gGWI%r><%3-g#Kr?^yysk9e3Ym>eJ+c=8m7{Etmv3YM8#F$^k>(B&poywCcpq&a3cc zpU4y&anc)D071^R&KfC!$*Kv96}lmR>;M4@7@IlFG&(X~$gBe| zj}$Odu77z;W<~f){p_1qL&in>2V)N|tY&5LzqFFq>Na3RQ~AOI8J7HCR$I@uhRgh# zHDp0KHa42oitTcjf3-rqY{kb`9EEd|r{&+Y>URYcJP_@qw|Hh-40bug{XSq0Y-3NG zp%>!$y`#I7G!Lg0`von`)VaT6Y-SN!4+8C(zIrLu{*fskzR#^NsTPs(m5%1z9NM>G zmh5FNm22W&YKGVg5Z8)#tpt}>t^NBJwimSkRS+QykAd~hN_&!6l?z~121`7-I#JyO zUi*|o4{qf94A~u@TXg;bNkSS}$)0xd{L{O@)QUXut=-k3g{CdLr)X(Wu1>NCa|tTM z+3kQhA0(AODwhg(<%ddjtesQqp^<-DPk;DcvI}PxI zFne(PX#_@+_ji|T$R<*`?x=rw_?TIMqIU71`nkW(HgOIt#tn}Z@ryh7hg2~b)>X>~ zUTv2R@8TB?*D=+pud^|tG4Z_eYHMZU+NIWp>B-?0Le`ne$_z_dBPaw!%YX57za5Y` zCl8Pub-DeqB)x}l=v9u7t|8^adM&lG+9o{5Z_w1RpIEe%a1DA)OJ#Ac_n}za^SxAs zu7)A#NNf+PmEGW2Xm1gDF`qE|p8dLqVX; z(Lg8}eMUs7E@h1>^GN7LJ-DgVJ+ATop(bz;44^j1g9o=-^A{$$tkMc1tB&<(Bm*4) zNPJePNVJQ{!b8SIv>By%OHYNAWL^osNuFdLZW0|@LOW-!mIJnF;-?pRPY%M-j<~Df z6sfqWiUaD!W*?(gYFZ77LD6Q}b)_5UC4nJbgvftHsQ#r2m+(Xj1+ftazfLiB-L_N7 zO6r+X%a%-e)MiRwd!+#rm=|aDBak&(gP>(E$tdR<_{bPB3w*Q4&P0*sC!NE7XKjS z-5ttR$7i0!U{R*cbSmkJWd`0WTuaraN?r0HdSA5#7@kT=*5xVNVj1viQ7MFQ{Xu1D za&IFQ2(!7kK)YH<-x5~ia^L+0U}k6}4H`1)2SNhF8c39Gczc4oq`=pv1*ciGi@~V6 z_ibuuhRJHltjXL~A8{%1Je=iM%X2SomAl_n-lc3%QR%|FE?dI=MIv4ZJ4=PW1EXqm zqwE<$#7V*;DVY17UD0Xs0fGYV)N#E6;&kq2d06Uo(eqj=ppGuOIpB&0M%lh2t3E zBrO0Wo$AUx*n`|NkOY;l95pe4Fs$I1KLRM7oYB12vi4|&(fTTz@;9$)X(Unfvwk}V z@sm4CUJi-{?_R5Ns&@N+T_E(fzfM{)H{otLi>%F2@Ac~r<~q|JUn?8i*vM4gxYSvu z+SVcC-^A`C+OXtSsB0dV_o>pWDDF#d%vW=EP;$4BiNgw?m)S!(ge4 z{lpPq^8qJG*_1DC${jNmc~G-faRmrpHT{}73gY_x#(6(=?KbI?|2E=0mW6I3;f-ue zBP?BV4Q7((0nnRTq^mvtjR>Qyu?vl2_Xv^ZHL6P1y2+P6Tb!wSGmZ(&!LFIM`&KzndBZnKQU7-5b?*3sS3__ zp-m9UNL&qtp*3&h%t?8zwU?o1JyJVVj$gA`gHw!NjQdN+t50cCiqhAdd)bu~4#^Da zYO6fmXr3(~M~NVoeqeYzEfN=$(D@Awqi8^OjirA~VAnp!^r4^J4FDK9LHYJLg~@h$h)c&PoNj3W(%mBmaqw>+ljSgK%UtdH$IcJ%*uLEBlc-uBqswYmgypS0zz_>FmzljnU~t6 zSS-FH0?w?`_2nj4;YrrJr*1Hz3%Sj|zNE)gqH}qwur}X4U5mq1RQ;LkiTI=Z+&#WK! zJ$N=Q6IrZgiv=$gYLL6mp7qWv0B?$Q4CRyejDoZ*|t)PDvY4h5}t)|!&f|TS{TtJgX z0ZoRS5Kbryy-tAgMSw+@G^n`gr`fd}5a!4ie*M~oqLywNH!Y#oqS5j{=T1fNfq1V{ z^-zM~_8Mi0?0ExxTherhh0#`-Lbp0iN}};A?%x9>IKrH{0;tw(Q2mt9A^p*z$4YYy za9sGmhOxX3Wki^rS5(S#IUJ83$pbaKB-@e3W`MmBfRetuM^O_ba;?!hHvBycB%oc% zN+(#VsF$zPUHx4r;Q!h*CVRi|?}Cq0fJzuzWavr#5@i8KAr$X_7LwjeI_iy z)7|sn~8X9KV9Ry3ZpNkB9HM_bqj$~ZS=>_(X|E>@QxH?9B=qVrM z&Dz-=CIsU88Q!|=(np#DG+%PP;@mn$>I|mCzw<0zf zqh!b@-PJg?G(&1H>Reecn7oN&JFD*NEVlqWROQk%A;?3N?I7}SVIqM{s65=eU^4;I zYH*nh{}yVDLow>VZE2Gy4aE88-`oJ=NRYCz@m&M> z8y<*@82bp_b0(nc_Owch;4_xI6{lD8K4|8*HvB>`eC;aRrWF|z#k*NLr>+-_ET_(< zZkD11$bo~onzT|dQ_LDj;jPE%GY%gS! zENyWz8aZl!RkH-m0X(VIKKz6yt9F%NYbxN%1FY2$;Z1!ekJKMPDa#Y^hlVL4sO!Hd za(6?eelANO~r!$nRbhz}_m$!hG6gcY_psOy5gSM#+bHlOP56;+S2G#%oeC*-({ghe!#$!=EAnBWDEtliIlT+l)kW!T;9vB^`18OA}ynZs@iy z_l*JdpCUV@s_~9VJ+6?fwsRv)h+^>4-2tA-G~$e>t+ru4`3Q->r6IHKAYQZg4aZ(0 z2vmK-LI$nfoV#xJ^8Wc`qw=rkM5xcrb!{OaiD;)zhl1@q;M7Kk4ZbIP?Kg0%hxm!= z|BA)-MVw$W=_)^t5dP#+ggP@I{&5O`1mp;*^W-<==)abV6$ZDo}tKN zx0y3MhYpm}5*AOQB4{o2gks<{q(W#?$_^~@KO#Hy-(J0TFZEXwy|)ZvN=CFEG6Q|{ z2LCbp@@Z?9ge*(N=OOSaZk7O{n~Oj4BkO2n+17fSz#qq$$(lw#BAU9xK=+77Al^&o zDX)2WWY_1XRzK)peOupiG=YDj;UTm22d!6TE)Qx(91Lyh?Cdw~zu^9Ln3_vgNds1q z>M!hU5Y#Wx#i6#iX|*0dQu`58Qa0f3P`TX%R30Ge*a)5jC7b3pF&sl8CP&lE0}1|T zA~8HW9u-ZVmWODeUCSTw9aSbcF;!v#NrIbb73@WhMGZ+y) z)o^#lb8)U|ZpCdSdKf3tr(3D2^_ZAE%ud;-+(REKp33_oPZW?)^cSE+CR$9gf{R!=to%6xSw9zD!H>Xx1wqDd1QQbh zrz=D=_CxuQw-)9KRU;RkY}2@DRhcAf7}a;U)dt8v&koi&GV-l6qy@3TmNFjU`9kOGKsR&D^;E~zBt1$WY1jX5ZvE@A)j&TWKy z$k{aO1Xan<2ZPhsb^0=O+j&vtt8MqdF2P$u6j&R&k1DMOKmN3E0*Nm~9UsfKO{a9t zGf?2slPkey{-iw;lMk5kg#Po)p9obb>|Rc%JKcl&awha);%1Xi2Zt-C9*Gua2}!60 zcSq??U9gNn)-)N3p@MCIL@spRcges)>J%Z@W28q{Na<`87Qpme>?+-m1`?mCHH`>>hs8~k8Gm-@VlF)VH?O1heBTEF z53V|j|LV32sHV9$-C8;+ht7u>>NDRZbtA3Mwe0_Jz64YJ>pbu0zpxc#j@(rvcenUK+xIP!m{WKLhB5T#E)r@{!& z-B_b9H@T$XasVRoq%{s7a$r=Y`ft$#T*K>|~%(4Q6f=lch81 zzz{A>?z%P`YirIaE8f9r#m$hTIj)02|09q3)y}XR;yW`vHy`<>9Ymfb5DyLG1wm$M z>u0?qzweP~2*j}2>LQQ&Y|kA@HKI=ICl3tyGxdvrF#X?eiM}>$EOOEO*?&8TWzo}5 zT#sgl#rgHmI5dIYTWvaf$Z$8Z`3q%%e@!U=0qy88+xYHx|5|&X{z<>#o{!gk(YeaX ze7`UX&}a{taVwbs#j@)ax4zKjvVz`6C21riG@Cw)wWX(g>i;{^3A?^=mh$P$QMufo zb-lS271A}<|7$oKY;q<9D7}7T*HxlBqlX1VED?GiR!G{U&TR{4{KX&RF)HhAXVKZ3 z_OBJL5VS=2d+L`8N$CY3eCog98`SV(>>9`sCeO`iGimy(gA!n`+9AQO`2aO&Hry86 zQ#R^!)hc1dK}&)i^0Nkf3VJ50OxVS%!Pf{kVPu`dYNCwa(^wf&^`yXI%4*BEor$|l5Ckw;6WMw0te4*?S-);REn6vU?6wK; z2@p!r{x>RMOoiuY)0LN-W|RP;nR$kq3u|PFa8vjKJSu7}+F8DkTzR=obogz^KzES% z6Xbth4#p>+ARR}rA+WgOp)=)TWFY-mlWq?!&|=X@kxGWZ^ek}1nItp`ZJObgyV$vIm#C_Ky zPJ_%w_N30a1S_^&qQq$EnBFVrsI8kda=%bl2_f|iz)8~o!3o;Hly3O83+dN_tqg&+ zy3!w^*1-7pt$f%@G&4MgPA}#^X}NW|W=JNq3COcHC{LLC6Bd{(W_SvBUh-{a`7x@d zd;U}I8c=reP@2c^4ngbj1Mzo2T)8h=Yt118CK<3a ziuK_QsT$JChv;`SA}5z$8QwYulzs5ODG7?r`S~3%L9~#axx>l9z;N&BqSxP)%U#i1 z;s=Hz){r`_e8i1I$tt#l&x}Op4TM`!`Av=$sC_jy0=~fLozQQjIdb;X+LC@YDS2MR z)iQs{1Gc1+iM!wi;K$fwPMm;r&sWNsXHWUJLgsiC6{Q3xUt z5#ya)Yv?|lPKuae?w{Df@pE2t1?iNHQehzDbYpwKszou{A=dgVw!(Jr0e_Jk9#VFHHpG`G=p8Tm~N_L|UIm4H~Rx7K6A%^|*HFpxe0$-@3y zvs`A|`0Tl0t=xxTl;5cL5UOKB==uSfS>IB@yi|w9mV6q?E?4d|x=hsXNZ!%HbZQ@t zW^?lfx!U?%FqoR7GxGQ^VRKGQeX($;NGU)gpevj4~E?$7==&*3$`)xjv^ zn=|qkIo#@O?iQvp;-cmYwkY(ob?l-QPT|Q&%o>4@tK;}-oo6LLiB8rkt8Sv};n{Pg zQDZ|*t7iC`(rn!$=`c`#&cC|{H8hy@ar0&Y)P_yP;VcNvE~D>AB8pr3qZK!oi|whj zmd9nvN{-Bi(n+xet46&rMe+y!N9^WKY$OP&D{$|#>&@PM+)T zYN6*e|N7k!OqY*U#iDaHyzPNAhPyT2zP~!wPZ6sBHWg}ouut!TK@G}ZY3tK&ZH~c{ zlC6YAeG$kr_s8U*fesyJ+0rx>s(;i;B+Z$qmOo?n-4R$woj69e_#@<$?NZg~6%7RQH14(Zpj$;SrL!>wX z&zM0`n{e%K_Trl^i_sb`g82h~>RS^Y)=+jnv>T=vdp0meQ~p6TeN*w4eY`z22*m8M zc%H2Dm^IP$U6FQ7<}q`XkjKxtCKjO7a#M&6-l8tLRjX?ivQ|Z@Pc~!`ELJ-rW_i7f z`8UmmeTENUjgt83q=a&qc8y8jBn}4}yl-gG@4g!H$H0Af#;;XGC&Y%%M3uFqVJ?Uq zNTb6D2p>4BKSDyc)x9@=#d>>EpD=<+fY*0bP zT3*V>id0jVC?g!>Hc}vq#l^$?I!NOJab(djic4L1nmFcDTPr<1CSXsBt~710=82St>fhQ*$?E}&0gWuSWqn_?>8 zCIhj-QO_~jEE^So=pofVNt&s86Jc9f&zHP^`Ix33y(=~)1&V;JKEXPDeA4@;O!R`h z%~yAmA&*?1U}GJwUm2U#tQ;w;b@!qRd;;VA1>J{HwpI52g@A?nL$nZ`O;#TBlf;37owGb`;SCtN zwEZ48T3fc(Zf}0{LSlRr*GB=h!m0Srt6r6L=T4&_s;r8I0OovU=k{-09`UOnd0!13 zZCu`H4;OMdQ-A1Tr`&Fi|2p7y@&az>^M(S&#ho$WofEpVR)OcqYLa`yNJ$xh;gNGR zKSQ}@B8j^!ELlSz%#OJ^2X0T7{3H%`DEy)Nq zSHH)4%=A9#x?UUHw#tCMv21EI!sBSH9cuxz^7n5xRehJ+o3e9PU_~U*qXsqNzklH> z@c0ZSVYMK#niq3{^>Y^SG}1h6Qyts``CJoAj$)kC$troUJYeFefM@`K3FLA*>~lpJ zdA;2J{p!zXPvBoakH*sW=kwQ}@&FYe{?{;_H+JGLC`GX*zIujzphe`_65lgwsYTWo z*%bxZj4l9{d&j(k2Hqmtu+jK2UNgKA2qG9W2(iL5##gkpK2w@TM_vAnm3=Z;0W;}+ zYZfu$Sr^;t=Ie3YH13$EJWrsX3+L=C*P^-mSGeGt?c{ot;h_eqAOH- z(_uk$D0w`=xyPc4jHjMpbc;Y}c%z`bNBh$SNYv>IzoPCPg#E}9K1bBn)=)xzS! zr%{zu=GnR?;uB1%8AIO_CcY#{@qukvcMTi)99E5;J6u(PC>BV}W%WE6uZ&ohE&6%` z8RrMBYm}Nj5)bO_p~Cf*%c+pq6}}7~8TfHnC^_bz0=)9u$+YR(F-Z4VHIX&fFb8^P zP%flGFnYO_@m-zap7E!;d zAduncV2kYnT#BNVSF2AJ$o;jW2JT=h3-c~l=+)J@D1Hr{`MOEqAu+ZK5JB!+)->B` z^WW@0G*bTG)&s>%)rEh=YWxf_?Cr9@Eih)2m^nt;@Tasqd>O>{`8*EG)oY?0vt7FM zM+1}Y0-jeWV@pF3J6=)Vw-!DZvS_;rkb(N<9^3GkcB9RTn@Fzs zxVAZbFtpSwleseGOut~HMH(0`2T1u=^TD$JR;B;%pN9*kaU?VGzYS+QlpKr;YSKm$ zKDdk3hg!;Bu|tH8zRrLd&n`qKheH+xVl0XTr2m`}8;g>BjCk7!>4BdaCm&5ijVUad z&;ix5t`}SCcJ2vwKo)SH7YtEKgO{jxIrQj5%!I=#`P8RBZxZdf{rR3CftO(bJ|-v4 z#^z|b`FF(sIo`)pffv4xl47RQcVAEebEpc`s$_7Fcp{&YiTHag?i%7Zf_d2#s$&(R zyyuFZ3^!;dO2m}KDP(%rzm-m6JNG072-W!e3z8#Sg&m8rxX-UdBD9Fwo|Du82Kw!d zHgNip3?qNBSf$Kv{lCy%Q&Oa}y75_){k_K2E zmzpdTU)Bh5RK-G|6?JkN+e@!ljt5SqyD0Q-g;C_!{cM%yZjP|=wD3%1 zSI9`W&1(Bs_RstW@E1;w{bbiLMo0YJ6LHl5OZ{Po8ejY6Aa1>e*RNwt>q0>*T~cGJ zpDGfg7z`V$c)U%A1}Z6l;8!$Z-6GUBzb3r>1@@&$*NCw!Z)81;QgC-H<(}No7gW=y zIOigOV#f<`lvM&waUelh z!>Fq@cS=V_b8LC2WvkQb<>dDJUN>DK!6c^VggeZkS5&D)HvZ6UJ7Mw9&YO+gYjiwG zsP-=CL&y8D_Ed7tT;08#*ewzrwmn;9rYl}&M!aN_&B@r5q6EcDv7?Yfc9YXS`|U#f z_lv~2RJyOW zU{YiiS{r&O`;I$fQ64PqZK5eVoRx7^bQdnglSh|w!L1?(b3c#AzSw>b>`@y1@T^#E z*s@*GutbqnK1Xquuzv>R=LQKfLnD}V>*1?W9Qtora;{S%dFRDGBsYFtddGnr*m3~*lh?XP{F#Q$+i09+IvEodC>{PbD6)f9Q_)Za6E<94ImW)`?-$HZ0!>*8lm z6|_zesOaBkfA52F31DYBs37=Xp8! zekdy3<@(f*oD?pDwR@(k%X-ZtamC6c%|^U&BFfo6NU)F{ZykOclOk^24cLCEfX%w! zdT#+jw>($zgD>$sYP-68t>#Rjc!{fTqOMl@-DT;7SM|Z=eyPy~eWN-rc6@>N8`tJ& z`!eVKqQ;gQq7*Fm?ojfs^+A+`Iwi1$kjLukyBC-) zW!VB&z}xs7t$gkgU?wiVzc_^2dar0I^?a$(1GUfna6WkacC*N+vcqruk3y=)23E6q ziuMzT~IQ2X%q**qq`vG7{CQu*TIF z1%Rz$QK5aGydlYC35C(xv8@k^rw#&C0aJf-N!7S7Z&lVXuIQ%mK(c=KXlEmr+&Y|R zXRd~wvSrMv#g#n^XSx44#&78`+jWLS5@X>L=H$AafP#KqGQRvV9@fbRU7P3O=A{p< zO55*-!V_N48G=^|Stp`b=RwYTWpYBMFSynEj4IquKX~|O@$E>7t%m@R4Q!7{1%n1! zo75?iwcqo6I2Z{Bjf+nIdHXg;CVuYFu3I_aqLARC^tP>`a$qM~Xh_J{S*aQNAEY@E zuaKUO-b4ZxoN7YWK>Az7Z+1)+8l^C0*87{P!E(NHcb3C8>aK-|LAx*>C4%6rxOXFN zaMdI$RZ$5Zn5fa`>7rO+FJ@^~U-j(;5J=$1@*UimbE{b4Qy|g%we^o2*O`S!z6)Kg ztJ^RV{Hsdszb{^OmV8Tu`gz1ORfAKwmX0X}KS3$i&*mF9!y&5c)%35%a|#{+p#yDW zSrTXcGUbzM%X`a>M-$YWnt_kzz_g3-6^vsnwo(i&SyY z?Nc1MnwO{UO`1lEz)CE)EueG4j=pc&MTd(fe8r?2_(S6K>pOhGl@!WrS-z78az|6J z!=kICX$hwN({%cOaZ%lOhtma-#mrJK)VR#-xf}4AAFCfY6150!ZPDwcev7&v~A0D4JyO84d za7{GRH1ih2MP!8Ku+3=JgGyxykh~`c(}Rnluudd%*}7#-(5DzUZbpxReJrpJm*2no zCHD1msW9IjqZ^OLRwO%jeOotK3&^bHTfI%O;h)vzw+yhL zN&NW8j7=#&<-TqLZytE?kg3wLI*o?SExqe(%`3L_Fip=M{vR=|hKj$8k0y7&0aJlW z^*s%ISN8YW%J!8pDZe>gDL{WG=zZ?1h)2$%imaV*Tn9ZMt%?&CUHxaXhWY#?zv8`) zr3-ly2xKAucYekL?s}t+?|8b}Ehm!1V(}&19sM(cHkbq95egn z)*>)t$c;y4ca!G4p1l@(`T7agF0+98(FffidmQ-F5WPa@UMs@1$k3~i?xIMz{&}@e zVsZ^9Kin}>>Spv{9MPaD>2Pw+l!~!aa$ja_Okgfye*J|uCuqn8n|6yu*rmV9Ze}nt zbK0RX|7~M+UDh$+xM{B=j-GOYImnu#h`lbtHAP&>GXx7zKk$W@AWG6 zMXMj=r4jr!7+?$T0~q#Ojz4E%DELEHb}APe$cfv@z7gHD(3~J>fsjFR;=Ov1}1?p&2-bZ{ZzK z4dn`fzx*;XmYTu~!39 zru=4^Ua^rUZ{FpRn5~x8WSvQjEEOCT{i;_We^DA6T~j5!$AgbA{%RQ&ldTuui)GKf zp!)&ymjv;=A=nHj_gJ5&-*{Nedd_7HvjZzoS-(S>%A=J4L{_mgocS%^t^KzJDwVb(xE>=);PU7{B{3^W1j^+Lb+FR!N#n_7&yeA7 zA6T+c;2*9EK7ah&#~%&g_#$Yq|KZ5AguX>jHBH;lQQlw=$BOacGu1+ zF_c<_xgP@zu9K9UV64O#E9hOCFN``m=@r%wGq~he!BIvv+*a6HG*!r@@42hlJlz1? zXNY!l|KatG36O#cPKW*lg)o=9fbpXjZ|z^t2#JKF`9K1XBE%KDg|uH{74%`*L@MCLAZq?=v(sQ{yBm z5hZZ|9wt6&Z`9JtqcXa<2PAsclOs?37>Bj4N^}zwG6{DEo+% zB@>Grrn2dD{3y{f7YAH17e)IaX zJdbLfm`9Qpd**=$Rz3V@25!|bpQ%1W1Mv%Xmw2Y4`&lkj=k`EeM{85bw`#c3u=ni& z73=c`Jq~t@LLkx0!t?4Lu$j+RKaTQ+DTi0B3feA1HRl6)mPA{T$mPY~S9~ zo-(PZDC5Mq^G9CzZuW+*I@S|=i}_~}fXH|S`@9j3tFtw%BXP}{kjXdR_m4df+O>YJ zssmZj>Od|XrooRDGlKH}-^9^8zoHbYc3_#bO}Ujg_C-eDr8>3&p|du>1j*sVFT=3wDwNhm zljx<>0avS?cpfLE8wB&$J#5xX!G$ocJP5h&B&zYs{j-Wy25ppomB0^QrBUI}rLvlu z1K%?^l&Z`!n+)_vUA(*X;2vMS3d>jlHV*}-EK0_B9s=fUc$Z4l-6Jh&sunrrgROMr zJGtN-4EtU%>cm=GCA%<3lW`WPsyYN;%J=14?5Q5FZ>_1mT~mb1Vb3ZSjehPr-T|@U zfS@s*t&lvrC8d)DRg6;k+uMk=kER`RxFulD3gjfez5*lnwJ#KlnM^xhIQ80SJf(MZ z_R|Y0hY$Hrn`eZUVG>ChbwYQVIM0sdp8Li5tTWZ1&*9MB(IMLuC--O``mjrQ#Vp+z{=%VD9*Q~sg@Ivyx_CIHI{DMyZWIb@KwbwchO+S(SIE#jXV4weu zp>pmeMjD4|dMiEK2R`3pa`n}(>po}Iyj{XQ+I_jH`tCP)X0N;wniei8g6B2glS7L0+9J)k1!#XHFNYfY*?#7-r>BbE{P4;KzCU zHcF8p@G^_VkxQk~-PJ|Uk@WS6(^l6%{Ja#IOV{x;yB3K_hSN_DUOe$~HQO9%)iZ*m z50pb?pZ?NwD3PtaLa7296g!8hkpAs(E|;LbwDNqfFnPP||T zYmn$!!$F+{yj4#$*Y{YeB$ZNygkkHrt2X-^H3q&*gM~1#rhfgVRfitSi0G^O=)03VpjAx0=K1 z;85}^6C!Xsm4{t!Ptb*C#noSfwU=(c>GX1wK*553mMm4#qe}0moYzV0TMyA%uk7y+ zhA2M;^2{K_$nC%Cf1uTMX<<_5-rc_(mweCf;QpZE>t?~;Hw1j1a=9O;GIS`_P_4;u z2#LdRr~HqhR0(XC?IscH^gDsrn})HhJM6B5!Mlkp8nATa(#94UW_D!AtvEZ6-cA!qmOLb7 z=xU|kE98cDeVf2vX{lXlFV@@JHj(wbiZ^O$=|O>E@3)Z))wfgFYcGApwUK_ zp*TTRWNhQ8tjX-1s{CF??18=kVHYRXav8fo!y9ysEGbT0*5!o<=d->%a2Lz$7{G`o)S%plOD`ieqY>5|CHH*SPQ&UDbP`o|n2WmPYZgZ@kZX zz#TGWvOZqsjLCB?#l1tK3x@@3>>A9466@VpepKR?N~HB+RZG(PwI-#$cy;|V93J(o z(J9>1;L@isFhm!dtk0XKALx4%Y2_X@+1o6R%P+emlWlxMJJArgd>AqY>6^w6R2Zp& z*WD5-SmZW9aXAvs~$@k=_pS>A78pdI<3s}2vrX4L+ z$Sj`HD4+bfk$Cn(VENPUph?+emELX35;@G7_O$S{-XjWiFBVgz2@`$m-0%d|Ys*GqN3%jMR#;UyCuPr*B^FhJ0wQ za9WXQ7sh>}gRDYEH-zvB7uLtHW93FC3Fag2MtBG9 zM#uwvKYpfv^$h-hJ8Bvcw-;M`RSY0vK`n=VMkhqi%Y7|-wbyX&SD&FuMq?4n+Bqu$ zTb1h{#2&&fHQabUTxf6K$F#3E@xhph8sEV_Cmc1LK07&92x-|8Y}FH~{`{gyn6}bE ztBS@>33M^UogevB7RZkaNh(}vqUfo z*nL-g+LFj^K1t{6HWl+lc+~HDhKblB_v57&?_JKPbKBCwUoGG&5GSr9|>l;X?Yd~}Jht+Sq84YnW)*2K{tJ)fnlG2Z&1x7|lf7df!B zKU!U)|KNl~MZ0^2XT_zFgs2TL-h2kKoS=lyvzu_p2qQdrgn0hehiMqOn>O_&qU}mERwX@lMZZ?DqXiBO3(wkwi1yay)r(It~uh++6bCGsvP8nus29 z#ec_RXR9%ZZGw-nd7AxW?18%2#2$P_BD)RCG?`_=T`24*hwEN z)OXMQ1L@Wqtqo0IzcW*h4xA|W@RuzA%_#j%x&t8_Xvk!f9-D=8H#hsSZ?L&fpTagp}e0j3KIx-MBMKMo`G` zE3-dBYyqgemwS0-&mdh}jN-TA8zw7FRIYTUQ~iEi8c%?;j#z40O+y<`hEKpom0!nP ziA#YEUix-lj!R!nY|);tpgD=QGgj2#cC*&%K|F}gSOj4uD*R; z4Q#7}0_9x+17E#+9)ySXzJDV)n4F!IpK7MJSa2tpU(Bjq^xT<=@|o8rlTW3>#76vB zlno#2bvQg94)b%A;qR!fk2Wf!U2RwU2|uDM*H+|UBcmUXkBpqKIn-NNV^5pQWiySw z_x@Pbg@DicK{-C0Q}d=JW?boFGZ6#wU>S=n?dt@aEhTb?Rw||7q9CwwmQ9&t0rZ7 ztg-XV-UI2H=P=G6McN0QwG!}eM2@+qvjqxU&S%beM#OM-OL> zUuQE|3%U#-oy#Bh7&PAl$2FF#h^*?KykQ-QHafrL{rQE`lcb)W_$ov15Ca?!9 z4?Pz$ynRs~E!T6)p>PmuF`{Z$)v8s;tijT0Lfd)9zyGvea`FF0ULCJmY<2n}5W{Gu zFK)HKXd@id*2v9hnib1-+K1HPODa#)sNvUe3RY0%WI*N)mo;m z7614ezgVcjlOW#^xIqXOpE)t<&SMwEdN&&k5Z|$%s!LX2=i`Y8sW+WYtn^VPtJ49d zaYa%e&${X;q_5nYa4cqgKl_zKaBS&K+e5BRsW$VY@d3G)C&~uB9sdY3Zut>Y8`Qj@APA$ zgWQkAxHW|?wlYTqF_ycbx+dESO1wKAQ z#wapUX~-Jbb-JYmuZbsEP9LA)X5AC_(w@0QGT+c4ly?d1nh@mVId}4)-O%q^wboLJ zkhh%Q=EkPYZP(l+J_*H7`Lk;!D4!_`4Z5&DzP8G()u?n@M@28~+xZ&y1t~T&IuJC^ zG*KR?8*ZqK6?rUGX}{_>fJ9O?ZTMqTVyR0f)!n|M-pO|bI`3_ch=*%ZVI=z{v7+6 zgqnPRc5f}mo=?HM;tQu{UstjF?RL)(YrnAcYUYZx{o2y#oug)lOB=o))~}UqD$}0f zrp_7WGlTgQ-4qK?WsQ5h?A#h@iL)sC(J%LYDoAl!Fa&s>tZ6O|O4vY)i(<9*;j9ny zD`YNT@6^JoRp>2Octp$_r4q`?9c^8pz*EyR;Ek!Jsm>49Jrz<2R40BF4b~wD>z_6t zkRKK6`O+Xj@@3TUrJ}3?KG6g_x@2ctuwOx7Tym!~9rYtP^Pa`3ma|`5r#U(Y&v@;} z7<0ly;n}f@;At)Yqi-}^A59gZtKExWNx(oik_DueDl&`BkvGA!X1X(&z98 zvZRg74)G#E&{?3a9O|O2sFHnqqu%H|wgNwM=CwXS! zB)qr9{p?&$i5nPrN!oaAAqalWhAshcj87n-(mV)NH1xx?JCA7ZNS+Dg4P1oHd)642 z4W6#CQZ3LvghI+hC5$aD_@%P;)VxqWR}}i%4|3k@BC5iwfvv(uE=sTn2*feYdFG&I5Brt%gv%+>I;p;(d2%t$iZnj!Zh-O9ADFujV5kBi8D$&e(vvtN8C zTqfrIV!w2q*Yw{X>#gFlCMB;8<$z5X4CeF#=q`@2jCl2Rx!Gmcsw7EH!&mi7WPxV_ zN)HecD+AKUbF&}>35e3d)F+6qy3$s1?E-WV+RXd!Y$q{Oeh?|W$15B9K?2j|HwtJK zEQ+KZjx#f@)vHVNf)0y^k+3CGqvh#f+`$xw);x4PPbesS3EtsZ<-+IE~ zF4s1LRg|&q{E{H~6f=B5e1RQ*DV$brsD&O|>~0YBsPfdyHJmld39#udJsY0-(x^h7 z5a7Kqz~R7LRK{pOztd`H|4>K*IxKyXb0%xJ>#NzxGoei9o%{<_e&pRywx<`RxF0^gEKhw+O0w{9=wYUFQcxLo1biW*q#PVSmKZ-d@oUb@ zT~@l)pg%pUQ~7R8{6u^VitvoBjBH*%rfu9TmNEX-C zsjo+}IFOB(^}(si!nLB3d>Z|zlWtQ%uNU@qZj40C>&C+-H-5ZXIU4jaZm#|gg!$SO zCs%5}zAf;^l;VQtW(LFa)wuTLe%h1=ZUX(ajZ;_yC5;)vBUxW+fE)ufEI++9qoVy# z|H_ivx+%w5d@7;L)Pw(@*?w=o@}#~xf3Izp(Se3Vrm$--_b#6gjup(}dd!{NCrYQb zTKYsy1nZ*79?Ov1>nBT>>?CSaD-66b5rwZHj++US}=<{BprIiVp9_OF*-nx%H21=q^^ zqiam2YIB7W&K=nsYURs67&iAKEEeFD#Bjd&F}aQsiD0JIVXTVmr>Nvgk<^sN_f+Wt z4_T7any0YuV|&hyursU$S+=g3u%>uqG==eq|1y%{tg6Q4&6fej5IAOSxO*eCj~93@ z0y+i`34E}8w|90aJHK^IQETIq;Jr>~Bc z>=U!-d9XBExw?6PX}g;Y1yj~)#27Z0(P4n>HMS5FYh>fjk#`bZ2jJ_`n_=)G5S@Z{tQDcBTG2@ zRt!^eE=2LB;#0kjDlZdO_H_2zWEuSPO!lAMN3bg^e&;_TGVfR_X}Wg{WGT4u%({pK zPl=3FK2W_YYGQk>_T+f63!K3JnnqgwXQ2ErB|KH7pUz9OME zM}O5eWE2q?<>$_A{XMtnS?1#KX*a3P?w8I2x3aB$A;rET(bO=I#()XXyxZRD`{sOjTnnz-*3rp4@+}U ze&>XBt>AyCx2KrL<`<(-4M6B}BVJ9qD9djQ0q3wq49PP=PK9W0hvcGi=D^z6=e2O$ zRl^Fn_1d*DPQVzJrgjjV0}mFJ2zW&v^Tt|2a4!T8Nn6d`G$rq;ru#e==*x}DmZU5E z(0#Iys4`0)V@wzfyb)Bf0sV~kvx-i@Y z)2L{0(#_W@_*O0;Ia>RGed=&+UYdimejIR$45~rXu&-J;3vS}8JpydJIkI&;ogCV* zwk^>;-&C7rr=9G4QEB$V;*{3g;Wq_)1kK#IRWdAkP*wG2_q;P=1w&ksIx4XWsa5HA zO)8Vr9kA#%=9I3lPPa}PCZ;zjxUPBzXxvtdZD$NR>z0u?6PcLluRe3+?2i)RPjKhR z!qCe7=S;c}2lZlJ)V65mPOJg%KSSm>E<3$0^e&PXa>4UFV}iw2Tfp<_oMP&h45uW; zxs$}lblbI-9)yiM0T1Q6I#v?myR84&Z&*ldw4+1Y={MA@H?oNZAwmj&*<(=DkZ7Ap zNh$T5Cd|q@%J+V^^)GSQS-%3B^Eb_U_D=n56V-A>y|3*N=efxOn9yN$oiqdcnCkQ+ zw^uxrdOmXnC9()M#jrQOe(8uTuNm&rWWvPG$AJZ##4QcZFuOL|1P$=W)W-9Kx*n~~ zv-bI{)8D6XKV4J8%)W%bb4kz|W*cKptz~Aqz-N-en4+0tb*nZv!&z_b9-`d^l0Iot zcD<^kJ3k}QApU6=$5VrkKHZ;`@|#2lhCg}drl%Br%CNrU#~D987_YVLl9&Zvm%H8F z+kEjj5@r~_(3(e+x&YJ(N>o>G03<0oUR<{%Q8Jg&&r${PKGTklCdk|DNvi2l9%JIu zv753p`}%gwq*t^X6IzgoD=St|rSW}#`3q$7MCgdZwA6^?N71j6BfOyoZ|jHEnvbYhoR_ZRkHO^&L@{kdD@N#n^zl02UokE835jT@P~O%9=`0p=s=W@pkOu8q!Oa zDyk<(9R0Dy>>vIIgbO+P<3NA|wb9t^R`H9@2rJY&gbmZcwOj`9hB9#*O9<^E7O8KN z0ZJb=q}%D#Q$1Z5P?kV7GtU?!*QsI~Tlf^Ili5A$6N<^!_mN2!O=8se=7}w*Gq|4C zC?(F5@3<7U7;s#2qSh%!0WfCuzOF2vZK7gddEOCSns2kzc;wnD`PF{1IfFf_VCm7( z#qut5R(N}|owP`5Slpds62mR-!xjYwX7HKr9{_ohn|a_b^kA|+4;u5rYR_1PPtM2P zZW4eO8FZmM3x#T(?~2ZxG~~3L|7@k54;Z@RVt>wN0m0{XIiH!zY_ew%KXc zTN1br3ukicMO`!euswoqcMSHq)LOB_(~OcBlGD;%oX$uVxhSnBX1aI2L%9c(jJ~<3 zEK-ifJZ{l6@gC|bSNT3XL&uUBXH|&(=p1+;>B`b?fmU%>WME10rP|*KJqpu?h8;_1 z+XnT9J>WRy;E^>8;M^FGc{3^S(ujXwdF3*_z}Ux2)oG=7RdhxKQ+{GXb=+OFAuYbx z&kxxyx$DlKNo=>L!zL3-5Dap|Gx!iQAu$++ubI6SK7KT>KiihM8L}ltcm;W8GMf z^Q-VoJ8%5YhHkceY*Dn`6+do^(LJbgEY|*;orJ3jvcPrR9?!aZ+O60?A|}^plwDZ> zmPZeqz^ogl6$-BpjNls?$>lNNMRn6l)jy_}YL@YQ9jm@9!%Jyn!kR zmQp9uRyBNP*W65e`rT!%-WsjW_}HeU@f43EDI!9^yYE`_shhk3jD4t?FhG)Y;A&jJ zVx2>NRW|N>(aJ^gZVqr>PUMhokYrZOnUM&Fe450x^peoriDdl%{x+4a4b%2ES7f`1 z2nHLc5$dbt+gGlh#HbJxBVNsrey;IR#1k6*s$qfJ^!TCoG2+kXby*b+MrLA!+hv%)3I%5N0`~bXqq7$-*g-ZKwqSu8B@kqjw4Q1l_%k+St zm~e!`F*A+Y+y?`ZYLK#$VB|4ZjSZ$~f@1aceOVq$OTS$_;>=X6lu_ur=G}TN|J~#a zM+BEy6MwQ~gi-f~-T{WkXH~g1i>=ao?2Xt89d7q6S{YBi!S1(zV9+I3mt1a_QSR#| zn;I*qmN?eVp&kfXaD4J*wHV6|2@sU6 zU&F3h*N)xY^356VG{z~n>ngD^C055(%48;1Kk83@san>J{^Hi(@zsinSrA(|&_j@G z8pm6NW!b(hyP%Z`uan+C;ezX;g#DQNuW01n(YnkG(~5IivUfA;hP{P?!iusp?rY+H zFF%CDzpQ$gwbv{)!)a+c+dy_v@qW5`rL5;2}l0y9(r9CE?a^O720r}lHev`P=TrVhu7Y}^=QJ=P6nGK4n~^8r;X*K|-tVHz*;LaT8(jE}DB%3R|1_xC zYnSe7R3YreaF?i)u1xWHq-0#gU0FMAAW{z;bXs+~Wv?>boMmWauTzoTQ@dO~S&x0d zLWuc7{fQ@_dcVxj$6H8mq~9QP-1)!1y~3^GYHtwEU51un@oQ&coIQHDq%Bs3nC6Q=T zC;t&I!c2fk51$~s`vTEdz@07E{}s*)2qQ@U46u$wKzqS!3HW6f;w2(5>5pSk_sn_p zF#SO!n1_mReBQuMrr3$7jg#WwI`2z_Cm0=1IgjYqK3r|GG4hygl<40uT_JM& zr4Y2$=J*I#mUQb+>(Zw|lG>fi?1r&Cz;zd0fI31FbFG^Q!0>C`Q}h*UqsV@^HwJZ& z6^jYN54l$?(&N{|vQy@(ba#WYoNa-XJF#7dhiJfhD z`_N51M_Redtce8dp~OYUi<<=G%Wj|8#E0%7rEaql{&cJQEgLvD5SR=f#cs>~bemXb z$29+wh??TxvDDUlp;M=bMyb+M?4vYMVb~ccu~46W4oIhi=$cX#juRLJq6?)oUBmdz z>5diX5f}rKyh%w#Jft>-Gj8E5aI_Qv>X=FivDu+b#3VD+Gl^V~yho{5)rJCtDx*!A z$fLfqIR_7l(AT{U+)oqfu&YjmExn1bK0_7Hkd;s9n8e80H@iWb#{7SJf%z8*&r1(5 z?+`fP_f{KNUDSF45cUaCf?l9BJxz#GkxS9yEo@5viA;rdU>JZPHz^V%Z&NN`G$|TJ z6G3e$g8tZ~-Sx3VqCo|PzM{lCxwuWlZ+sKYX_i!7Ce(idCjFePgKIgi|5>I>gl{to^n+j1 zvJCL{RKH&Z!2U0x4Xlc3Eu&w620RRqE=3R*g6Gk(~TXi+yIxBp6N5!Hq8JLeijd45CWV34QrA+1do+WiyI{ONH(lPE%jUkF-C z!V`CrsQ3h+=%*CK2C6|cBm@}HMM?tWs6^xs0mj&Z;_L&6vnK$tgDBae6nUaf6M*O* zQ<@S|l?3#JBG63|P%uRxB@)mJia^&%Kz}Fx2@@qWDDo-^D4JqVmq|cz6oC}BfkL4a zfk<=;rAQ~UGsKs&5$1R8GFkrwkz4Yu($xk8+7<*!aq|2N)fC?i+A%0aYMBuYE@4d2 zH6^lx0wS49w1os1=qXC>!ay|9wi194FL!K;A?74$RvQRLX1ht6Z!R_;1vTFieGnP& z4gq5ia@j_Yc#G<$B_w?BVIYq#Ab!2THg9qIE8@|$03@Q3qV#`TKAs)>d0V=t{V8!x zQHyB$hy%+}9QfsSPd&FO0)>!(Oeq3AB>_281R|+r97VMZB5_`oAZ{BgM)(CI-{DGn zBas6HbpG3n1-Gr4qXJ-kT+n@G%ljRCu~R#@Xt(Y`=x=7du`{Y(-u(l>up@( zPV9oOQt!;sZ2`HE#Of$u8M$_5nYUmD%p~Di(wmDVa1DACkU#Q(QevI1*JhR@F>{=q z-fJ!Za1qZuig`i+z}OL?(8tji*E?{0r70sD>@nO3tGHXXG~*EdF6QZUvwa_rG3+hm zz=0TQpVL@^rv!q=MkrFBnZ2dGk;OJZCA$h!g^m591wm7+k*5g%2Ue}3b#Fc3_}j5L zn_I+)jBru?i#8*~F{@0cb~ae7#LfC=1gZcD=KOF+0z83V!df17@kW&jX??f|?9I4@-7s)!`22$v%{ zv0*#6-nV*ne8-N8bxxnaTUdnc;T@4RO`+C$7?3yZB!W20^DL>N*{JCo&^@3!#;c^}QGC&LX8 z$c=}9i~JiJ8yic4ix^F_3(ihX=Zu+N2Y|#?T3HCMo8m!zBFscT9%>Luj@UVw-xWa3 zG0ShZEwA%|t`V~Oj?`r#xRQh>4CDjIjy>Q?;@$r!b;Pu7I6(W(7)Oy2DWF7-nB5=_ z#vDLl?vBT|R~lo{-ELB3btZ!}p<9$DBt*;_5C^+TX+l24n4Sm|{g}dpT1fryo}z#l ziPNtc$a5N6LK5xQ6r=&_MS?j(0d@5=+vGWM6(LAgAty=x=4A@hkvAYwP?7@MQ-ijx zggO-^n9Up|fr9F^6kv4awx|4#j{;gbw%ZCN??geNjEhNgK1miY#Jp`xO`bjoYJpo% zi5)Mylq3U8%&nIv1o%j`JrslFZ2Q#<&FuwCdd+XV9d3?MlPmqTzy0RDOG2Z)`={fZ zEAZaJN5+B`nt)?Wffk&aIrgDsj8;9N$r3ncI(fq{(DLr4z93X(qz{5deL1)uqkD+J zz@IBqRaO!xc8HsYhle$5>*O9c{P-R>wGCI}9nais0SiM&IL}eSS&D@7ox>DF%lt4g z=RoM!LXm<@j1tp8#G#{)QD9WG#5SXh-6&0{e8+?+$+{ zyb}kvk~vLCUBA`0f)@~-&)G{9=eXZSZ3PB)`C zAHx_lJJ?!ob++UC_wU`8lL03Bb&E>G()-PgFDxO;U*GQhMa)w{f3!KV6=qIU?apbV zc{{}noI?gwr4pKcAl_^bsB_LjtleR~VUUmoG>GcRf|~;AG!Q6!8W`m@n|ml12PbEI zOilh8w0FsytG~o;ty+s%Hb8(PHR#NzVBipbPi zl32WpEQ(*S=X^BdfSIUASf_oz=y>BQc}7&of8Y*NfNLXJ zl6NO4zzDqE79)8R3h3!xAj$P^vhE?E;+iDx2T(9H#!pG4JjhF)+=!o~C4rHGGD3Ms zw2aHzRZ@CG?GfU-;hwqji6csBCE z+dV{U0l*?aWcvo<&Af;|CJQ+BG>n2!xDbO>;<&;CvIYF|y?=Daf#M2~)PV+iB4FSZ3kz^^9D3Iy}$#$z#vdhUNyR0rn zLBW$rZXO`bFUVzUG)Q)0V22OBO+vz#WYTmHcuK-9zKs^B{0arsMM&hC<)A>qU}CKg zaeOF{^&^`&65dA|tcgObf@mR$NfD(LM=?gg5N6dKvX!a=HN2*vqKa<>3^7`rB>T`1 z4K+~Z%E1m+^=}{uoB4mWqF|D7%Q+AD*x+?kXFvWI&Zt+IOv-(kWabd6WbI|wwa!Aq z?g+_)0=bc0ArM*O2E$U^Kq(Qmnk~$)$%PJg096Hlx5K0e z8|p|d!+MyME`nYmmpGOeATjGW*<`O1iBr1aVE=aR@2V|Z8rWBCv*euu~{zL0OPo(~Vg?|1r7C*1l@ z`czldEk(I7yP-B23RFJmkp-)%BRDj~)}~4>Z-62N4Dvv+-xe_Gb6~Tkjd(#+kz5z{ zJGubs`AD~JeH#!bnJv++6my-YS2SnY76|cEie!shPLtcUC?dte& z7GQ^U)FcZ)s``LFAPYc>5TW5@0Y;TU%cwI~n?6H_R~E{p;m8_AdLFyrte}p|LMJ^k z_KN%vSCDbcvA!w!CY3vJ|Iyc1%}PB^%xS-}HkDlJQa;qR_u$!)uy;rFOb_olAGlW; zcJj6{^4A+rE_bCXngY^rG!}&|Zyw8gi;D02g|mZQTxdf1RTFBSiS2raq%r1~18yap zXX_H_^ZLW>coTF3j{X2Q>UAFwB*&~vJ7nrN2eNp~oE%h17R>pnn1K$hh#os2soy!3 zJ1|AS^6-v7%wNWS5A=|;?O1$(?|#(5YpBxU)(%G_qJMHiL_~Q?^pi^y=s;h`Do}!a z$;YS}UAUS2hH8D+HhhEzRtfFjyjxR;y6Ye4di$ABs{2MG}G?m$$y2CfT#COFKSK>>|m>j>}tL50KXPtxG#TukUc~c3l4RRetyXgD6`+ z?+j6p6DDNFDKtdQHx&y1B3y3q{l8$yyWFeXY@2FGrmMQm1dqS@k1bR5H;_6VNyYyD zA7Ejr7PSR)lc%0}S`gmC%j+$0XLxwivyN$8H6`2tefIm#@uS!y>SJ-c7>-IWLLiF^ z;vf*-#7DJ?WMZG8SJ^<<_3SrI?!N;OIzo|B9Ap6gpOdihoRc&G$3RdK$_#?ioik;= zvkS!h|4F&~g@!EqNx2a+w7p-bV$M#CETN;%&Iyr$AY78?Cu;HiPq(NQ&ryOQ?X#1E z_`fo4tX9mQ6A3XNx%O^zXHZmwHefs9`WM_g8QG)2rIyQAA`cPDqvekk+9BnNCT#jW ze=vYPTFizm#D;OoiCX@fyMR6*E=euduWUY6qiO0i*Rv?u=d$jCRnyx84fk=H``vMv zoHe^084HXBmG8w!br%38ZT*cUZ(p*K&w5p$FtUzoMQ`;KMPo&>UzR6-NvqKB51<49Q4w* zSMbr?TgblPKf0J!M=(Y5N6!arPQQB_7`RMo{KQq@-OGI<0-Jr3eG&&`K#Yv!PZ>P9 z(@)r{Yf~Y!Gz01N&8-I3iKUb9`-CM@{1Lfe0o1Ztk}mr5_BW#A*(FRKYo<-^Nmji$ zbWMa-06-dX_1|cTfK3U}Z-CaY)J(r8h}!+#eJLOH0k5d-8`{Dg2=rjH zay7(7WYmF37hbYeYM_#Lmb*d51>y-{4!`AI-$2kiI_WHZz<<5KwYKVl(cKmORni!S zMi>lsHObO+5N7&!>*kZ#%y)wjlfir3U~zJCWCR)LGGtpy$$DQPP=3Ugb57p-0zt(m z%|$L>+?+w$9Q%O~#t)FF^B3s4W~3d3o6ucw<3k`vE@Fw#yT)V&?-H-|ISUb&J{D-l z{5n4fQ8Dtzp@wR)fh$I_VW4+QO2y|fzFUi;&4b@fxXyl`(T7sXe7?XW?8 z7a37|#~&y{3mB{5?U6JuZ>h|E|KifFogUtq&d91-P+0HnZ8|m^yv-M z0H_T4PZyg%p!f?KHUHaEbExZ)oQy!SY@X$8{j|e&H0|vgic}!IPJw^z+X80ILx}(b{@WI=fZ~)K#kP2Y z2s}(_-m`duGoN*?Ug2%$K2UgLqa+{VCG0uyndQC8;WogR)rLJ>WWAhOA%fp#0GkSI4ziJxv809`{Cdp4 zazNo0;~pDFv3g|(74Uk?dSqc)f2SelP11~ubd=A&T?3PS)A$_8g@9fN^wxE`|qqu;||g5KVr}*SWJ#-Dgrc5X5)q$mhzZl?@I?Y$|2; zhvdF7H6@ht%7|9L?a-Jr_AB#W)(iSQnk)~4vg~zM22sNp_Tm}_gx7&CEi?8UY+V?N zvj_9C*D{lwF|n#AI9P~}f!udXAfC%d1_=+k*11U;yCY|4BKbO>Civmk*!nz7o|DO= zflh3e+uZzZ`VH^r0BNmKzOs=l2K0~$6lJa+XKGdfFTHj^9VfTILG#-I`^(KpFs%2p ztKVaWd?2l6AEM9SCDc=$1!g~6WJuOhz0z?nwZG>KKrQnth)YVvt>RAAUu^!$M=<5` zvQ*P`vje1*+Ez%2t1 zS;TvIu5#L}7MoXbSMc-m;{e;<-JpyVF@!ontFXMBSM??(^t^-L%Jlt72jXpM6mOd# z>iBhC@NcFK$(YqDSzIGM&Z_I~6Oqdqgn2%oI8RaHJWr2jMkjcCNiO^@ixS7JHT(C~ zzjp<0%m>U0d7`|-5|;!9k%M>e5$`eULQxX39uP?DQOm$GolL-sm5)6@X>BSYRtCJQ zs;MklsBSZgXKs?)c)l@;P0)?^T)zFX!j6!qEK#7u#TEl1KR8}Noy#VMc_GfF zY&qDz-Z0sckzog2asgI1kbP#gNbjT(smFis!>xDa@+_NVYmBv}abesfzGLp4-ffC_ z`0&$ikEjr;^TAXtC!r=Ml<|8EnSXgq1w^jyiHp$L_xXS^bIze%PdV<+%Ey47`cqy1 zctVLvnH9+rVj&t+i^684`()fGAM{q7&;9NVN0%+FLJw_t_}l~DFeB@#>bl^AE$4%A zCpj@c?>$_{U8@_S!QH!YKEhlp!W{Pyob0nuD_estX6Ypz9=ii!dw} zn2H&Lg<3x}qlY%IxGysswIdnmjQtfZCSdPi6F8(o9LsVK z&Q>*QPwNi5QiQd};}Q-HqRyCk!hb=~N`T5Bf`Iqj{`bwqn*?w?auqO9M@L*8Pix#T zIFg~lH6)&t9&G;R_MOoQ@Jzq;fn!%fbFnQDBMi;}OpEJ6KWjnXmO@QB!DwFXiT4Q= zde)Wv!03`*%3`0?C+1pH7!viRMQ0>OEU0qMC~nwG;Q!F|-EmDW%ij@26cA8?pfpiY z0!WeG6%I--2~|2s?;yQPQ;Mj7AXQp`(4`ZaRHZ6N4WSwkLT{n-K8g37mwSKrK7a5L z5}%!&o%v4L*`0tYrq=HC=$V4_D;RC5@zcFrGadU57lEkuECIz19{59W8E1zh_}W^) zHQZX;@nIQ#tN%Odj>Y4fQ?MkwFYSAi*gZV=zXCj0@TRD6U?P;a%?6z?B-lZh6nDM7 zUvUXM}A_OVWjc z!@q1|wK36^dmBl2u%lt6tw1K(TgP^KR8V&GEhcQ;GC;gd>Tpr*WIsQydB<#Y$E?h! z^6pXK4>v#^1I^TpJv>SOn~OVr1StttrGnn<)R_v^h<4Ky$Y3+g$Xop}k#K%8;c-KR z4mn%o8zdmvFJ)elQday}7SI;1v>sS-2b|*^+bs)wSe(@1jM@omYGtr#f2;8Y9o|b=Hzr-CQ2j5e z2b=`s2DFYTBWg}Zz{9+_TeQRCRB;C@q~d4F(Vem+O6z72H8)yPm8>~BAvotin{$3D z2`kMOhR|)Vdtlh_7Oj!Cmjsqwb}_szvKHX3IpI)k)V`wdj8 z6d$<>U-+M5)EB!c>Zy3cj5m9}s>dzQ%nsM|QyxDx6^dB{Oo>FWcg!M;?1#IAYpn`+kG4;-1*bUN!FKR*k@s7C?WL34 z|K>nC^nw~V!(jxoxo_{clWB!2_A$`!43#(kh#RT4cWC77Se-9;`~ITXyue7PT2!rp z=7^D95~loT1JH_8zt~89BEea(d!ek}yNunnJf1XR)}8Zo`w(>`cKRHB5;=v=k%H>u z^@yR{F9D|7zb5 zUWE>k2h{t!y8RcyZ^liBtTP3%TjGGZLajG;mG7sjUnmV_4YTZdv_vv1iKS( zp+-*g(&%C=miwT}fj-AA!I8bJ09l}K*r21#T6AqD?%4BHz;=w#%IS8%>HzZ_vkc+u z_#q$u?;#~IZu%#;PQ9!R5U{1YE#WVek*~D5hgmQ{&&Q`MIVMS4N$$GgRB^+-N{nWF z@fFusDsQW(^c7z!SaaN3JK9n{E;-0>O2?-iRbCPyTVelYR}}=xRrX>`5UVK=XDgb6 zX_)H@btfzAQ(NZhP69HMBN9_pOuM+$elOeR{uPxk+GapoC{Og!7W4LE_yF)?kV^Fb zezPLbd)bnmo($cq@hrFbb^pV7sZh)o^6kK_D=OZTsF)v{OYI2zXRb^}ism1aG36Q+ z-D1}3aVMU6Cu^rBgGVY-VbS=rGl8(2|0xdEP{U5y%e|%sQ@&$DA{{N5=%OvBghp2%61urb8|Y%34rHg_x}TgN0dFj|*L@qS@9do7GPA=TA3x0ImkYjAvhUGUSrl+c zg50}LSf0Lj|9g4n)Vr|v&lA#kd}=PjTmja zDHQR0+PM{DGYu!?Up`Gggx8@2fD@#Zw=XUnGS4W*e<;v%G7gY0Yk-NooS|)y$oSVY9 z?{Q%^`@Wo!wf~3 z8p)h)Yo89E9*pcVFGw972H?1FCWUXf0jPT7Gj%xGYjl$T7l=t)_*9ibx0O)j#L!P? zvAc0SP3(M+Ld~ZDCES6TGxK?nr)|1X*S}^f`JqIL2(-$2)k&)kixeCwx+P2udp(Po zT8Tgp>vyS##&y_iEPso{3Nyl-(E*3_r#lNLydBixyUg|e=WEzb=cEqSnkE8pIlvus z_fPi&_KlA7)C@_ScnH)s9oQbO(Tpi-oZVoJd07I>jDS3mS?N6(6?C>ctU znO#cyBC>ikGFjL~1&$^p1jOGR5+R#5glK}9zK;;Q16TdfTmR>Z0lzoT$={y-6`#RI z%dI8yA(}_Hc19P>%bAA0ZgiX-d+}+?DcFOsbt7H|yzdxyy1sUbZeojW-2-fr<7va1 z-`YI)smASpd$oS{qJC{+M8+kQKc~BSeCvt!;c*OZszvzvTw)iUnJ&DHtwZP(bs`i$ zC%l{7I90#zr5lCW2D)?J>1^bV$e`o}LzFCgC}ijkQ|p6py^jy&&7^FX7t)UH9)|2K zSuGvk<*x@$0-xX}PCb(nc457HjZzOMn7jzv&!_R1tv*k;Xm2|t2O-t zz@>@?c85CHL>t5wy0kiuF{nB062^S$m_NYypXkXEm^sZ4H23}w2S24Dowmj9fXc%> zYEFZc58SSni(oPuqMS&$8$xADZHCJa7;>i@Mw%ol6vCH+U49?>GaM`$$hErjRW|=L zYkEM#)I680@TudWLx+ZaCsnwMBYRds*JpohwPwi_Q+7UrBwfBbJ@{b9!9$EDi`-{W z|7r*Cht?|6Ry9b(OT|RjF0}vT*b43KV|UIf$0D&X9GI_t#BoT(H)_fdS8s3tmbr?< zezN8T13wXTVFUFS6B-r(G-(=`^S$S3TDg$-lu+2VTYL^>u)kcjt*9=;7x1v0hUoxr!iCP5~JI#22$IHj>s|w z_u6HT%J=7mzo(Q2tXzSVbbKCP4PY3L`w$~Q>09U`B~zbUzhn#hg0`sETLD^Ulqf@M zQ5v#MMPTEW{2qZ41>SI=-L%wVZYDeh3TtHll0? zWuZoy)GVnl65a1Q#zfv{yjrkXL$<-yhTt~y^_k@0eo^O>yT&fD7H(3`h$~0Am!taa z2j5iQsHV3B4l07yZ*^gXl}jS9S`k>``({23?EbrRD%X5>brkX)lZy#$tIAy?jp*^8|T%FEOEw$-o03%Ta) zV_k7|k8(t+y=GAGm@Ii~_3V+(!A7nx_1u+Mpq&AFyKGAEFdb46{8T4^yzE(wInZ7w zW^edo{e4)37uO_L!=X3xZjr>O#-j=Am6(P}<1nzF#Q9;~_K{o6AOy2erV#|KsmCkxCaIN(y)=YgU?H z8WiDqD#de*bqV#L>0Aan4y<+Z*uh5amonFa3oelGr}`yq7RT(c=PW6!_q?b%orOyM zN~hIqNV0{y1p8Ot=t4g$J6GRu?^W4o&U^v8(BjU1qNR}*?gwm6!-m!jhakr+xV9Hh z?V7NUp^I#ZRoA_+F}LSe-Y)I7V`I_>-6V~k8~9B6Ipf{ zbF{_qJFV|K@@e%7s?wK!PU#ZC&eF2q+b`T-(PN!2A?xWJbsRTEI?wYSwbW~@gvALR zDo?9@Fdyw#UR1ui+F6HM@vl0K?J{v>ILKr;1cynkO=VUBK$oioFfbQcTa>E`{c;0= zGOrvfCQX;az@mGHx^+H~$rJ2BisXL=ae=u`Mk=sMqe{0ec&URI>Dq{&bI%AXtfWt| zk-Gxrpgrfn*y=tcymm=)MPMp--dq=>E$dLyXRhBT5TlK`*z2EUy}FP%gpXr^rVxdx z+TV`iGU!}AXbbKsnL~G?7Q#GwX+&13zYQk+vSBaR+d;Ykcl55*pdgJQYtI5Syy&2Q zv@k9s+FSq>h4WF5JPYc}_q-{qCLPu~Otd@DaP?g>%Bg@Wn&s@Kla-oD!&>`0^fAAH z%c6nQxpuolYL~SN4AIV@S<4J{6>_s`G)%~uNm{(xEgG@eHh~310bJgIe|1TGoocEw)!G6zT>M z8vOFB_aq?&x1A;e@AlIDrBA*xS|WtitZjfPwPX6PLaxXdPE;NWJl=p00Zl^F6?0v3 z>mD4KjM}-Q3~Fmr=gC;f*Pm!Qh9Sn5ar7%MVk%FBr*_o!G`kOrzZ|FF;625^t4m1R zZ`9@Vv7nw;JF zkG9m)iK`(E2Zx<9>IrdG=)iE1_tvx zHnmDP_D1T44`~-|Uhq`ZbnKicPCjh88p=zV%q~-(ejf|hS#jrXwTSQRHDJBLW&7qU zGE>*VFaeQxNAicp$@h6t+FF0jz|XZ0z}Sb{EF*sDOUQd8Fcb7omG?O=Cbro^=I*c! z*r4*(q`{QqQ{ptIrmCfIL@m}uVx=iX!2hBl%{33))|d^_PuFhMrOW_@a~82Jj|-FJ zHgp#;N*zdBTaoyw@w|Gn*u&X%B-(E+^BibBPvNQ)X-C{am4SC+TaHqpbslZ?`{~D9 z#z=i-%BZ^pFVD%}U*Eufjcoa3sf0sU>{AKZvj4%M0={?I-;Z!2uMpPv*!;AvX4SNw zUG1xZ>&|U(q$PLm`8fl73tRR)yXyr@2a(F4+ZT0o@(v|{8zWq3_m^M$G~#(3?mnZp4`=iw9hb+#u%CkApkd zQjYBD3=Z_(|J09%QDI60x@IUzrtF!9C4!i{W9Vm9=p-oS?;WrK7{x^fJA$ zbV-<%?Qd@X0#qSl_s)#7$<@Gq0h*flNLmkAP*;lNs%Vb8=&~pKitBgb1gUA{jz-?_ zu)WVBaeVG4auyZhAeg$W`Vf$Gxfoo<2E;GPOB2&|}Qx3hR4*hKTiUe{qpZl-@x1!hMf^#R1E3k{PaxbT^VJ7xkXd3mR z%=FB+ZsAw0IaJNqgW>O_Y@p1+29-k&{sW#n`Qw`13ubRHc9AylfkuE%2fGB0^DiS| zn8x}8)1it;Z*~ppuX9Ne>`Coz6x|CR6tIQ3h1WLwrh~tpS)-|wN$KE3U!0w@jzY>) zRUsAAy+W7 z?dTjgCMDT#gG>rRfQWTw*1yT6o=ZgKsII%#%G7hZe%%3_uCHp`MhXPAoBj+q_dxG% zJo&)PG797ISLK3wp6FI1>wN_oYXlFsig#~hS2-jvzTH>DeEB_nMB>KQv3k%bey{WM z)vtpHn9Ukle%x~x8(@vB)6|Mxo{h6lC8USIQF6iMJTw(tX$|$agH^=N>sozRzL`*8> zl-u{sKVDVt|1gf(60Yh_7?{pi?tire%xB!F$Lxx8YU}LBg*qT#8nr2!X2F+`?3N0> zbD7H^7SVSv4c8aCv#CY6z5|q?cy=6D3G zzFqB+NC=0ulUB)^MOhNXw{(i-4;|JB)55KxNE7zjw-;3_C`OgdO5gnWm|*!yB|o)T z`)iR%Ff}p*gVy+f8Y=p%|EB!DqNcV%!zhg#^25dZ`Q+`R==zk1_w#C`?X8t=NVbwj zozOV&)vdd`W{#c)`Uw`5;RwVr(^6z(-cpe|AUT$fr?Sm+F?DL$7AzzdW`#*&kac^O zj?CV%=Y%T)oMwO!Dg57ZF_Rn}WrmX6^X^s~xnIkG9BXMlxzf#)U}tAnlwj&Z1Rqbl zo)Rmq8S(`MeN2JF$f1uOv=qRkC+G*RKMa!jgrfzXdibF@9o~P|XEHfaR7Ms?V#-mA zJr=?=FqWSho@>kcjf!u~VGq)AUEN;WJI^keReB2c?c8v>(Xu^}lQdlP1c*%1E33fg zVj43FXt@hM7qWh_yEi`JebCSS+ZCHZ@OGM&&guwW) zI;7c6o1D+1bW?m^KM|!|=_{!eiW`{Ds#=C!&E0fi($#O&Q6+Y8?KgQ=t%4o7-SHz2 zh}@}hFV;P!qXzH4rG0O#vP4Ipe)J2KRJRlQC+W_Y*}N+Jk3&Yelk2zl4!=(c;u;w> zn3~rSeD7J4&uJpMt*c9PKbKs#*0W53*TN(vS8zdAUtIf1yEo13DdnCWAekow7%@i8=g^xgF?cdS9Lt0}^ikQ2~IALOU z@rc!fKK-v>7E1G*Rf4XQ2o85Am|s%AHnnkp>R;Sg3bh1^;(fswH}N-gom>kXk9p?4 z30~LSy{sA`DbPpD%9Ms*N7FVsjB*&H&_o7n5QJrk&1nfMFkP z02@G;vYlqfZe6q#eOGvXvH*bZOK%>AE9bmgiNB^oQAJ{hwP1N2!zbYb0dj|FSim_m zh#T2p>+sH>VJZoZlVHn|t94$(?|6Ww(*SYYD+<_677AEoK1%)nsm=QCCi<8CKk!V} zPnx%R5Hjcdoj1n55S1_f*clyKP=I()XG`qvn{+GzaT7v*W_!;w@A6HCd?i}ifa2bR zG)K5w@m*mOFJ}XlP>J``(>^5@&X#NKWdd%4U^na-BS~U8m_^d_%GK_BMt(myh)6)w zGT`4%FYqv`OD|$b_G3S<<53FJXvKRxp`ht2XFV(?iyL9w1V5x%7vW-*`%5X|PBMik z7cKW{1Rdjx9(Cm$1~;U}69H=FV$@qy^j*)=)p@}W=GWVfhVNwfz_;J`3%Uz&!=mP? z`Z_d*MdPd3*MEINcn=DuE*b z1HOnrGkTXpD5)A)SwVrpvRE~GpJ18;jet$L|Bpv_%6lG_>yynm|I(@2A9~zLx-6XZ zebNr@LLuMtbm)O1N#52iw`vDyPK9xCf>e&XT>|Oy-V5}OL2`NdV-Yc2P7%7d=&tbB zM%$*7zDQfk!7VGepZ}_ZH*1RTXN&y3lP$wwSP=U6J{drlF1KWwKWEkL^z=FhdPp-z zMwj3M-v<|J0;fRD$p3@ww1r*BdrvR|F?r-HT9K9jaS<5?lk+;F)ea6@3hLSU6>8Uf zy!*w{VL5kTy>h^b$q!=m!ON~B z-f7b*?Hsekfi~dqHy@5fIEk}VCtJ(hzU-N!Iwo^c+ZWDzy^)RJ0T6cD|M4;LECX@D z@@VxS;y{{$0ke}b@O`K#_^aj8iEr`h0pQZ*uFk9cAjNGx@nD2+GVWPvPFAi!of$1l z9P0SvYZYFq3J8vHd^A%CX-$$ zCU4f>1k)1WWc}*@!9OzUIi1{Jr91ZltueZ;EMlmefNRr|Nbd*AGkz7esoXrfd-wSBbv}IWTJufi>Mn zC8r=S`d8uaDde4ax280H84l6QuYcdsKpTkAe!Q<8Z!RIIorc{|538?Iw5rOG0dh0)7$j`0}6CQv6@0iIhl+7bY&v zE@E`5oHu+|^jRercJzl*&$T6sW{ad9)+CZ-iS zeGuB*`a-CB7?u(tIAU-$Yv8VAA^Bn1d)k-6Zx(AEbj0z}6}Tz-re;G<^F2|$OrbYR zkD{D4r_6dF;XFbh39y6s@1oVGKUBzA<1d|Xr^8$Hg3&eK2wsl@oe#R#>ffPcU7SRx zsOCn8qg#k3CB%1eZwbu{t=%$0Ps+cHLDeh(eyj>r%1^(#1}*(QlAZjG z`i-wkbjfA4{*cR{KrfhKr?cP*rSZGqS*>HzKjE4(zXA?q$o@kZHslS z)P*LbdmjZQEG*MO^t3A2ks>nlm05$6lc*6rHm8M1^7n~h=JtD!UgnibQyH#j2rM+H82x9pL^IAG`Vu49Ec`MVZq%ip$$fBnuIg8H4GV9zLZ`kjQ(Vh^E zD^LO<(=ec%>7RgTy~`-7HNo}3(p9pGKK@01F(puJn4Gc>uSzm@O+L+e*7Qfo-T7X zG}zbu(1pbl-lv=Kh-=XG&N3H|C5y)&yq8nrXvmmZ@ZT%kOZ_;hkK zCbVwx2&q0_1}_$~wUHENo_C)~aZ=HWh0-F#B(%_* zX1W&g%}4>rgKVBG5#EkWau$637vO~S16k*P$M=+&?B%6jn0DpFzT2@En6J4Y-3%F- zQxshcAel+~;#bXn%r8$!N_P1NC3bjkK(8rvc<;MN-Ag(5jZ?{X>8-6SU%jQIeqm2| z%8BqwT-*j3LgOPc%~&-anLJqz+=8fEOgvNSUbcIgey?wA zulL7{aQ1*Kz9i|VcQc#l(Y+Ban@TgntLW$8nA41cI{XB=3MT1ud}~QM33*{Z0yZCr zAOrDGle!7#@nTZJ({~Ix%(rEo_%goZ4@dr~x%&qn6O+wF{6%tOs?`ZMBsx_sA#8G- z3=!@(A|FP-pQfL?tx3VMkaZLZ=?7HN-AgQBH_rGQX@M@zb6(`2X8mFR+tY8uG)l5TQxD>P(879WL`kZF z8+(A~&DmT4;V;6x<~QNNg~ZN=P&R07jryZDz2Mt81+eEUE^WmHuiow#4Y^pZ%aTKh zdbTlReT-uhU+jj;>}bNbc2aaag2BQYVmTw67sqZi zdY)O}@X6L1c~t)9zc`YGk23yFcqIncF(7OGdU(N-B!mjIu&{~3Y^OAa7d=8o-9;l0 zDTfz^8D_m(pJEX31e=sW1O@fL0RC=Nn4 z6D9IHQOHH9Z))}n)PbL_2kR|%KfYg3BO+$uxhSQO_E=cZSi#agg`f=G3HcyC!`2&3 zu1yKDltHR09`?W;e@-*L(6CnfWwXjyBHtAD50zjpBR0QiLfj0BIh$OXe*d85_m(k! zDN;fO+f_&xiu5P!vUzZi-(FmB+<+|URIvz)x>CTg^-Yt}clVad;`DNA`5yjSv$wNinl@DQTtgi?e$!PjG zcxJkk%NYU(%I+`T>IcOwIn`Xf!68QC`8~3Ow#}gKUVQ2w#^5X8-pKr2fSJHX)6OY% zT6rn7{}2zlDeuY<+Rz$uO|+KmjnoEySUw`2ZT(vp;(7~thz2EeS}hEr?#~-Z|JO~# z=bo2=BZmud)zHMPhLTCSpmJ@2jt%{sdg>PIqzLu!d4(}?AoU9D#eew~=lg_~$(ZdW z$pJ0rg=*l|65vUDb0&+>oKwpco-E=&!QC=idw~Dg^6otnTBBFs-Kjck<=y%FA!tF1#klY3d-RGqtA`@?t5 zg!HwlSCipLDj$$2<%-p0BH^{CgU{Q_H+RyTVaR5=MyJV`2;r@#>A$h&ZkXwZbX*|oKiH4M9H(%|Dhqgr; zY7C?3NM%RXS87W>TO=*IdGycSZlf|)hpS&J*Q<8SaXPpz!X5F@+m8sOPls`1Xfrk= zp{$}04zHsv@-yybpzE$_2ga@22%1Q{^40ypY z8w3(6!xS|EC;A)jFjSZl0=E8&PQ}A$`21ap@{cj*9K@cVoEbu$zHFH)%*zs}Q293< z5m|~TOWx`{rR|#OV8eed>}Re(3gObx^ca6`@kv$p9Z@*F>JLvBgBg=B9f%BYFaI+E zTSzmB&|qJE>bp4hg&tRR_{(uBa%^p4aV2z?&nMdA7)VVdw5>)4+bsu%7jzBG@ZDQCK_MJ5WO zXRH5-0rsBA*J`z($In&wY3LvQZSOVHv}a20mrxwr{#e_z<~d0Ma^kIcvoRKy=nf4G zN1kRvxZXom|4cviECC|lGJek=ZFsbg-XP?Ca_vO}C03i{XFun_$)GiMA~~GI6s+tV z!1RN<;utABtw;FpEqJwf&~@isvbq`Vl5 zg4k|$9(ChOGmkc-SZazvjyI$izeo@!Z~6GF;rMw>+-~3gnW2dvFgZXmE=mnv37$9U zS;0%8T>Lc!isC5wOSEo}X=t4Ed6%1r8%Pt})H&Ka*BPOgy0G&uMKE*c9@!{OIW#bj%X5Q5?Mx0-Oh$r&Z zq3M1`n&3G8R2B31{j^JGjcK8X6?9B~MhT~@X%CbyJDppu7jC04yttmvot_xt6ckpr zE*nE2BZcOyKEif5+3b^#o?_VWS=B)5>s`MB3vMhH%xjS*SYA?K6RGFL7?RT7y|;Ct zvx&LABEBV*ZIDjpD)Bky4HxJ674lWbcsFoDV;D+qW^=?{TG+^}YZvg|5=uE~&!rdO zV>jQ~`8u|X5dCSlD>>nYe`sL*7Y%#3Wwb#IgSIKt^p^UN1Oqhtxq8G-8GKm%0vT0B zX=TvJrFt^dqiImk)xDTs_b;4Wu9bH<|LftSx5>92fzFq?CQr<>3oh?;80sZmmEAD2 zs6(jKh5zidVReBcZQP`r=F0L4op6W1)Xy>*XZ9 z{E2w!OG2>PJ9q^QL<=}3(L+bG=28bAM^$wcM4NTdxeQumAZ$OqJ(r~jL9z_FQkRC` z*H^Q)XaL(ZH3`U)YBXrbjR{*gbW(^}4VYBGNkEC>l>K9N8xHCqdI+m0NDJfqAo!23 zlE_Z%{?BH6b8$^7NvM7Q#4C)7$`@NtJbhw#s!NRy+)s2!-E{3u9}rg+#hIQ~MKDzL zK7dU7x5@SXe_HXi={Nk05fSZoYHQ1m~3+Q`UPqTTQH z_KtEHOsql;;J^j-dmS|W+^RV|_A(A)kY?8Txg0i<67PngXO3mGTC&kU6(5_>kon;5 zfCBSX7yoJwizK34#oIFAs3??lx#RDh|3K^uKA>2}XiI@K_OkE~=cBp4|d z7-ytm_moJZSfA)w4}XgJCj4axosjeq8oJ0VV|G#hrSzw|E47+kUH)H{uSyqTz1u?s z!Je$K3-VqEr&;sEse`_d2LU*5N7~V;#O< z9ZY+b#aLKYVriI&ca$!W(;S>XcRu;Ss`NG-H2P@mCPJkrEgnBQNbUYvvDWmy6F-u@ z-rYDt?)Zn@)xT2WBbW1a`&=O!E{wpG|B{g-B}WLqDFY^*6K6V+SmUK4lnqKS)aQsO z@=y|gOLX{UykvaetLu&Z1MU2$`@rC7{jUR+dr%$p;>PCz4s3Anh5XJS;0S2wtWxX8 zYi~N?XRq}hpWbLLh7=U(k1C3AHDx~7MAW=dbY|pB%A+qMRqoOy)sJtj@{%W|{&3UB zqvhtoHPsw7?6^qM)3W=pz>Zo&Y@H-Tr>LDO9%%Hf%J2s0mgEVjHnf|B65I zJ`y4S+4VQJ!!J0e$K8zwVm@Z}NN?nC_iR+s$ln zC`jMxdw(<$m(J6{BtA_x!J^}+G3Fe)PJ{ua1>=p%o*}bMPFj$07Yyh+H&%ykVHEr^ z|5Gl5%kOf-A56&uT#Elcz7j!`eXD)EJYj@1G%~B#nk)2J;Fp$&Jh2P8E@_mY3b0qE z$tJr&s?BbWl2Y+7{qaINP{5&*w{Ao$FJ}KQ(&b13SKMsO_(e)Ai&t-40X2sJk_TgY z)N;{OX;KIFaiT(<@Osel`Lk=UGbx7=fcRExZ?1$?$KA1t^w*VV+4jwcN(_X6|(h0&atL zU!R>Nxkr4tgf>NnU-gPPuyFt?J#SheG2Ym%2u-YtqoI0O41L-1hLnMSQH@kThb5a2 zqU7#k@(zS8D#`>S7{Kut%CyBf3O5q#B!;p%e)wGm8MhSHjJ~2h1o^9roc>8E9%q~d zO1Kw$c)5-*(>n1gW=8oBR0gK3%zR#$7eT*mskoy4k!a4wb>QtKeZ#>-OBHwjL`p!Q zX=6>-Z(`uQv=;p;2ZiB1ej=`tzgKgd=On0)xE-yX;F(`ytg5y=ePm_*dNy}{e_{6IxHQo z(T+PmBuq;&+`XK@0$7Qqfll9hp%JT!ytTaN2%~~VGbR7xmLp`jN)yh)GHSgbKR||* z`-6;Cz@2XV3QyPVu#Ub>qH=+S@R&e2zJZJv;u3qf;lf2$zV+7xZyfxkmL7bMQ6Z?| z=2sWnriJle9j;k*_vq*8fs?nxZ5(Oe+f7e&s5OU6KUUnNj*fJTj${R!W%&$`Mgidp zNZ**zZlCQw+$Qm>%p7KFP@t`Pzrt^k^JF9aXkS%&Zv*i{`8KMo%jM(ZTJdKI2S-%M zIi7IB&hs?Xg>z*^V^v|+v~g-1chZ0RwDK-!)Z9>t7_`@M^!4PykoEY-8vh?)0XGNU!Kznh01)|FZKs zdCh0DXDux{T0`d^6#ux~cRy`4XRY~M^UnlDy|=$Eflz!Y0R(%~eDW;5;CKkpyh?e} zZaFZTrWu45JKdi;+S9&H`OF%aC-6AkSQ9!A;-|NNFzdH#5CYyz9Jwi)hrqKEf4%2c-l+ zqepK$`r_dU6ljF^3Ql*Vj>CmcrUOn;F@Ne&LCw`4b7$6b03kM&D5s;4vJ%7K?}Y=6 z7?*~Vsftj-{niP1q1@L$xGa1Fd&QzyeUcplf5xkw zaj1Qhg^~f03$x&5@c-`af~TRzRHTEGcsy<%n#hlFi((&Fq}GAiJY!K>3S6{$`9P^B zenj)RlX%d#7_$u}fS6LT`ss@xJ$}#DKjuvws89XJyiH>#Z4O4X+HK#DPWagWE!D%1 zV$(SkLPJJS zPmAwXImTnzjpPYKH&d|rfr%a+A6$!b_!8#QH?JK3N`&lO;>i(L;?y}%GuNMu3*fuW zm1jM*!vzxifRfkhU&b$K)t)?`^kc(g2Ec9qGO&*|k?o?)QZ`SkS} zq5^5BxJ{i}L8IqoUIPwPTJ-BKWFRS^Q$UOZK!c1IWAhG0%byKRAfpT5!#~mD;Y@H9 zQYdmp?b_VIOyQ{-L38F_{}{Fc=}-Hca4QEk@Hi%)hk(R271Vye-eMm8f-N7lWComz z`st1**IS*~i35$MAOD%89Uu(ssI>4L{KohHVV+8OaEF9sQ#;XZZZ^vwM&cm zQT9Bh^Ya!r+~E>oH)t8iGuu^t=V*V)s4qhx8kBWbum^FmUN{qKGmh8Tt>l&2EU%js ztbgKCP^keP4o5Y>k69I7@A6)ROH|uhIw;^-5jRryu6T_W!1mOgU#<4r8Kq*LN#!E5ct|Y_Dg%^KN^Vc)D-ONAH*P7}vKI139oQ4}eX{8)rO}k4V zgJT(UUabsnz1#{UW-ph+Kgyp={46L`1aKI5ds$d?TZU~m2+Pr)oQ0sL&GPw^C($Q9 z!=KW_KQfKP3XQL}YJT}dc=K>pLLyN(Gt@_)&Nm)r>Q*f2B)2{Pi+kN_X}B-zSD^ia&NvDHYuQiiq>TLqeS|Uv()?G zt>&b4IF7aK@Q?i|EE#R41MSYG8D;uNf|||eRUhwj^Vst~nWF>XpN?3}?)mTQ(t%gv zGH9j!<}yi)@#KJ<+Rt))^=ny06QACZ+_k}fWm*Kwf7`oURO7>N=qG@s?}S?8%|I3J zsyQt+2su;wts01~uK|^=`J2rQ(>L3p;>{&0>g4z+9q;jI8q;bKyR#ha^`C4vjU72F z0>7Qw>>sNJ;EYZktqI=(>8A&HnQhEz-blI&#{gBkr~aacTfp5LO1D9!KBk-^scYI2 zZ@?YL`(FDv$0tYo-IuLIUtz{^_e5UJj4!lonNKVxNhvZV7}?jKG?*r-CA~Nq$#3P1 zTN-}WJGk}yr`b>LCWXtbv`tcE&KqP?iaIG_qYnb6Qscf$=$?o|HVV0&e{i3E6r%#s zmer4pZqt1-mD#gVKDTafT2Xn&P9}mENO{mXPC6jYfq2Zju%n~$BT|x9n;CbFQ)S)O zZFJ0`Y^z0txi~4G<>t=8ad7)nA=8b6k-s3NbGJ8_T&5TAp?iF6|vRCvCvy*i%j(g@y2%DBPBrohig!^n9M&Yv%~Vd4rnHQw(>zE@FH)4y33NU8$y9{B8TMTa;Sf_urTj6ODHzMCu|0Jq(tY2;+9Nu=NKjxS%>RDPKWd0Frxa+># z{qO+(Y{?K4O38#9j6eWoET+ZkQD7tl_1wpN57>8_CNp?t8A-(~#Zm3^BH&eefc`*h z76w!)Qy@g@&08W~)!hwvR{&olg{oV_)y?GXIUZl5Ne&p&}ZXrLg$(=$mdk_jE zaXzLb>5;J-NRs`l_hP$Ra-3c}ovGe%ABUjxaX*IN#LK@(H?K-QNRyK_$BnH0L%>wU z;|yJjWPO-q4Ut}!l8q>MMAO$Q!K0l&ao2y|3tIu3tJ$y*}Yhk*@@46=IS(YZIBg3 zlWjl2?oWG6so8%aqyZ(zY%(hJVmp*Z$^@}xzSDlStR>08F0!2x z*2bDeVa0k&SZL9}yP9J48H$w0xb)3f@51a2h~MI<5R;~X*Xldq}+ z;e3Wu3FQ-(=P_kZ6ZN?wcMDgw&TBVX#>&3Sek9185&O`-tzqPjNuy|c@#>n-wOI=p zQrh_aN$kpDGu?<8uKaW?0oC7#SGTb%62yLG!J|C@a6&lqa`HkKfi7zh%#BOL?@kxI z($ab4kclNg2XJ;1AH_He#7hE(pA$Kp0FwWwvUuO6=oSuz}`9PT0pKHU~j3B%fvCLNnNE)5+ju6-Xo+mQ=c_YPJhfp`T znElSg;Fv4Z`@0CkR*|H}xK!L|Gx>_?CyBJ=k^UTR8I5L*`=Ig^RDDs}+vjCF>Xtmj z`8KjnGA%1trRaZHFux}-1O@|mpYJ24r-`n(PXEJ>XCOHkvN_>YbP2jrrV=zp5W5T* zmhz=!CEJ;g*zhOyeoL_UX55-q=4^X(1Tx`t9k;o(JBT^8urs#zuV%@+1nNq9!z_0d ztvJ2h_2g#Z0_|0KH;|l2j@20P>|3UK0Iy6R)LWseNfly66{yXVrtOK;rP{7NiIm&m zCvJqj`86zq7cBoT)#8895j!B)yU^=or2ZyRmN~arV1NP;nU;WJ!fpKstWFUaS?swn zO{O4udb;>2B2xBj-|ocOTQp}-_5<4R9sI+v^cF}I43?lOb?15oT$)r?gST*(M1-|) zjB6ko@KE!5iEOQ<1os<9uX8fR8$HuQ_E-Nd!`V#K#Y9r=rlO3Gi(<#( zpZ;um4H&i;xsY?tM}lY)yoDy+cjTat+ZgHXDusI0=HR?lzs*% z^V{TCCqi_u!f)xKA=h(vTZ$AU-6$pN=z)a*o(aQ0!hnTKBZY~5XVVQ6#~#t|ZvnhW z{*at@p$5pw!K&lr;rmAcRb+HeS&xsF=1>2T54MUz>J#}_E*uf*@BcA4{<7AvC z56H_jeRPqW2V@^E`>|(pL$n--X%dBisLae}s0;vJdPxB1TdG&&0Q=zg$nt-Si;Q>C0^uRow?Y>e|EE7dv>cnV@QfKS}sNnl|-- zGNI8`lDpR3N)lj+gls25PVY(LMk)?ATJm3O=D+?Y)c4Hd{xp>a{KshHH`zPh@qiLF zQ0$YaKd{`eYrK2ngJU(_gpY!Ibow=z*G2GvSDM)9>K@^)7`F^B1w(jS+je?S?NFka*6Hm|)41<(TNmGl=4gZpkJ)Crtz1_u5MGSG;Sx zLlMKzt_4RY?g$|d_(64!ERPMTDclvb0QE#MG5t8eOe#i0mO4ji@$^A#k`+0~V2XmN z;;9eZ`yG+?{_OX?X$~1RQ3lSyuJViHsQL$J<6qc$@Iv@*GzL#JKs-FOz#>gce+0sEq?reyXneK;5xD-b*Ra6dq-~%K=?sh z3Dlv2Ocl*=KbA@8=a%a0pcb^nn4y(Qv(TqYx}Qi-$I6f@*PPB%S->ms|4^l$MOcE4 zzE&$xZl$7lJI(U*9-Nb=y;foFFVWP8-VTN}B~UKbrYI>$c<$K0d?8M^$K*GhpFJ8) zD@QnS#pAIxkHu~;Q!EIy>GgGu_8cUS_U|X*ac%WozRg|@$}8wt>$iG5zy%2eI>H_e zv_GhU{Jkc(=IE^78tUvL_=ZP~gJkv`fCe6Jy+2e|;@2bRqFIy*cjAwNqHpJHOm<*i z+JMD@XLk`ZuV%~qh608H-S_NYW_YXY4J!sad;iGCFm^msYf+c0n8*U!PCjL;7*E7g zXSor|@pTMIY%ZRf4%4u))`pG{D2VV^%u=+}^PEwXxZ;Ma35{6`YxJ*~Y3ewdY^W~{9~ zCzV-+AAg4;ptJV>)LC_xXnQV!$~`$o8^~(jFq_yvd!<7dGKc5Ctrju^oiI2AHbUb`bgJ?>UIQnvZk-Z~0gLHlE%kmNqAPAt1J3X!% zW3YxdggUs0d1%(cM~Dg)TnK_1&wJfC}M(Xg*IKM#dWspGS8m6~U=w z)wIu2GvKBfi03FJr)2tJO*g=PY=Jw<!62l%S@haFd1% zZz)X&95>Smk7Sz{IHR@#rc=mEw6e&qa6!j!*Qwo-rHzvY;q+e5)VoMS#gX^5Az{9dXh zK!Z}l-r28%|=)j#;rYM3-4DxFRe_tj3mdE&ZTsFtryfz;S z;pNlMpfdY0umzMsySccTx|nvr+im+e!LE7DH;+4zAKAsgT=#?^WRS0^;Om$4>GRf1 zu+RHc?0C-obdY}((C>ElmqP}G6Cas_+c;We?6?F0tPNDgKOMWi*^ad9YvVd|PdnIkjJr4GdOpWSvsy9sSW5S zalhh2ew4Pqsn_NpmiQb{VON0y&ZZ_UDl4B?JFF~M=QS0cBcSycR?5JeVj?Z*4<-cv z^~BpA9y+TT^&F#vr!&ROXYEqT0a?~XqF%duI~Xqu*F!T0*Zd({Pe)~GmKJ6qOCt9J zl>ROu-NvFCWv*`^kq%dzecqBZ8K^y(x{=qgl5eJu*lp63&xP9fNB6}2(yefY^Zp8p zH1aJ|>oMXCBx(*KZ3Z=^{=6-=T*vZ` zXqqX$QlJ&1388)FX2K;Sq3%X3kSPXnW<>KSWNn;mn^prj=8ja=MA`P2{A^Ns zc6bx=V()kWLb!kS?tD<7qrL{_*R>`mNz)!DN#Ys-KNF~=qI!7+>b>g~tDr@^^RgDY zj>?Z%l$MJ%SKHzMd_hQ(K2Ki~VIsqlOoZnv-zSxrFc4>^4H5eqoZ|cNW3PHVDfay; zq(V;vi31|!R;6wW0pj69o*h7^H<6bT8lXe+-?8f9b&?%OPpqPt>rkJdSLNN9=jAD#O#i4j)yXPj{UJB{mrn0 z3ZP9b7nSuk<{J;Ck9;-5f>TB~1(4rj3~UOkzxG>EI{-Zc|Fh->+LTpE?O#|_Tt6S= zvN@&8;rUm2iN#F{H&A^+w7(|YIg?P+7mUCtbB}!bub&^eyntatZ+K%CyV*wOpX3d_d}eWo=U0VC3cBL3i&EAm6xfiC9v1zPA>3Y;opfKD&!ZH z1po_7ysZrsB1j@VEWM?sexe`U)H$FRiJ2kArxy6DXl?mjfc!I;g7ft502O-oAwQoE zknMj{`kq`SlS@)QjbVYnh*Kg$nM~DtA_%Shd-LuCo44e4HV2%Y-}>m+01ReKtCB9; z8RDyq@LX=tPjX_pl0Ma-cH|TV<6wf3MC@+)toi*MSsAL2kXHz6Y;4ah(_4}M$Pe^2 zumCh`ATwRlsM;a@^{b~Gy|GSuH~>_R><={ z>g)t}k9d3$ZESy)kH39sWrEG}ow2Bw6I$!;TaPH1ih*N;u|FzxG=`K3)I#7In^Cf3 zLc;WzsK10_VKm%%t)!lO+*OYQNJ;@uBIOm={C}!GfBoiM=iHJI`{t7{ssa>JM~wnP zEdEJ?3;z)#oFayV!V=?O#$-#d@k+srt>=;PYF}aA30P5P zo!l*XExHqFLh=MhWtYYT%&+g~R{ri`j~OzifVG@<+nAK8=@ zixT=k`nSm1{CmVL?tLK*pW3dK8Y?)l*b}a_b4iy=v*)&u4^j;*G%jx@ygMeFlawz= zX!|n$+=(J43NsE3?#x8=I2+eG0>zmsDW_KYxr?J(_pW>i2U#zW7%gES9n%vH{w;yzO#o)Ut2 z=;4dTElT;(sXn~^sCLNppqk<+vq`^O_vq(&r5#YFYvA_a&qEL5oSwPkvGghH{deJy zj$i5kvcIZI&6kUn2Q1Ypz$M$4iL5?9zR4NMm%7-{Pv?sVvS0V+8634mPxn0S&LQS< zR9%}rJbl?C1#=4#{Ur$g1pnEql^)?IwHCxM9%*{}TU8I9(D*Q%ON0?OSoef6O!+NI z1B&3=WSw!0O68)_DJGCQb&=SN9j*&xjTZJef+i6x@NXm3!Zv!7r&;e5!FATsAb+Drm(sPZ(KWZ^Uub}d-VVxTrnvEp{kGm> zDDPtj+$>-tQv5b^`6JAj%Q52_r*ngH7YgWne4qu#<*mM%UEN*={0J_oJ7Le|haa@Y zusDr)x-Odfcrjja@2(d`JF$dWzY1%-WY8tvoNK;)w>LSL)HqgU4T#{lBRuY>yYmf? z^>XG(-wK;mQiwM$D~{s2J>A21?vMfw&h>xqBFLNC=h`zu8l8~VW7{R5)rwKEYx2`W zOO6GMO6i~cl$~^263(vUKAj|rmY_!JTE`oGO(t_wp^oHz!MG2+ zGOs~*p4e`ww90f7@BqSjVz%VSy?qpNJ2jaD@=O zQ32e^R!O1lW5m%5KO~4LBZhVRTv_mU>K6%CGhNPjvTyg>Eoqm9NO;U1p;71M-AkVv zB1pY1*Ff)yE457U({DL#m6VCfPHqYKnqP>dJJ7`RzZQ2ub>MsJ4{})dTx<73a^nr4 zkVclu=;0LwoA|8Cu;DE#$Kg&jxl40KBw>aefex~nPQaVhyYzQgzXa9sQ?=Fopho~+ z6!#5%&K<+UP+_XfxwvQpwL_OGK)hLvhd`(L92&vzD>TJ8^(sPFrh zGx5YKB75DaFo&Cy=W1tl>db>cHkL5+*=s!!i^Em!$^ofQExU`aKl32V<_~Q=wvivq zrVik)88p}Oj0CJ*{Gf^EWTZ~wQEXh71!Sv`>gTr*kGY= zx!sRvTj#SKT!lJ;_bbpm#x8^DS?g0#)9zV^hfbt$b$zwn2UPQd1B6VQCCppwM&luK zn2Rr4F31eaasV^}QUhh4soj*>=cMS&9j12eebZ%cg{f>BtFB%wdKo}=@jnNr<#^2) zNfZB3C-zvDa7m@hm*q+XW8N3wdN|XHDuk0tu+&3hIF={N>MrEiUXKwk^0kEnVCn}&LVYH6$*(eqS}u5^)%%0 zXnCFlzLwd-H)RP-4|{d(8O!*!&e+ENd!r~OsVhJt=Ha5;-GR06ziX|hq#ekq*v1ci z*TN5@H%qu&E_4Sl@c%tv3+=rX8FGdYnmTcPdUM7Or*|5gMvgZanaGV_0@KqnhpG5? z6aP%Ba?IzJJ9wrglwJ8@wwgj(C?VgRlP>CbF`E@A-*EsE3|ik0uzBGXQTPdYB$;;! zsTo_nO5RpvsK07FCqo0Cok#yxkKUT0sjpQMOF4z?{fa9`h$9YD>!RC^0;sbngzn@f zEd3Bflk8l5_2CJN{F~-6L9|Yo_4^?axL248dmwj~nc|iUfW3zWv_@2syA8q$nBOtf zF%)>N6WkFRcwav|8xSk<`IBZ!A`1KfR%bkh`@_C@iEadApeR! z*9Qw*0-uBvw$Xuq)lsXfB10)k@@YDE9Qn7vCwLbg*@E)F-~-SRH;uwmo2rQ?9iCq^ zw$=7os-qWt>Vmt9!WtcU6dnZ*Xhj+8J&AqXYQ-S|jcQXv>(qb2__AH^`YT9G)-ZLI zMOVg99&@ztloQnQ(*5m#M+i2n&^7!oAvgM5+i`>~Lo3h9#NcM$KS+Tn5U>63(WjFp z2WVzS`Q@H@41WkD^JLi(Gm=MSM)g#1jT$C>!tWmMRFg4mP|@HjxxW)K*lqvDc5O8} zaY%HmRyKf|VCCzQk3e8)Y}<$QC&Jf(V#o6{P}5Tiv7D0jAU7*1LzoGhJ+t@jM?*+j z?_MD3qW{r9id?yCN*M+EUcs7?+LMAeKEtu&AHG0s`ygWcDhm@QLu>-~>T5Q&Sz4&Z z^zs{=j7)t>h|?Xe&8l2`m_De=3$2d;0;)T}@vqjM2Mg-EI_4$U6od?MFtmOjZ^4FI zaT#5RfA@dH|6}KZ_t)!|5;HP}%MzO)&$(XFuY|(V?7`!xjBGYzrDJQ61ganm%~5<6z+Kow@>zt&E_FQxJZQ9^yFPi zk%G|+Ih)`CshMWooU9$*Ulpn#cc7>Ie|13mfT$}W^CRX?F*(DTSeBi+&F5>YD%53_ zMQPjJyU3!UWVUWGaEC9g$_4{oh7RsT+hdmEU|aT@?tXfi-PUoJZ@4j7c5$y0sG|ji z1@DP)O1ik|xTMhuEU*(x89CtE5E}Dml3=HpE3LW72mRF) zT{fk z@5g59$r)aP)fWN83VIzwFId9BYZ!e(8k=jk>)gnKAi73pacyxOD;w7__`QxC8^~99%db+NLO>)id z<%=%7mh6AKIrg4DO8R_^dh+T6T4dzhG|&C&05%YJovNm$_%@2G{!@5IG9wUpTy@7Q2 zi&%9x!B_BCmlToq^XgL2`IqlV8DWR8V9XGy-Y@$IiUjV~`Cm)*G0>GUVEsd;qDtb> zfom9zodvU@OlFFl5#b=tc2@~<`GpcXyy{`Tb7RVOIK^k?;xNMFWK#I*5pPkzo8YlhvN?5xYc{nStAXLF}1NFp%R#Yq0UePghbBxCEc*|uxh zx2X2N)k^|eq_&Swe63tlJ~inREjk7Q8Xg4dk^-)wDw?(1!1^TI@VaeiKcd4C0QrKj zWo)gdCfwS9?7ato65#p&*`d3_@J#2N_>LnI_=nt~eny^>LAOzY6<*P)2VV&}ncn0r zL_hqH3G?NZ>VIuPHF|a}pqxv^c}_?Qkz(?)AO@c*+wL}}g3KDF=M~PA6Ar+?x7RgE zf}?o3fQ}Esf)k$yK&7OR?!|0melT+b2a}Uxw=g3eaga;m0ZcC3NM# z1_+`xVJ>F_lxx<}f%qxb@96eNnruDrNEvDudtQWdeoNC@^7?x}`(Rf1bBMTFCMv3LR3a6ChwnAB<8zP~G?}%QqZ}UfFqC6r9QTY}UC8qpQAR-i+EdX_q9(0aS+lJGrXB*?#k|Z}P??Js0)-p)$K> z?E%rz3m@;rzkT_Iqtyy12jPl~vEb&t6<+dKjOk>)&Wc)t^0Z6;BG-+t8Hr6+?Ry(j zCoRxfah7UfG$NzGvPQ6TW7E;VQ9@R4SP-COlhmt5lnJ19Q*r6Y&-SHz%f!gQkld0p zDMYp7o-Q6p+DXG zolyJL;^Lv=*lMklsXTe{YIamk)91u`66!ctzcCwd-xT#d!=2JXOAYwOK<$`r*kUmI zC?aMPvWXt~EvUvoaEt&%v%mQOxPX$6V!~%r(H9B-r_TQTueyh;Uoi#lT0%X_Loyb@<;)aI!;qPpND}3gVcw$>pRp@_^QMCKjQUV7_T>#)4Glw zaI4C_a{_!`lFq8=#GmP0UR>@Uy-J2eYUx1KfgVW-%?)d~pS9!tey8)gFkEL@NirDc zMv3L}Gokdewd`~ubxPNHH*6zfEG{>#SUQzw>!a18Gy6oi+Y|GEnCo?J>y^1?DdpMO zA7cYk7riT@J!SyBf7CUI9ucDb6BM);tty4YwSB050?3>|tg5XI4TV`v;jUa#;D724x|jgAi= z;LqBBZxRayV+Y5#{r16SMYvNgE@-nr>{x$DL!u|A{ujQvaQP~|+QW>#X|k{RDCu^e zkvZ`cstWMS_o3tJ86`eVPcNc@Idfn?#_VwK#nlYlbpJ$|7KDNvi_X_NY_R=~FiU)N zVol{F>z8FY0A(`KVBt!s9O8f^rZRq?F1c@0QXZxl+>ecW93Uggsk#y5^pdf)Xt`AX zF}->D(w68r7c6X326T2o*g=M$x--CDZCYardHDg@$SC5*>o1NVTx?{n>K&aHlPI_*N^SDzgoaR zJxlB}@p|P1xL%_B$qZNUohO9voIa(@$`Xps5Cu2-js6H{7|=0i!#IK#ex6PhVpcMe zg2A6UQh>ho=#=5g$vI+1R~H=(*{wX|x^Wj(K?lrt$XZJE^Tct2zXnDS$1YH4sPD^* zJk5V$jX6cchB{zyJ67(MF4;e2Y>kxr1puuXS@x7Vitl6}WELg7x~8q@QQ`xerD9=K zTL{H`NDWn*9b{~s_T1HdC#*`n_95C>zcndvs-wPMTh-H^|X`2d+$ z|KPw940qaqJ7n1XmZXa>Kep3W{G~P}_!iU?Omgq9g0Rt@pP7~$v-TySrd|j3+lGZ1 z!9)F{h+|Xc3agXym~SfuP+M3{^~Ua*$Dr@JG&wRZ+w3yYJX^);|!_K5BAxF@?Aw5hJunoncx#o`%`8Wx*?>|-=O7~)ENC>=5YTOkqbab0TA zlHQdU?d!GhtBuD;vTC@ch%quMdzU{2NBFQ@2jFCcZ4hdi(Lp~5E;Y#-LswM8oW^vy z1t`>a#tyUlNZzvJi3|n#G932vZl~KNCk%!Z7P#r>=;d+dK?+@6yl~d~{L|qhBJSZ7 zy^EpmGnXBXW{5NBGE;|FSVD%rzIrU008D<-Q|4E)%0K@OChbCGX^#)T*jocj~l^aYoq`fpW0d&^2AzIk)-SgVne4fodVX%mP9<<}wJl31D@1ll)|fHrLITr*B#DP*FFTyZ%$SC2NnV z*S%z$D9WNlSc++*Zi(4SyIBxltmDn8(tFwyWvaxm6;)1K?hqF)DiaO8?o!rd$N12q zY0nDn!GtPD>=MpvCD&Iobu<-0vSfBYWsO>qNden>BzDNEE6;3NB@YJH#JE_cpur2ZtWd@->j!)h z^+y_v)~LYP!PuDe-Gp4*Y3$;Oa84@Bszw9rs8>eGClyCdj^={jcn+`TYf-YVZ;niv zj!e7$omAaL?>3Nk_c#@)g!aPdaIxHVLr>Lfxgb61ArFb?XR}HVf%~zR?)1c198NpC zQ?e;6$DIfM8X9AO4{9TFx&3%zHNpY&b-k-s2qXkY?}B{m!NM=Lf7u; zz&r-(x2@y1=OxZ{{nsh^^}}7R-<4ct1K&ZIwp7ChS#C_rsO~l}my`&Zf(fH#iQTK3 zv;_5<8x2bFRtsAtf52 zh6$Pw{NOf776ik5*e}a#pXI_8G^zB4s%Ee>Sfx6z(0kbPxeHZ|dUaWlb#Pdyt6Pi; z#f5b<19&d~$QaMPM&Yo0^Z+32Aq>x&Z**RpxpEzYnY5o>;0bbyEQFLY@Q}3EJJ!!W zAxrBX#2cIKw||t$zzyCR*nFu|63ho;Z0+ppuD|AR_4pBkV^+eCit73bT3!v%I+-M;!780lMZx-w&~hkBH>nO{!HT+q%$>EHs^PP;M+Z51K(|qu#Z|Fa^An4HB4UbSDpeX-gD>Q^PVGOIzH#xdCCD~9S_rI1XBm7SRjT4rOWPyDz@yN9=as|Zsq9BQB>&|O zU;S-2+59{aaKOa!iSNVfa~j2nQc}!yc&FnW-zZv2fk#L(b+lhyIAIncWr6Hu`7zcc z)`u8aSlNcrxC~Xh`Njk=JF-o#~7Og)z3Tj5qQybJA7#;Hl=K6uqSK2FW3*e zj$GvLp7f4V6-I`1vUX){C4_cXGWYUl^vCyVc|?K3)P3qQ;#SzZ5<@6@+mXkjfn$qh zp^9?rv{R$KgOv_mAhWul+rkOE<>tAudkuY|Kg%Nq9kt_yIgE%i`c-OIBFhebp7)J_ z3@!nP0T_dJJ6oW`VVhB#z;(gRySO7q0I{02I~%v7YQ}^%@9J6nTCQI|T9yK~nKr#K z2cFf5!ekhE;^6zF1oBU|5)b31E%gQyFq;P_(szM7{d9aGVzDC&KAjtgLe6FgRKLVF zmnZ5mK%nzYSW8?8(ZEA7aT{Dx3M&fd7ow7M(A(IEV{osm=0=CMI|&qvpA>MjrRfY} zfZYg&7cscgu>?6L;!5NcYhXRXK}ifi%kKO>}H5`XB;WVwHaJoZ^Yy5h*2N7ZuoUG%hLV9eW< zFC`AueO9IB(?EBo?K{P$5ubtXT@kgut4eipwj-E4*dv;R>6g?}W(pBJIt3U%(Ael(M;w>Y|F`h%jQAm+x$gBBIB4gL_66#CewoF2#S(6> z8JB@>#)X5An=SyRUu(P24=6@J3v2>+f@@KSY|@69&<>2hd+6O&lpxr@Wd)eE#RUuz zEKn`K-Ls@FBD?e^20G1+Tes!OU^%)|pZSfYd(LI`ISRPl@jD$%Lqh{i?!ALmt8E@E zuq$>G#cF?PiFmk;2|9F+UeMfB0o$~ntUffHu)+h0PGxi*H=mK3_H5Gj5`pT-c%0k8 zt0v02RN_Z4aduTty(kqF+OH^*PGBX&W&m7ePV6^7`S9!xNbGCu&#iLTf!}y)_c^9} zHjF!(KRcj@(S!dKofH7(Bo${Z-Ar@nb`W2}P~FQw_KtV|=%S;5U4Oqc51v+h-T4Bn zVIXKU=Bq)aw|%F@!ff*73=)z#H!}l)9Svbva5#u}T_em;eBLG_e{5T^bFw&9E}(We zNG*4k=^jQbg2nY9izB3b##@bfT=e@^)NO!k*BIp&*qMRFgd#M0D$C1!@EL(yM=r$q z$vwhx--C14#?E`m%*z5m&G3aNE}c!yien1@+#3fmw(@&~(K);OfKtHEKo-S1#&)d~ zOqXsTGfHk#+xI-qg8J1ILT#DCZvyMJC9?_VoO^XVxC1BsN(h`Wfm>qJG?6@}wtPUvhXP~g+6vhC(l ziV%oikQx7oowb>E4QG(%1us9~2ej3+B?n3R{v6S)BlAtwsSZ^DR;LS@P$kag7s|)N z?7=q<^ZDIl7L$@(GpvI!(sxs>^+K>liNhzcIu;FwTgugkgR7ES1pu*8#mQ3LDV2&l zjU-_8e?2>M0AXjwpH(vMf|ANAdfRa@(YKr(U54GFahXGauE{MXDX>LkBBz{ifQBeeN$NKDWrMvGMGS$_2iU&oblxw^;vaCf0iqQp{m(z5 zN%M+IH!)PhA`Y1eWuym6FAYf+-y@lB@Y$9kYzt?7VjOQWwDFJ(erc~_%`q)nOF+S_ z1^dyZwUm3Ejo{it{STx(*}2%z6v&hp93y}!{|%ezhYN5C zpmGNa1^#!>-S}eDiLb~4slHr?4qd048?!zMn_hs4&J>$Asq?E*QSi_Y+8nk<8kOqL zF>@_Q0*O}AE9S3Y8Y6X|kF%x(4G&MJ?zU;Irxc-Asys#sHm|=>uHCkEm%g8_PGn)v zGq^s)F%2LEi6uvi+OM}aGndtGokv~JW?-+(_@+`0wO;878e+Dlwg7sve!Ae!40Js| zS5s?DJnV73J@wKDU!PP2?FCoh=kzPS$40tu~i88 zIP1Kc?)0=Wv`uan7A@9m)TZs}(l%4|OPOyJZtIKbw z!@+T3^f>Q;o%EBfbLP_**tx#ZEM8$qJ8;H64F7H)Odvpi(s}8q20|>c5xIAB!d?$b_Hh zXEIV5)+st2?A7=l%OFmaujhLxouO-x`&&>WfzbiYx7v-UR31h-c)1JmQ`|s;CvXnqnvq{lf4BJP0M37@=@Z}z#bj1V*PKjCmF<`}9+?M`w=2TXwAOETZf_y;=0@5pO*j{8=Z|T&_fKYu!BXLD2ob(Drw&J(}K(7yGtGpAFD4z15eI`V$ zGxWyBO7G7-eEB9|bJCFXXvg;DB6k9B_Wg8d!KA(*SF?E8;k0WX@?#Ki7uB>L5HH>z z|G8-xX@UTXw6gqe#p5b_S6<%&18lFqRgXQudm5qm4;lXXFKJ$EZJ10wZN3w7C8*su z*fEaQlA*o9OeZ!N?B%|Zv0{9e&|||AOuFJ<-!#u$VoV&A z6&E~GfPohvAZgDPiY%eqO4LHX=6TET&F1&LDwQq6`1o%D$iU3C+HGH@eP}cEyKtO} zA+J|OjW#LrW+ArpwUOWrJ-UtHTLbO1Lr{87SDTHE12d#gQQ=g$;p=;6#OkWz6yqeD zwt$Msquvh(ihFE1MNdzb%1@c1j~s(!eot><`QMg6C_PitKxnJB9y6CUIeRD>)vwl5 z=BrdWbR(D+Uhd=iltu&@v5+NxK09XZqG?;M@Iy_i8=D4IK2bpu=`)BpE#3jIr$JhC z^Rwe_^ISmmLuwMPA{+rBn$B!7{Z{h@A$FJWa&B89N$x~D`>ZumVl-Ix!6**}z=N;% zlmh$OEyOperW8Wk6B{Jq;524(H{GzkihU~`%(nQ3offg;>W1MiYCO%EK)Q`B>NkII zYku_sy4d&&7HAyXF=O5+0ir_x+I_#^m5eb9wEQjbSF(Rh^bW;8uC)QP?!6Eg!`_*% zrh(fxmv0&mey<7ev2zB*;i2uw)txf4Q1!l|O;a)O!0XV-1I@EA$ySLqXwz28=8xL; zBb3FrXD`_ZneM)b5Fd^6s zm#1C&x@e_XZS7>@n1w2nC{sp{j|=0;+;F-^uQSYDJt(n8*@-yL;xwzD@YXF!C^{&1 zzPhgo&&w(q55_J{c@ku#l-$S&FD(fv*9`o*;W`mHE4y-O{Hv*(k9)-A6F!6%M`zYn z;j4|ppNq3d@2FAlF$$DPA_wJ)rC9R`S(VN`l{hC^`hAP|pO%zRmk>kdPhWj6foQ&q z6Bgl?Qi@hnqK{Z16S*LCSgn;Q;f?5 z763+&>Yz9Bgl~jagM<`hiD;B38ezTGSIR}}4+b?@hQiAJ;{e_~ZXItD$llCBt_atSg ziFgVZ-3{(0{Q>clPqdvmk zb=zy1kyY)w4o5yNi5$L~uk$tW=E{T3i(Jf$9^6OYaPVl-DK(hIsn8E7V`zVMOWN@bQ?q zu1DpA!d1C(al4MW8Fk~}4rX0w>Jgnw^mU)Ehh1i1>n@elxZ%K)X}OVZ+&iE1U81VB&7z(B@rXT6o= zHJE)E*4_0e;K;!nE+$4t?IoIC5BKwRg3mYwFM3PvQ4V_Ko$d7Zd2`jAh;1Q|osX*C zLN;n13}%Bss~tFt$kR7A4X8S1!jBePKV|-Ln}=L3xgL=Jao@W?BBdVWbvwvPF&xpf zuoE#kALE<@5psZj7=8URnwKkEG-8RlAjD0X-|7DH#(V{XmQv&Kc8#i(ab<(KdfAK2 zuqVxN+w8qDU$$oKX_=%1MzmgtRHaW6(QBZa{^nJZ+M06srmrRRc{j6T|RI zWJH=K9KBibfGfl`9WDh=eGno7zwIzg%VwHI0&OGOMHm-AFVpNh1)F^506$ z`@EjszY`j`<%x8ku&vc`aGCp&es`S)MHc_;Dbm-m$((aBF(m{;gr1_m0KmyJ_UN@bXKi?iaCDy^ek}s{X@b)qRcnnw}74 zP5#J`N5MeG9xGvLL?f-BbXJ8lYpLs(Dh|o)Kc=4Xs9{>zIGhrD(p2$;OBDPv-WUWJGS6Hk(!%-bL*krE6GeV_7HY~-1<#o44CU|YPY>Blmts1!AtVngtsfu+gi9fG5XIOSbI+bCpto_d644gW_ zES$lvzZbm#;Ka}!Yd+fSo&o5gr+GK9og=Y+Sa$N+BHi)S^}Uk{6a-f{lVvoO?m zm7G%TZH(v^;S{6H-96@{8|yFi1DNGT`EMvw{FdAs%jjt-;j|U0BFmA0O5$J2ME=Qi z*b*-tiPX(Od~4H(E>OwWM))9Z(VhWeiKOc2Pt}xLVg!l8OfoM-;0(KJN&HhXQy+TB z;!tApNXp(>C&n+dI4yNLf17?PGI58*rF5 zmlm~{r3&;su$516sDx_@B|k#_{DLcM7Qe^Cg%a(}9&l1Ju*s^L$sf`zv3NlrQ} z2nuR9##Z^gM4u2v-3Be#49d7lO?73Ve`xOJIYqHrYrIaI$r$WDPvw1OGY94WkFmFotD<@ThmQ$Js+1z3(p>`5ij+txAYBq7E!{{e2q-CC z0@4SNZV(X=5Rj1W?ydvB-8~qe@6CB$&-~%hb!V=AU)Rj+&eCRfW#)$|UKnG4leu6x zvjjLh=cPop^7gPui>}4Ju0sJ1%VPJ$Cwfb5V~GMid;0Bp008B&O4fg8V||#K%*o`> z-aNq*$jhSWUXc~(`^<>9Iy$kO`@;8$wlyCU@wyFjM~iAY0v0%q)6(||y} ztqh{;^BWHPxGRtHLwp=?#=)te@Q7N0t%|b!mm>t@&yE#GJD&Lub|lw-&U(+pVW`Es zP#=z#<9gG?J2wdf=pb_I|0)Q;Sh9lm#bV!71Lz$UG`#kAF4$%2smCntkKAp+%fI!& zK|b7ppiC;5^G#C8e&2ck?uW|sm#Guw;xo9hxZhjyzxmUKDu!@BG~m+sD*xJGxOl@Z zk=B)l?J3jBYxat~_uN{XYH$pmPtV34+4ED%6TC9^6+p|b45E8tzGi6|V;!j4w3wK) zSmE^fK!g{q(S-0?P@D36TYsha%w}}t zw`r2ZR-THE%FIB^fKeWRIaa)Ub~AxEZr7JD`&9+AIFQka(-c+MQdf67@Ph;5CzZK# z(9|SuPT$7oi=~J#0vK^2<2D9m2#r68ku;R8Hu%sWq8(HILrq~KSm231;U@N zbBdgG&81gX5nT*)>`k&*t40KYuP@xdKU2Ps0i4|We;ey!b6fR@c@Y0<$NTgkoQWfU zaGkQ|ohs7XE|2}BYB4-=u9IBB-S`@W)hNpx|3>D_Po0Ke3-w>4H8JB6JH5of`nZMM zf4~<>ss`?KQ&!V4UBd0x+kzdefhr^c7~io6N1ex-_n6n!5h9S+wwASVYvJBl8{nk> z!xdAE;=>>(YykLpX#Yn3#C~SGY-{d@*wj!-Yej^n@2qLb#;F{9=vIeQABv?O)!ks4v+bkD_ zAa`N~-HH0YAqH{g^9!-`^=c#4(oUe*)aCm8b|hP#Jy{xrGV0DRd5*rcwMdeq1FFP* zHX-eKX1~94iu?*l5hwEh!uyG=#7g=zBjknR1xw z=hlZ0&wYZ9GI4#MggevTaO*^?8&Ao^1|Jt0Wz9Tm3^+{`c3<{B-2Hcv^?Q8aS7g#D z`|Is^;+EkMpO+@@cAh|$D^BNdURj8cy`wUxLlhX}uc*5m%orH95$y1zofuFTb8^OmGwP z4Il6X2MqCSDx+z2jH3-Jjd5>cwJL=i8*n=j5DI4HQ3XWbVYSI*ZCF6MqGy?#MnEsY z&Cq4wk$l)@*%nd!RT-7_MEK&S)%}e=$#c*^w^0rBfj@+*y*fO#{l;be6|ye~e-}TX z1F`MZtF0El!WQa^mk-5u%e4dum=WVlV_8-#L^+`OW}hf(FU4yDmJbx%|4?M~^OwFGe4pE4qJvEJv1(($YY>T9 zEo{*iKrx&=Y+9euV1rwc+7dt{$kqUe_J5kY&T75wzCB@5I+;q_b5ibG;O7ErghBsq z$x$zsg`0Iu8eIgLsKG+zj$lFHe)NUTM8wc{>5HYqt!P>qui zmS}&=n4h1v965>>C`e{bC9U%Tnp#~%m8%xd!XT7hwZVaSv{4Q84nZju-+yiVDVmNJ zR7K7j&1hMOm8?xmL*6l?k!&7OW0B#K; zv&x-Xi(x7f5da||s7atfN8z*gHk88!D>=U8ZZ7OYX>Hc;j&X!HiTN;omGi+l5EH;W zi5z7H^(Y&*6YpI$$|1}6cJC3zTsA8|2wY9c9U)SRsT>vt%`)qN%C_(Lqtaw$eeKnR zax@@q)a%-PHmgr9hjIb9pX6SJ3V$z(U2CQ(*qlL>Sg(Od{ensraC%rx0vJVC^4;?^?YI^OR&Evzvxz_C>pMUoFff1qhBWV5B=lJ#ztP=bp`U%Dl<0o6t4c1!zPT|FYgHBqf-#n=y;%78 z;uiE)Zq1LYC^Uvxe9!Naq}4+YVc?1lm~66l1c?Q=)7yRX)>2=Av}zbpz~GPExVB&- zTc6!9SLIBIf$9mca2YwO4F@4G34*{?Csgj}x|PZ3l0@D^2T>;j!@_)MF95F7rJ)02 zFjTR)xuYoeX2pftu2(mU{M_iJT6j^x?4LBK0ibpQx69Z*L!FlM2A@uoc-tN5$vqwz z3YSh83Dy4w7?H-wB^Jowg)MR=#(>D1;TtSGw+A;?&y78c-*+Y^F-N{vdE-1PRhYYe zxDz+Kb?2*~G|<1^2rz_Mg~O9R_*~8pe%nrA;38}k4^>KX%};(^Y|aoe0E#+QSZGf)PViUD!d0+7CB6mf5qL=Mwt9(<)nCppqSAmC ze^iR>%+2{<#_v;NBl6Wq{P_m_ZrNReB^<+MGi!(M8U#gw z+dNHy0u4g%4d!38>L7H$G&YBB6IJIQ`n9S71rTv!VU)s|a#1^Vt7-WqQxA9Wmj7*= zS>pMdO_~}|$x;I=pYQiaI?7sSw+|S%Fe_mc$z-!^WV*@!iGD>kQ7<*mA&OL*3reLW`4(()>tAcuR1E>~ zK{!4NC{Dnn)mE@VY&QIR&zXMbVJ5CS~3Bn^dy%k$QL{V|5(K{7B~0W(Y>-epk* zmFC96Etial9;hz*VF=YA`#ya2Nljf?V0j1I|Ib1pcok@~R6(CZ44c_QEAz=9a|!0J zr7qNg*&YBzC>m?rQRS`5TMWrP+w8yk85S;s0XcgPEaSntqoA#F5aL-IhLYzsllQ<1 zk1?{RC1j>!tq~0Wh#W2m$%s+aZwW;Fp^$~(G9`edU|mrU%Hw_$RUtpEn)%vp zk#YQ~qYe|KVS)J!W0p%1u5007b%Z2&3k7s&=Ts_Fwr|$)Lgk|44={NF!O%eg(nMW< zmu~vs+B0Rz5&=ty1m8!GIO|RAMlS!csP;Eh+9_RsL|FYHOx`%B7b**X+|IBVdTLfG zz^GZ)4{6r@8Y*6yLvPX-6RcTTRpLMD2^%EaK;fk zT^2BC&0t2I&C?MJL(qYNj=qcLD`kk-v7CY9kC_9DT`HBf9dvHvWFonx*|I&q9GAQ= z2&%z`6fZ2wRO@bpALJf?k5nrbq$yGIq}MKH_u{Ch$sJg~|16OeQXHtfzs+|j*A=d13bTx?eUL)E zWC=9&`xK1=k9h`*BAPa=3YYqJ0a(Kk8iOjXQH#qcN+sVef6>EnbyGFaYe!kHLNjm} z4mV1+_`{%bABz$>a)KHPrPhqW3net^TI9Yr6hU<)&efA111Ne3FEz_8(uPFL=ypN& z^L>TX5$jV_9fpd+)}*ZRG$6Z00dv(GND|sIs6vgmQvCr-dxI^+(TmSOtgOyqyBXnu zwyudmRZrUN*<6OC-YlS3x7)(D^ZAXJFoAn0GV9N=hFcEVj3OONOHdvBQ(HHQ4(Z&R zl&G}(ty%6-*qZUsa2A+XYHk7%38XXI6U7;#l1gOD@mh7~k|{*!M$++m_c0lvbesVs zmar@;v3zx%u2uK^?&bj|FfeT+dugFc1ZWElx8@xyn3pO-hx(O&?xg|6?iu%GE1a`8 zaI{K}{Gj?A@V%NRH9>Yk7&+Yum-@1?#=fsM zEfiJ!Q0|+b6JK)`0zMb#i5Hd44=hKJ^Z7q_x|~!IJ%A79I38gzQ!Oy>ad<+v>_?%BIz0W?%}TE|SEjj; zzFza?0f+Oplolp1d#y+IjYHYDOZ0PP^Z-=m^1#6I1uU&8z+UdJZlYLA*zR4>XM~`~ zA1uhhwZ?l8opa(S9C9(pRG$*+VGPy`z)FE5QmTvKbnJgN7NLQF=iNk#!tc^ddwHiwX!j#Fo|&=gm{5tu@hziISL+Y*VP#sPG0?A%KefIT9G; zP(_gWHZtp$asbOG@rce|EQnVM^gdFY({^ELc=fKvEAsKw)l$uj3SuwN1f^ldSo!6w=ze0;p^!L3@!yGs0VL zcM}kza=x=2;Q*Ebki}~TP{2Wrh4F(a?XL@|%^6x?B6P|r+fIVp&%HoW>%&D+xDaaw z0AB<3W}p9Bq&opr8$LtLiXmeYZu@tU9Z^ngiDmS!C3OI{3P9RQWaWPuJ@Y36AG&QX zU*u`tubJ3&<4%~nhW`{h={bvM^n_W~*_5>lkFHK$c}Ia2b=6T-plw5c^#Z1Pdu@c{ z(px#w3@h6Yx1P=TWNrpJT18oV#IRsJPJJxikuGqjKPHSUtVqo%HH`1k_7yRwz;o-{ zdOHqr2xkK_iTv{81}*J;-VfmCoBnAEsU5#`rRn0t!6f_XdGWA~>8JP~y3jk??)8+~ zL<0Y_p^fb6-fZPu4^n5X$njC5p_WU#~y{cb;8;|ECz zH>78_cvtV0n_q`|X``d}iJrDbO@YYZK-`Ix`;N7>0j+Qo%=oadTHh=b+VlpWU8wtq3O+uX=vD)jXV>|=*^jahSWx2%BO%AF@6yN+yu7th%i zpt-u1txX$d{}-9w2__dH8mqb@5KD4`z92Zs$un!&`vT8vNEE6w?;I8RS8prO#TVQh zU~8@_m^fn?9z-ys6|nwK+2_c!-i6H{K{$o$8R5jk$NfIo`C-9!2h&hQOS^WcXpYK2JOd~~#vYL8)A`&ncKh^5NnaWs^ z{U#&d5_z>iRFFtfTPfq36q~_@XuShg_D+p&i5xaXL}?-~RIf|KmX)c0ud%2cj%3)iKdxOxc|+B3Qk#94W9&G8bBNp0PQ#4>6_0FvlcI?mgk zb@PEqBr!F16Qwe$ASSJLG_A&RG|X{}zr82H>T4z2-JAOw?e@VVcSO?-X3?i5a_E8y zX}0s0>2dp?>@4@VVf26-CTvnI<94`$(d$)pb$hLlFF1Ef1>C7Mdi*p3lWB@y$HIK#6}D^9(F!14TpyQpFbpglGz(B*B3M-`;MD{^*@CoA)`88 zhVe@zKuQ4XKC?jJxFRu8HX%KvkY#lZQ9vUxcMQt*{VI;T0Tk>y(RO0F&{@`x+X|pFfZ2A)!C? z@@ebeS4cya_}H%cMSg0Bw&ow}3@a|37zc1;{41w*I;$9~-c9cC8rsg0@D7*C;edn| z_B#zv<&2I>GLAofYG*X6SVri6<;Df9am#L_lf`Rrw&EtFsmC&>?J_bszhxXv+!E*l2?e)Su2bKJ3Ew}QUpi(71$%$G>V7`m3h-O!ha4jBdh|x3 z>wW*5Fp8UG2g4V^h{U5iCDXz>mp>vWT$&rlj)|9n`!$^nTxRF!z%1wvtlRw83*H&r ziLB~>L~D@5D+|T%M<5h=+`e}Ez}&rN9Vf|w7b<{9X-?ykA{&$rL$Trg`&dI@W1Zs7 zv_`ktd6>j&nx0&&g&s4=2}NG8YIE;>4U1;_FLB}i$;^E*QJZiu7rm2UicmKMy1Qp< z7}t$2EJJC7YE5tHi-y};@s5Bo2EfYyX`Pc^ki>GeIaRJo-vZi5&cbv}?96XE@4RXl z+ixMd1~`O!a6fC&R@!NW>_ zZnX)q#JiE><)PL1-0HHOB^zUIa31@Fzf9inalgW_xQJt3StU@hx8E{G!y-uJS~W4Fv(YsK zElpFfomNOly!u|#&2J&_lF}E-|8F|_cpK5>&gNFa*(&l~jO{l9p4NwuxZ*iFUJ?VH ziel~bVXi?S^69*dO)2Y|N2!nd%~hSOWsr-W>>)j8}Kq(d0B_|`XrffaFU30mw zqms$Q;V`})mrHi57sJh#sGorx*4#XG2%U=uR$Ui!+yn;EfWZ5r^vp`|Z4)=~ z+3iGl0iVgQ)!5Y^+~k)81TJ_&gXo-=11NMenxP*kci8NDaegw(5=1x zE7;Hd^=WAPj)DVc=atF;;1ZTxDO>EfYtSwx+q4iBdT$$9c>|RbunvRnj0bn>xdQ(E zf7_QqBhpw6L$bDWNV#8_wE42_T@;a914VBkD4+-^ zqUM&qbCzHU;2h|u;kK9bV{di?n!vkX`4dPI5#z^I0OI{=6amb@^K}*n!A>Hwvb7W-<9H&cf%2E1qJS-YeN{maAm?Jf4|;0B7mY%upkInGzHs|WD&)n-7^ z_lcI|Yf)84)h0>9*3RI|oI4e^XDL+J&jA(Q5HizuesSCR4Yn{G@uHF)HSXObY#5$+ zgXiH9af6F1T`p+}HMaTy&c4m7hBE*JmhN`WiBWWeN%cc7rzUa<`^xkhN9yrsmpN|N z=ci;S-H%Ih%g_qfm$s4ulDES2OUq1NZY8F!yW=s{e?md{>}lB8P(80~6fMA}&^w8B zFN1%3Dc1`K3(ykK_U5}Qr&%KO@mh#^)vR_qwBe;Y6@!_2{ngLDAvJU`tOgJ3RmBaTZq*LTgB8i^0H7j) zW|41-3yq~eI4uAC(e;ECGMxhKwEoSDK^JqTJxeE8)j%w;9NTOXqgbmts2R7|i5&r} zl6NmygbpU@uvZRWMp3~=j}Zo=8QG+ThTwEt4bmzo)}Q9?*-gambc;8`babBgM=Yew zzTL%1%m86s(3)rwELbP@kf`j{TFD`+VEk{j1Gqa02U?CdTG^8x8K4+ce@k-gaQmHv z=U7?pFsC@uoBq)J^B4D*d)7cQi9{=dHfixNf${>XKHqHUl;mu5%mkc93g|9;x0U|~ zDbn&ESm&(7C@gKQ%`rEkzG8w~#iunqG|1Q3-}05$qEj|&mn{42Mfk+Ud9a;!H*oE> zXA=;rjc%PMbcnf+HpD2{ydbPPrO)fcTCSnD=Y|0K30VL>-Q?yqN566prR>Dfdy?Ex z)veF1(>e22_!c@!-mSU-XV2KSO9qpNob5!L8SB}+;__lVrJ>3PC@Ju?V5`q8t%!lR zovMS6mAXhd1dpl)=Ay8P!jPzndHc@eLT#P4v)#s>-Xof)ezjHxo4EK+brMb9B zmEAEr+!Lb+2k}bTd5F~KzeJ!b6mJX`7d(+vx`D-rvv~!{PHH6^;SDHzq^H^frNY+Q z385}7r=-iTV}~le;q%K>iD_xtPjTl@Ac#VBma)T>xQUEe&V z19(ZIY>xcc9WpCdS`b0*ZOu64YId*&gXW*7^y(Cbpd+ZOou>=^%h$kVQ=K&%JLF>E ze{XmHy!!|UF*u9vGr|GRR~i(OTw%bz{}fga>MhwI>xa&6Vkg%wfTSB$DiH}?j`mZ*GqY7Pjp||nm z2-9Y0uD!|!eGaVrME-j-bmg5bk;_SsmtcC<2;n%d|D^91DVefmJSvGkoxcjis~Aod z^sGSWVCj=K_Otqhjtxwp|DY0x{+_`oulXuA6t0s;i;I$C2_}#?{C|X!LNMk(LeyvW|D=(tZdFVpGtEnQ!bBmiP%QQBQj@w@s zmmkUY&XqX}Msaj$Xt+2|t94gz;Rnn>Otw> zP0NSUqrh`u+WJ9VqynmzKz^S6iP%}WAZjj)XT2QZwl;zeVEbv!-E>6Ji0(Y^4j=h0ORWg5ATugs7yV)g1K~b)f33Gd2HpBai5t_d`SF}7!1$?6 zdjRnXeDOTtiQ*6-=zhR4!oRjVv-jldqyOnsQ&j#51d7?8BZmX#cxPivw_6)Mk9Su_ z=uq*5?(qmbGUG>jMlr*A-i@l`qZP0JjC*o{8w)xyDb}&u*i9APdOS~@41E|87<35* zcEe<7!R=aJt7C-I{R9qj$MyklRAaX%LX3ZJuUMn;7N#L{ntU~iSV4qRpy)8FA`W~` z66W4ExYJBda5i@Lhtn|gKXZ@&>1JQ`9#SL6P8IM0!Wjx}{Z@CEcyOW(8%roPCVSRZ8WEB z#u(9~6pnzWmo+lVSk8xU%x-s)qmwzVTHXVOvUstzTzP<7HOEv9oCeDEOUQmbNb~aH za-*BlDKliXg`obCq@3#c!xB*PJ}yObiu2*)i9v1>pi&3JaI05h-4Ly~l}jrppKt^& z|I_;9MoM4qbv|1ndCv$qB6G$59if}&+Xf5G1<5K7NXZF6h1*I0djid$-tb!2<7pDe zI?8JCdwmCB%+*B7pRxrGgPDAi9dQt3r_5RbX@uh| z_Iw~GyXqvgu6olV6^f`tG;$)4Ekl{p*}4aOk}YW1SsXe=$9Rr|{5S!$sq*!IPxSgD zMUBtyWLQhYH1~)+I4xoviXJ`$NKFf_*9HM!j)A$SJU(3@_Yvo1J}7)s4)UHNKH%{@ z33A;(_Z!-3I{!V2?GHIvPoHxhV%v&E4y0DozgO=IC>;22-sDr2p!@_^tJHa}yuDHw zDbLJp^1~0HJhP$y9-;P!fHt9`i=Xad+ZAFtj%Cb&LN_41urA z|2zh{voqg1108pj72qqhRSxw?LDA!flhz_c1*VMITeWAu`ol8_6M!@KFcb>7Iih7! zy{AjA0GUyB*PrDm4)QXU)8!{vGk(gfb-l6=Eu^8xdaoFRNQ)V3h#n?foFz2sJao`} z;9a9}05}8Pd6@e^*Ll+8MWN?W1_1?UcSPDAscG+Q_zRIccc}?7V8fKmyE{zk%Ifa{1LRfOQvz$dGoG1GbHUW$UYKyI z-}2BLPfX<`fT-jiwnLT`6k;#gjRKUaC-79iNDw)m z0a%i)9t=Y|?7HAy9ukRFPmfmXNsVGFD$pBh9uK)4$KjPQfM&MXn!f|0F1+a9j|BYI zA`B+AJquuipdH^+$j*%2P-d^u*!yE{r_%+Za%^1El!s!2VJTDV$m%9Y+ z`6W%2llyb4HX|T!1wM*#nt!+TIpwHVSzDApRf4?lq0_OG5EZB|F27UtHHuX^A(J!c z;4pN!3w+2CR#8Dic3c4(q)*~>{yA2i0C(Ll;M?(ONfh_@e{8(M{gc$`DzxnV^k2lX-14h<0tSHypGwq6dux5OHf<7OTNO}N<$C%FctPr z?uDnhnpZ)ysGWRY+d`?1)~wio%&UtUJykyVjx=#wbi$B_ikedJSNSXAmYsw=cWNcy zJh5+KPopl8mwA~P~K`&qXrC$o8h+ETmzepovFWy(c`H(m$7wj_Zus z(-^&4Msyl!VkQHX{=e2M{=aV~btopTl>ZJ$9~LdS|O zTA)L33~744*8654J5q))fThL=QsSOD^TZw{Ab9=nmJ$#9*Y&V1a{W&0AU5=x z--(he9LXyIT<(?Gc!R7OB(+=)F(FT1IPrANW=VNT4$L~8&}mbhCLXB*6SDIg_G`8L zfeSO5E_o?5YK9pUvxpzw`YtUCGSLRSajiH5<7pxHLwH_HH;s2%uNh`c;&5rH<=n-b zNTz5ayv-CvWf}ZHp14Xo&PK3BQ$`KFu+KKmN##A|mXu4Io*+4Mkt9bv+Qu*I;kMF- zik7-PP9wsrq@xZSY%-n>#Mqvk@on|?oo$Vrft{Rwe$h{jo~mRXntuwOjJ&Io+T@>u zJ+Q|U+nPqRP)ixZ)Z11v8hjn|O zzrg5#cRN17%*}2UTUbbZtgSFAX`@;m}^LHy5 zlk#7(lR0QQF`TT+0tOVSg~(8?*+!qRCi~bR|L$V}t6x36{{@+MaV8Z%O&DbjCIHWF zHSpb-qkNlM-+UcJx8JSr@k-gty~kGlvL}GK-yCuL7=ordNN9pP)UjTQ;)&%nvJ9nE zQAm|ko5W`-QsuQ<7VFTua$e==yT0lBCOzKB&lhBC^^|EHJa7!uVz~TEZSkmo@ym8) zFvVh-73Eq!jiXzA6dz#C9*^7D)%59FP_PAWR_k45#IFs?3-43H0H zEV}nDwf+0ohO?{tCcI{KO>nH#+oJBjc?N!KQlpuRb_QEGgaluHixogqj z@)KG1A&KNq5(N$K_?VaZ zPMON4$}nvKA8}ATPU-|DF}YHYTMhMo8+Y}U!#n@1#@28hd;=0@l?yi?vc7%j_&YVB zpEwHdr7qp;dfoDI`YDgoHn!@5(>hFSd1Bwr)XpZnFbI*jZxL;k&6L%$P*2fHV-vN^ z$lNT;)#lbVWfV7a&vjz@Ic9WJ6DxM3c*-rlSqquzEglJf`MA`jeOZ;YyO{+hczP;$ z3Y8OEBPQ%-Q6vl1a=h@;g>KrTu?U&x9@>JqbrYiUpMMnxyC9-%<{9`{5b76g+RkmRMBRq#CtUIL9GOSS_4_}`(vfVeNNw5DcuD=1h zbs%{64)Cq7m**5*M7R@=f)j*Crxa1n6j0t#9vjecMNeF3WgmM~ z2!2~%pWbgjj>zrZXOYU(Bvhyzea=1@UXkt~W^Hi^;!h zuylBQcI1Ws^ylwDn*ZG@Ueg%P#cKkyeAnUwXs!nSPfYVw1Jyr&`58#JB0^E!x5SEAgQ=fnwqZ8y3zAQI-}o3)Rj&;XU0dg7BjOtj5N2YYX+& zyEm|d>c+NQIpQ%cw&@xSGp0-B>wNgQ0YRWy4ogUlF?cG(?-tWvKe3qGrYjWJ2OJPm z)4Vqyar6L$A>(n5^4x=A5`sRPhsa57Omc-_bBkt-n0%3ad;0@!h4++-KS<7Zr3#S- zHP-KS;Ld9cVp7%nv==>R8(42}iWKHjbK*6wnZB0{o~fj$ zW+9eIL+h$f+tB8H$&5pCo8GZL>r==VlY#zgy$lP(pFgFF*C*FMw|7bSf)jU}q0#79 z{FLQjn?ysLT2gbq=DVc};vsWKi?jAiGk5V;&*~6gkd6xS_)MH48O1oQM?jmwN3^%h z;M4WXnKxECO@~9uqlp%KrmG^d-RqySnPmQr%FC^+?I|x6fMun&v0582b7cW%1`nMa zKixt!4SX6-wekLYN*mU`C%TQP--|kQi!S*8Qj+j2`jVritJqJU*6CN z{vIVWS~9zID647S#DGxYwx?lFkP(|{=Qyo&!S2T_W}#m^;!BRMc}&AR*W~pP-y6jW ze$`qF#&K#59}Hutpcg_{icP@?wKVRyt4l%R>;S!5F>eMaq)u? zgOU~3I@>qn)afgC={r9&>8~FT@tZGk$H?Fs9*i(V?QsTQ0*(RuzF_%|FqyXn$lbk^ zvr+&E^c-&Ks@>>_bCZbXYPDvM#WviSV~mjwG2m^h|3xXU`Ol70=8EH0w`YT1$p!uK zSM`u_>&}r}lXEgd8eR0#!GEwN;Hw{Am_pT7Iw~4w)QQW?g$_`C=JbNBvj*hhSxj&zgxbhnjmu7@?yUf`&lhaXU1v?r z-$B(;jHbe-*xs^BSI9VT36o;@mSg#j_r1G)Ld?~#6hp!q3zj~X;FzhAHR=zI_z#SW zYy<>^O@^4vjL!nsHI+0%E4NFoPjAUxHwli`Z`@jTxmTUFZ(19vP_+22q@*>Ib8g39 zw>Zbq#vC5;bEo1K?XtrZ=d#uy?z~eRPX0dYLv~Z!-wp(<9pX&i<2eYCT>ql7+@Zg@UovNPND!I7E;RRvT7%jCrfK43U zySAyS`GhQ~-?%6#7>E%TX1FkR z5W0z0VjeX6t7JNS=&dhu&SN4ExoAiiG*Q;JeoxIg22`w$-VkWDlV+E08H=pfJr} zZSZHhByQ?jtYk@CVfiVW=Es?xAM2l7#4mn5X3qpOd9)<7$zkBS%#Dt}Poh?uShL_VCikDTRLAt(aDH^7XJ=6gT;(`v%ipsws7F4C_J-%J zY=4YSZE<^qUv>{-OuOm&0ghk|7jD=F=ZRm=S(Bl~S=RjX3ft5&jtdrJy$TY$wr z#Nl|6 z_4sEaDT#4bh5L1-3>!(jmv*)d4|*LtwW)gC90W4v?=fSvJ&B{#=PB8FzP|ZHzw7&j zy1my0Mx|D@6FN%w!}KfblelAWcLd0g%QHZnZ`fq?2AqZQ^2rFb>s%GOi(9wXqOrnx z%K^yV@P~2xJx?JIztDfSytjHQ7I)BYgn_zq_N(v6PFwZbwD0itMM+R6aA_I8h3hOo z+v(F6?p>bTN~Gl30xV3uv=T7E$~mBXO+S2Re0aEul4s{yWN*EyB`L!#{|WY?Qu`7f zTTIVox}0YhrWA$PuKr`(Z5KN-Hz$!OHZHa>2%Kwg6ZdjWr_KB20t^kfXgl!Pg`Yr5BHv6VE`?niI3+<54rZ{$B%K$}5To6!>T zQ8SAmE%;=3;K!ZFuJ6l;+Vs(%=w-O~Cwk#VbrocUD$CycDtw}DEN{oHnK8`hni>`5 z6+N^`4b{{bsWHNfwlR|_0PK9M-pJb&^6>>`F;%UKzmwAepxR8|yHnbfCrJY&YHxY4 zF^kqRSPd<60vEu2i{C)WC5oRWEsu*I0T1u*jQw2AZ6swsTH1f`;BKE)qjrGdfOjIL za=%NKUHd(<#%2K(KGQMV553~Squ=P0 zZZym%$iX1`S4529VS)N0O7SaMnVf#>pWW`g!Dx>+MPQ;CkSs6)k&$DEOIfR8>>uUF znMqY!ma%Z}+Sl|>>Sfgr(;*r2fWb-ch?;Btv$SVnJYtrVA~>Q1tzZLOz+e82kp;#K zTb%xvHzeW9`IK}-J2N7Z7W@N#NAhu$ev!&f`kFnad4ZHX45nidNz`1rOT8n}K8a5% zOZ^>6N{;anm2v=^ye)Qhw1oc(Shq9NQOmxw^7aHyw5k4PpB{Pqw2h2Up?rC4ggZ0z z5A!1_i`0l4q&2r5OTy{$9qm#R-f%<)`5(xu?NVWI-2+g%bAa#N`Lr;=cfR-wQP!%q zEV$hKqfJ=NMysaU4 z3gb6DFd5)ecu*(ST1ZRp@zO%$%3$`V>o-1oYXxgRnKV-Mby#Ae(RYeJiYUU z;jIfY3^{h2Qo;)^Q7E4 zjs5)zoY&WbyfbTEuZxya_E7@W_<-&|h0Caq!+=(?UR*7(E&{eJ>^~F08v0AgJfE5~ zXfU`m)E;((Z%OC^YXTZdE|T!M^^AC0nz6v?iSeW0utHr~E={GCwv-yFwtCKZ1&6sj zRubOxE$9C66=A!Wu@ie`5&R{Q@g^hIg$~ZtpHD_5Yd~TW%!3}BFe}7_VRj(+WQFX; zh`Dw>9rJX`4I&469=#AlZF#5B6HY;HN!QP7g1-QIEd50fB~jvrdy!KDlHj;;@awd9 z1`dDqd@wZ$Da*RJ#71gnC`hQHDdl0BSn`2LaWl90g0F}6vl*=$5k0=h(ZD}{kQ)Ae zsn}TZFG^gh%g_DdpZ#P?zukY=eBWfCl=(uDwEEHwiB|(3f_hv{dQD9H{adQ`zHL0P zO(#`Mq`UCmmEIJWTNwo1M69i$pD-OzjC@ zF^Rs_V%!ij_|;jV=SxqMKfO8mK@CUHh4~>7IyiO|C%M$$6b&mI`+lNl?d-p?-zKd| z{^i~~bPrPn0|(irE(5ed8TL*f?*Is`?Tw+b>pAHj$_) zz~_`iRTM8hESYkCJD$+IQ3YIZke`~qz2uVc2`!znk6JnkHw8Hs_-9QKW{?|GL;)f4 zl6$~k_n&*91eU}@%J<#wkabKug|uzfxy9q;!W#&15w5cMMnn- zpJHde;nMkKygRFQjQ43VGDwZ_?RYA4GayGJrR*!#`4-mI3*Huj%A3IdY78I0owMD7kB-HdRdR&V^MQ~B?R)agfcj)LR z>U_E6*Gd`Z3x9pDWmoIOiak z|IgfGfst(Ru^fwC`pLCQ>c7Kh5NoiXt?10Vx&BjsPkXV7*?!Mb=lpgxj#yjJ>J>Kf zMP;3UHqUxV{R=%q{DYAnOP~EUvwLBf*F*4O0kDmhoL`JWzT{n#Pw7x zMve&mxn-Gl!Zn=mF9FNebJ+F#LOK}srF(fdbvrw()Yt~|&#H^Em1%nwx*|khjM8UR z3>MX0kGbf3m1uXh?jSYmQ`W!ZuAN&%{ zu&F85LXTc@`%+4BNAsUM#$Qf2wLdDOXnBeB8E7DQRYumbn+N!CHQ3-vf7wmS&@Iuw zP~uZjVd7=>h7AMBy1r->&P*f5f`e;J^-;Kcruz0$!Tt7XG#r|$Gj(Azm6X>?{&}uY zTZ0PwkkxcTD7&0!JSXA=f0ThkOs0`9yue@IVqs^f>BjbZY2s~`zW#FHl0_w^dm?LE zFRA?-hc9%J8_ib`_$_Nwh~ARV=PM==Poh?o|5_6^|2}Ipe(vkZ5{CBFU;gF4eDJy@ z=~X&t$OgA!oTao@VH<({ocbCsXfCJ8d+?AN2T2x&A&Xl-}z`EjX^i~qRthbFAhvz zjFR3DW5{1cREjp|4_-n%!J-j!&-~W;ljI~tg9F)@*0Pg5`0dilPG@afk!Na*I(Bke zwV%6jKU`l|NaH;&^Yt@0X)i0X2KFpl&@EnzP)T0g=(~-$yz%mB#nl{_;evm{?`M6$ z;0c%aYRm|bubq{I>x7#spUGjtzA4pNk^cZ~aw_ifsD-Z5_bj-~$oF-P+cjefD!@qy zi1*mCi@=Rmk?#nGSN;wQ5AT#qu@Q77%*SJM@#4Z z(;ZiB`ih^;z3Q!+7!=q!ez=t$bl4eNbw8R7x3ALaI0(0DOGGRGA}nX@%%>@*Z%2F< zz~PlYYB%h{pIW+JN5irEKIxfVQp}hCpgc@PlQ*w+3~R&Ly2+`u@V$Y9wX2ti=1$6< z?WdxP;j{HkEZG-TxVRp8HU`afNh(H}Hw=-k*!}h}ZIuj_*NWq5g=Z4HHTMtLI_0Q< zZ=iHE#Gpgg?C3X8-L8=jjC5{CUn1<{ zoRqx9dCoWV%ZJuyMd8Z0^^61Xvo~boA|eSK*DK9FJJepXa8V3i{`YnLaOk~k&=R9m ze|#ZN?z%8spQ#fV5NUJCd1>! z*@BSyX9fM!EApQwX~h1*Uw64+6rQ5wUeC~Jt>+!y;@2YPo=nEQ7k7C-_aXcH`#c`} zk`EcIwb%zso?qbk_yK+Bf9$F}Wg}Si8%Jss(fjTo&rWeKWta9*OpGX`GuE!L^=o*9%#K3+PxJH zHOtFZ)qAQ^;FYX&Vv#G!%GftL7+YD?5-T6v9s7S|eRm+$-~azjiYR23`4*vEM6y>( zk|N2<9+AEGxC+S**<5?e-g|`XP4>#(d%M4LZ-vkA`}(8Xy@1)sb` zN9oXuqR2tMX9DkR(6Zra?0a6v>X*cleEQ$%R%)Wlzm_$+9XsyHPN8_oSDQ3W-^(`~ zqxiFJj`}sOshq%sAfmr@1t0R9WI4@C4i3nj56H{;3I0C^P<@yhV9|k=w3Aw`ob@>VbGM2w>zuRWE z$5V~g%ub;Y8x;V3hz4~yE@qxTSYj;4!VYcYm9Tgtg=5B8-Br&{!2U162I_OyeEP3> zufBQh-{7nHJT2m>z7ueZsC&p>g+S-i6(U`pd|}wDC*=lLo zdfEA@h|#X#n`*2wU!*TOJfqFms4ce0BJ=&7mAC$wwnIr!o?N}w0M-hAPcNp)OEHx% zU=a=b)A1tbMPo>8pPjFaFMUqCh*F?u8|tfB&qO|^Q6v8nxoG&>t=RX;1++w? zpESeo4i*v}-V=L60;{%T_^kNMxn734{i1JgK@npiYi08COeN=&Xt8;MfRCQJv z=DxAO_Pv*M00$+F>RgfE9+_WX2+-hSJy%2sM3n71b=KAfavwA53O?_%lZQ7<8?myB z2ag}bDQAg!m&rP7zIbCg3{S(Uw7lf?#luEfM> zsTxF__8+EmrWDH!yQyZX5dL2FL)iQ-6W4ADlb9Lfb`L`b$9ITVs_^z$DvhUE=tbM; z9REVI!jaor@NfH};P8=uwNodqg%eH4H-7yh)}kf$M*fm7y=1^gB8Wlvb zlW0&z-il=8@=&2zY>+?207~Y+Zgjr#*61vxQA*|xogq!>74fp?*_Wz`w5b6~ zygV>hKVN=9O(7p>tS$e#{9Zt6_E)P$gLM?tugEKf|LDbHx>I;XJW$K_{S{}%G2R)s zrAi!z=GcL2e=7n$oMllPu#rEcoJ(k_zSa6AXxhsj52B$b2H3$mq*K12JwGg;wbUcW z%=hA^)9O3jE`En+SYWKU^Fo;vkVT zQ`1iH&(sL*y$!OV=%iw8v-%DZFMamK<2eE73Jj|J@b$m(AF3Hl{Wj%B??gD2|Bj5l z*xCC>1Cqsbuf(uu1Y9$#4QLg{gP_^44&44;iRZ2UmN4Qo>iIwa#C#|98;~*j_fvo9 z+3=RqAP3XAGSuxs0UA`aumkHP;J4e&YRhNF_2nZu7xlp~IP`CkF$!lx3W?Db3wX*{ z9q_b~pgQQPEo;88SCwHc@kx;vGX3HT$fw}B084z*lFp#dN7n!Rk zZpq^-y7=Bk!X*b2R2RORX?R$43m^*T0_uPA4uOQT@$N%{sXe+XzCz^ivh=e;XJp{C zmoLg>r?$~AP-KjZ5#N>zGQXtu{mjNdoavB50TmBRB4C7+@4u--XL3~EthsWr1)WyN zZJnr#@jQHjECwTo01|^Eb5~_RR#(N&@b68?53a&nY448A&K_g}Zud`E=WHdmS&NzN zt$DA-yA$6w;5sm0y|GwRmWDFggFms@H^+?k;x2gDn8t2Ay$bcW|NLysIe>v|OIVcQ zfm1bZhB$J)P=vEv2^r8XXW84YBv3><1s9s(yerPe^q+GT zH$7HDfwVyJhYLwtNGWOysIzRz%yNV`Xjb*mnGjbm%1|#WT!Iv*&0GD1hlNAtBWPK) zWiRwW4ED(Pzsk@Fxa0oX0r>*?L5Qy;CjLC@;}|E$Dzg=gZHcfMnu|T2eckrDLX;nh zcneuz=bQ7#qZBZKCvx-$f~wYZABe^~Xp-)8jn@CsTei24_GVCy`9oB+!=4{fZXj^_ zvoQ#|nQ#e`X&Q^SmjMw{lu;;oe^F~oQJ}`Te~`2$kF`21t4o4bNNi#J2Ti@MyDa-53o)3-1^dgEXDY44a12bl`KtW zH2F(A>+rvxANibf`_I~%imz>AQ>U<}b(e)m>X~7<)+d)b?+IEAZgm5Z^wqevjyw1Bdx{bO0jA*JAD_cqI zj^)+$sU@Fm9XG4zJ*^jJ${`kij!^k-J{_irlrR)P{i`X5GBS8}Xm*+iR}NsGLGAKZ1rje!83UCzuXhJ_f*e~RwBbROP!UXl3%4E3R{6M^pH;L<&% z>y7M|qXVR@Oja2XOVz)45LH$SiWyaC$(xSe2l<2hneKvd3A)L9*@l%hIrw=V^xdUJ zzCn?>3#$?PCEoN6hoIP7K{dFK08bU@BkD6G7ekqcmn7>vE#3nys9mg2QALCFI#l@6 z#=)8VX;bz8O{pQ@8hqbFMs{gB0x(NBbCmA%_aIHz1-uIBlw~z7drj7wmaPM2`F7?O-FTy=sDb&Nfjm>0k)Ov*ghqdNYNHo*jJ zuw|8TbpJBS9%f^nsS{KbKi(d>;%@$1XvmqdM7|!Xj4v#^H4Q{e=%{?Quu30kmgGD6 z)b`-8V=q7XIPO14yD>y(p&Bb2oweN?B82gl&Ut#UYChs!>=pXFP^5V}yPQcu9HfM_ zqRz4)6RnRDw#M~g!QGGUV<+Z_-%G(Cd{G2K)utks2;@Jd;a^6JxjddFOgM^WN8PsB zdtv?zV&Q|@NuO@af51eO{Z+BOvI%7=UZR3(!fgHEKSkwW8i6{HAKrKysi3|Sa4Y^I z%9$rcdbSu@)&1l6XKLz#2dh*l5K10+=AuFMQxwB#!-!rIig6OdOubNjwG!0E@FD(#`6tiRs0D3yeNgg!_sqXQIv?C5fIvP71%zCT zJRqGSNI4N&VOHLU-<1EUX2w&#vZ8}xN)$hLYccm^z98?@HytI>mX-g0LZa4qar}Cz zKi^OPi|;=a46E+(AiG8A##!x6ls_TywT0-*E9e)bC`BZrgoPfttg?4?AsPMv4cop= zANC8`C$9<4#9B!i6^5AX@4XJ%d!3Ggt>BJ-SLt)47^aN&Nb>8V6YrLCmJgx|pgAi5 zV%gly4uDWKsnXtE*1TFh8S2)Ie~*JtAre&d)u~rBZd!!w_ZaOn4+&Wep!4{04Lr+$ zgav)g-3i%f>2C~G*^xu__sV{N5F z-2paJdZ9amTVH(zHOe1b8e7*!jlh$$5rA}xBcJRSV-t(JAUQzB9*v*_oZq_|7;V#u zN#3$zJz|Ko4j;g|B!2@J@GXY7JL3Tw;|}6PK#x$VNLG`hF=Hw`Qc6TReW*9d@zP=8;GV5_2;1+K2vD*| zeDhyG3Nd*kLv$bLr%=TvltMn1Hz3NZ!qI4B*w5zUxwbmfwCoC!RZu_roaPy1uXZWM zOG5_{4UV@Spvp{~&lI%Z->Z`h`*_y|*=%F`BNlfShf^s{Al4IYnnXND4Z{%zL+kH< z?PS$8=lsB?bXanC+8dRTahx3xpiAlh3bK+qYguU>qq~{r{gD3OhXa-v5NsIkMqWB( z6i+h*CVTUp6}043;baLfvL_~3v*n=87T+c{)qJ|SUF+do4vy`t$CyCD%9;RWa|FT) zkwq2>hU3qrrf@vQ0Qs=7w;%_g>`T77 zLeIZHM$FJ4j+xfD_7rM_{*>cfKzOowi_5iT+_t=^W2HL})`xhgobpDs{_l&xM@Iae zGr`(&>k!lfFIbH}NdD97XBkI;Y+94bz>j(%@55pU$c3XX8%x5rmX_A>pZ#xfk5h6> zDN!uHA9@E)*Dujz6DAuAkReUj6YxGE>~pJaQ^VCE@lJgwZ4kh0p_2h}R@1JW+Jje} z6plFMj)!uBt5>d`*VOkV(i45?C77$!0F^Xc+t)>!1tIaX0_RI@)-OS-d43HKN4>k` zoV3lq9?Z8@Ombl>C09Vhv}NA?)>cr|($d13LkpmCh#23&K2z>@;QYeBIUJ;IDgbHL z$hszU6T^*EQ9A^=_35IAQ`Kh-s`H9fvmueq=WHD-fcjMZqL0jJvfm0KI-JIkp0ZQp z%;bS@@&rimH(+(ja+;6m*x>csJ9@+iZ_UQR3zU zO6GrR4(=A-Z>UpUJTX6>l|yu5-#CAs|J#p4Qgf8SnT9)TQ`2O#BL_fWdvXuOSNu-m zLIWWuvNEw?MpD^qvTTym=|s8$247kyKUX9*ilEr$MLQH#ag3>Czm2-4F64?1da$$!G7yAa!d{`(gbz6%|M`(yWE0uxVftr3W zZbye;PuHw0xuHt&)RqHzw8QTE==ip|%;Te7gmuU);^;uLO>oXH>i3MnX~!i9S6Y_9 z@zLjJd_rxR39*wPA_y9aXTjwdNW1rB28j zw0PH+L@g`BF*+*I{rZM>*;W-gB%>?~wvzr#ZDDNd6!){F)6`>>v}2H?FYhAu!&Hw# zW8OWPy;K%mA?OOM2J@uQ-w})1o09f(#emIyEU>K{7uchpT=uINz`n3liyVZVNEa9T zA~)(Q5wFb4-CU@+@JnHMVm!2g#JA0M{=36z9>FFp&L%Bc`7z#|Xaq@s4_Wj{#PiYF z8>X6O8V-0VEqP*LbeiJIqo>cv0&7gn*|=FFF;+fvj+BQ)6>pSq@tIOLnQ=;igIpYT z{G2*4p`!rNQJfh!_j8B>RG2CNPnxm1h5vY5pfI?@eksDwX5(D5VnjFb{+LQ)ew%LS zj~XpT35kR2s0=en>)uKVKB0D4 zEwsLdfkbNGP1f^l!6*4U%k`T3FLl8DMZP2uipeUc%bwyKJTpOemOw8@~E9Z~oZ-absb9J8Xq3REY!eV=t~VQH6DB(ms>2PgK1~9 z%rw~fEVWsDIXdWdwFzw!%~bA?*5G=UfLRqavVQUB zA!N2vR|QBMye?aFS{?uF2ip$0u~ClLUIQTTVr|(z4}B6ha@JaDy{z4|-|IG+`p`bG z$wS>g=}G$bcs8`rC6IHap=qAdTzx8h|m2JnED(QP)35 zZ2g>Q@X5j%^dO5CzdGH*`fR$B%#VNfrOjrS`}N0$tCe#ulZM8EC<4ZLhVu*q2>y2N zvL?vNS5ychKADU%ev#zA*rOBSgpu;mEW2@$bYz@-yaJZew{YD9^BeBduH+-a=YX7R znk-`M&Ti0qb?R(A*CaPmB8Lm)@pB)fSs==bSaD+&l7>GcqAToigO{0?FC%!@M6Jgw z_k6X{?*(L}$x0aR;`Wab7POEOC*$ii4cQdor(IV}!1DZMTJM|3TwarEMvP$}i1qps zIkCHQHmm$tKyCBYPc&qmSWhQI-93D4F>hg$V`JZq4v0~OS!kZB5-oh ztHe&~A=R-Lxy4&GUNTx`4A0s*tjkTatBsKsKwtpww#KAoW zsVLWDe@w_UDWqEFB}ZI}KN_R`DeT02vH)=;j&6Ewu5$lK_Bf$eZFh4qC!j$~B}cZX zsZBEA2jJ`@lB#XnPoP}qyGhkXr)P93&`RANhAiHDuL3bAfB#U#byZZ|()?8Ho#lAi z^M9&gZzhaUB_03ta`JgED@ANrnEiJJBsasoMTNPp?K$2#-mKcEH!DV)JN@nF3TpfB z5@+@kwo=; zt&;*DHV@(ZH)F(CPuD9ZM^5&zK56cGM?@2;Y?aEPs1tdF&c__c9rjeG)|*hUryT)v z&(o>8^M%o3zoG}6LiT*x+jXkCK{c(hr_1fkGdzG z8uyD7sNzUUdfN&OI8MQl-F?snJI<U)y zhd{Vj>4aYcGgx3g(=&pOCv%*ah((;b4X1f>fy+Z!@>b-}d$&Y%1^Dv#?dCtKJdDC} z)f^zK_+D^2B!pj`cJP~@iVsTYVr$zZdF-`5!{Q`RzQ!qd_d2pE&UI*IgQ~Etf$>At z7t{NWTM^?wVQZGKHQ3>)-0AT6>HOhdWFWHD5U8)!6L`}HB*-y&>CkT>P`O_-j#q1W zxa$Zb=Q!O|MUg&1ps{sqNennWcn#wReIMA4jvDzBd~spyO_PE?+JfO<*?Yu7B^rd$ zGZhtiNaz)K*S(XZ9KI&mvL78JTn)isFq^n{tW*gwJ3)sb6Ct1N)#wel%_Dy@)1;%@dG123Apo_|c&0$yoD}yp7o4 zaMn?sFn(nI9S{4i_3hP~C*vs&fgh&{gHA>t!@jdzQzLR*FIu}Mcz|uD=G1(ujkGVy z`^&IH-pOT!qjUh}g-95(BUt|I%!Y)JP@F<00yMR@=jkjUCSubpBNRrkz2PgSQ3436 zH7o>}1k3yn)MCPwFKPL`L(ateNNtf`;&N98o{?6AA=f4vgww;Lf)wCnuU9ZBd(=*5 z)wfyTKMFJ@bf=3r5$3qPf_*#qd1L}LZBv3r-pSy&H$62ek%9_`JHL2rYMzBn7((AJ zELt_ED}ONJWim#afp^%;hWO5x(+_UzbXmN0ZK9R3z)0t&dz6>+ft3Cz@1R+WgZs9Q zZg@N01F7_vf%K~$VamtvY{Uq=8+}r3oi^wz8c*zb<2Ro4=<<@0C93B~i}sir@wv_n z5JNak`EV`P$xZQIe|;x`Vi81Td=MJ<^zaQE)}V681d+-Rq8IfZoV3mmoLd z`$u-JU{e-G+`|TbHMfEp_2`42hLd3(w*C)7BXmZNGuF2di#wBRrz|W4$i$n4D{y>& zIPb{A=nX2bW-m9yyDSiJ@}X6a;5svI9j%=ZQImfx6R^PP2Z^OM~LH!8hS`8#^EOg=5zmI z8e&V<=CKq~SD3p`g8eYrw2(8R*jw8?s5mMetO6^VG1>}^hnB7pjugyTk$hedBWO5^ z@7lF+`1*9ZLeDNcnkz!hbXGp^(XYqP^P~vw#(&^wziS$qKQj@+a7lvMiKt~=hnL*G zVS44mZa5VaDZH(z*5+G7Tfzqz(jfWPjZooGy8gT$!iWzHs}t;dFuGR~vuDk&Rx$sm z?N9oj+(V`;Vi9_VJ!Fo6tgy-632=v+55Uc{Y)5tKIx03TYe6y2zQEh4{_!^PctG~S zB|Ey0ZA}%NY07R@b=>rtZ|jQq!4N+S8bnP&#FRXaJ%Zh|kZMY6WR;PiQLIe;F#lSt zM?8bAL5_?fkL80fusxrU^A&+)a!->58@wU5DWc1Xm@{yMZpOq62OGazqsXJDg1se= zJ?!KKc@Rl(W^DO>R@6LPi{wRWw^!C(*oYu6w2;gXhc4a)@71n7mi)x6)guMd&ejGG z+P1*^;#4J#awJv34Q|~bUc|C@ zCi1&y`a;4Eo@-(IjQabQ!L7~Zu6Zlb>8(JQ3OpaHqn?eQd(0D|bF$P;4b)7#;k37t z#e%^;M*bv=hlorONx25NXv1m?;fwB%F+y+0>gJ>G!!X|RV;M8GQP+gt-C0Bzy*Nn5x zlj~LB9iO;edvrswA4Ds6xAwbJMfq|Ix~%Q!hBiYtY}kz&;%Q0O270=jppINqO9#T& z`clNaqG;Qu?~7xQAiBDPUh^AyH*K-~UMV(iR}nWpX7x#?k;XzmyvO9Rr+-T35^wh;xei5S3T_FxLI9y zqtl@-b=>Oxf|23{(-WsPV@|(@7mM^CE>!P)uM!UM5td!OtJ|MosJQPIx4zv~kL{<2 zy{bLkHRM*Mp9~+j)z0UH^YKyo(Y5XW=QphL%##D)jACH{NK>s?^Vs82)vf9XH@WYI z4Q1n}b{~?Y)lEjH#u{Ydw3ObLTO;}HnH^?nirjPr=0s}MR!_&$$H*&Bbr9U=ZV`C+ ztuuOFXPF#+Qo&y>-IikH-#18BajYHZB_5N(p`T-bi)o#wE ziIEDcto%@5&D<;>WiKD?FfoR^Qd^9>29lwY=u)LLp*h!e{<1si`@Np{>#HUYg?IhE7gHjUES%EQ#mx zuGO=y(_J;5+t?WJTAKHh)ah0|P)TNA{lR*c%qL-V`qYNWnltfLyU%rPZ>{vTeNZJq zBDj!V=35cArx<~QFy`)(_V9MHrSJ3X{9ZEM7wYEMvOyZv0xP1mIw718a)}1 zedG!C?9PDp3oE#8SX40O4(nS{WhN82h2q^Eq|F?#^2|sHkk4r*C^%wGB5CyN(sDG0 z!K?{aqNrXb6HHbYcysHr>Wb$ELaSc0+fORv^EW{=9XR}2?JIJX{Z^K#`1nS7RUgGW z?qS(@b4k?Z&qqmaZTjc5Me0c`Is{uEwa!m{*Rp0GBkc&b?>d#J3iEX&Ay(^K>#C`g zf@D`$>chO}YcbM%XU4v-MAnBT&<*C3k4?m05l{TtZTALem(G4pT-T&+P70=Z|B7?t znYo$J0^~l3!~Wqq$@2X*6d|QEjuf!@h95^8Rrlgq{?dwN;aZcQGE{8_X{GhNMNwhUf=z844FzRRR_mk0-20i5gO>OUpZn6<$}^0v8(8 z{gv~MOtQkf@kQ~OztOSJOgKor^&{-Rk+5l_OI{%I_T)7j2V=Ua{ev}Q*s3u}fO_KU zi4=Kw`55z(6QHzI&nRYFDGu+myuHX{u(l#dzFTOOAl5Z z+dh#>Vozyx_OMl|~bB3ed+|p^lU6^;!dr+PM45NKRVf}-$f$b;#xUmCO4`eBp z{j|+F>Ss)XhUUa$DdyrHgq?KQkk-<^=%$mXEZfv9EcF(RcMVd z6Hs||hAd6${P7rZjAW}ouI+@H+BmurzZnEsm3ZU=fN27OtqK||gw85{E$hKC ztelbW2zFcs;&114JV4%(=C0`e-h?`XX?O`C;Xk@iccW>~x~NedRyM#cjSvO%5s<$U}9#E=6USY-R0ba@m}|CT0{R*nCP(+#hWDUbS^;>v`DfYK@J4 z?$PT(@7)zgY?8(>hAbRlk%Mi!^yijm=|+2qqqW`5Qywd7ki6O}GEdFEKNVL*6;jcq zE;fWOAg)l7la}WBT80D;-r*Bhv30Uwafe)1C16&al-{12>6ug{JK!eGvsHSVWQxd< zE;EUpp2q6u2~kz?rE44ez{VZg?z+Gg{yi$!h9@&A(0>nXj9ur_?bT{5gp;sf=iDMQ zFd|9aqzm3Y_IVO~gTwl6jm)^~H0`(dD`aAjkc}pL0S0u5w;)6ewyt=LjDI^>-LF`& z9CWdWX$VjPYO8hZh;HyR1pb0N{3(`Dazg>btpUJr|59P2t34XGu#U<2SmZHzAQC=) zDXN_00ns&MC-Dnf7wNg92%RafdQ0)F(XZv>RNHAj$vy$6sasN!9KP)7|1sNPEUdR4 zoUXsM%PIENCw&r^n`v)ZVmi&0>b|QOAGmk=`UaKJTHr}3r4lr73iGY)ka6RLfsHn= z1lvkT#;gOagz#IO!oY$a+#N}NrtPbB4u$QvNcCmaaUMnZwEONE2$c2(-xGIb_A_5m zN*g=Io*v{@Rf1+}HZ`OV@)eH{m$TBkkWmUi-?3TZ!Y%mjdcn;*h4cA?#N@>bZ<8s@33Y@~SI!^8DYE0r+4I_Pr2K=)G4SBaYC?ne# zc5xct0oZ4MLgBl1lHa_ZEv4jC9Y*1M)Y(bdFSE6AUiQM6<*44 zHR^b)o;tlnqjQ{(p#DS}S45Z9w09w{kUW9uyMBxC(2a(>X6)TuFP2K>g2*Jty*8Wk zSc731U#9Tn>Q)9TV0`mC{ma*^9h#vlI~)>?Vu;>;b%p;js`v4UDxx$_8b%8-Q9~LwT zJOBPATs^VQE4Id5L1=P(r}Yc@>Beu+xn4vc{8%?M-s{EU|O#i@^s|wC& z4SD3_7etxJ;&3cMO`dmz*xy5@(?Ysd-DEPxi=_uD>|{Lk?cTF4XGOo*oD7SyVj?>}IFm6eQh*U9QN6u8y z-{9dXT&72f&*R(qC-h=>i730WnhSQv2)d_)NTGR+!Tkk$Rvs3Xqa-9N6&X=w1#TTL zmgNs~7@Lv|)s+hlwoPHv7G^f864PUBC%10Ha5 z3ECN#SJAbJ4~N|K#P~=2(d8^Iuihw1gsk_D!G?L=s)hf!or~Q8^!Tpn@4Q3N;F*%6 zT98V8h1a+YA9q~qu9#)O@~6RoROfW?w$xaaO&Y`LcJ7}ZctO7-)m6)6(V^@TKQtXI zW*ICY4^kKkY&dT4(>rMeM3K8HnzpM)QXnhUGk2s+#<1T~6 zV_tV(kSKH)VbCWNQU0y}X3}iPzC-Qg?HK%Fx0=F$^30(RO`>J`BWr!^=oTNcMltT! zLam$MFL{j_NvEuL$c`^lEAQabu_Zk!1*#$Jux&!4TrScb1QMKm`&lfTF;8 zn&=?o)ZcdAtBS>yo6CNek-8LNF1{1K_lzcD{4&JEVX0KKS^w~|h}^>!C$5#N+bhqu zyVb&ei1p`3SPWQpz^&;2^LPS8bkV^^yYW;XdR!rxwVMvCTRLAJ#t7O6zbA^H@ZZ-z zCxtGAntjcT8eB9SyJaWSxAx*D)>aq%;R-niAcZ1@)`xPIsfLhA4jT_BuaFAeNl&im z=sS5l2*;pi!lA7d_EV4=2{v4%493R&EHhw_HzcSERHhk7h=@o>o-zcI8NRk|%0{me z@XFqDYKU8PtxZDpYEs1Vcd%dvq8xXwHppGyAd!aclA{O#Woq`2@s>2L8dstfP`F9yWrud~Ta|=5>-|fE@2V0J$-!kys z#M%PAx$M5fFtO*kIqdTDrddS?CiYeB0mWZ2S8N~13kD_Ya~d!{(78z=z&KQFsx(lc z*VpWpM|=OsWpXlaQ~~D&9oYV{X`7G9 zI{P)?1A{p(t)N2j7)_7_4MF9;C*Fi7c_e@?sNT%bOcv%s+vw-~qa5aDh>%m0R2Ac1 zc7gmGkm|0ixq#ysayUFc;^4(}_mIy|TraJ|uSWI~sk_#xFEy*Rn>tmZm4 z_wL=n1o0X zS(B%l__hQWJjYamk}GXRbqa71PYSG5@Rf|N^YMv7iZ!fZ`(x{2e*2L7UNg5j1(&j` zS21AwN3O`wgrb}Hmm^~9be3DJ)%{P0c-$$&1%JwZnl$Zy1MXXW8to*3X>M^;HcmO^ zvXW?9(d8X~6;dswhkdD^!{}#_vT|4{^yh7qQ$F8TROv?1uo=8i%e2qyH5cW|VLnr+ z?%w^NtJn`ufv-7jSfCY;dqc|Cv>&uPz|owL#>al(lHx(=w`>RL#2fsXe{9bhFc2e9Xpc49xGyts!G7Jb5mF&pRp>eAlN! z1SC;80&3jjl>rCjgv8ka3Lqi#O4FsA#sonHPJfs+*wl$eo`uAi%9N>(eTml8a>!@# zs7_j;d-zxIRr(cS)6s>fJK~1VDksu%GkQ+%O<$$A9Utc{ht=1ZkK6^j<$`W>7z{W1 zyWJ9Pt}z0zrkGO`s!plB)R)V2JrJG#dsO2d#uI(!OnGHu7b_eR`oXuPtXR{gckGfVqMOx~`8c zf49cN8}`SE4BM8o7YB1Iar5!(M%ReBlsw;*Dsa-C;_f0+iC1_>vc$P6BF5nl(wLIJ zeM(zj9YN9P0o6OJ;!S;Me=b}k9iu3;*Jkp~gES48UM zr~%?2g~JO-=3Tu?B*g}5zqi8JA(-$;Hr6vFUvOuhD=2b!;i{C<8M`}H~dIMjCCH!Ka{oj z;f7Y$gS8ymu`iWnyu;b?<9#sc6M0O-OZMNi2*e(AJd#tCXSv~9s~%=iP|A2wCiQy-=-0j*YUPm=&7eWnqihQ?L)~|&-^%n;3gy_j7;ygzLUW%Jj&$XFr6&ea zDk~FoFy5a^UL!=uUIBKD@pvR+6;p8MAG8b6$+)(dbHOvuTQD5_U2J;3U`D7pCDh$uCKf24jB{>LpKOt|{Hx9qVg@%|M zuXut9EzhmGt#X=H^x1lB!`Gze)vi2{Kj-&nlf>1Fq#(#ngjl>H7x4#th!fqF2L&wH zldcX&l^x72;sr@)kcsg63LmD3EUK(Jw)<{uDcpRH@SLnDfegIUCz|@1N()rol**lDSbEN6%^R~Yvzif89+;XNtW?eb|04_q*vV!sA zCEQv@r(<`N#}SwKH|6WxM<`0|59}!tB_>Ec2o{vkM zv{^h29ya)^HXd2Z?9g^Gy*Iv9FUApsF3KTGt00{fWk#@g=%8sO_+?X15}&-Qn3V}Y z71j>5d$SS>Ltg2z{D$1bx-j!(X0r|nE?F0qDk`E13Ne$4t)kp2>MxqFZ%Eim09U%n zGiwq+R8ax-U=PU4-OTk(5Q@@yat}i8<9E7S=2qR!a1=2~51Z^?Z|5DmX;j)IfLz+0 z-Fj|NVrU$az)#H7V~3ydBs%{rSn#SE(CuaK2bDR@gqJt#jjn}i-}v+4BNy6Y%9YdNne}a2$w0t% z>oxWgsa+<$)9Nz84Z^c=g17pmR4AT*(pTOq=(ssFcdeVtZpDsAwQRE5oD{6+kZ%!f z%c;PqHTXI$__1Z|IaWsQE}67cq@JIuIvCAFh>3-f?G}@;+5+DeHw#vk=>U~$^vMAg zYQE^g$`pvalPB0BIuY=2W^0_V_FBa8;2g>6BZ=f)z&ALtnCQ|*5plaiHJA=-nTzdU zD3yP})S5_l#0x|K0TXuhCq7$PDYA`jZ``Eq117=;uAN8^1A%03RJ%8zczK#iG@0oM z)V}U1eyeof_?Ic#JV8#mDx6yeMnxSrX-&PiylL-GpC-+*Lm=49MxQo$g13La%1vtS z{zxltDfQ@=f9;}PclQPcm#|I;92=P|La*t*2L?^lX=-P(aNJSSWj=H#F}lMYyjWW#CEt>L2J}KGu(vpyzmi4w*>%A!3}>`X=Ib^w+{_X5}(< zMSLZ{1j^Olx^Kkdh8J_^MQttryOuczS0!2r(6d+$_<= z)0tL07A+Im$eTic1ykSO)LPX)8RQPZkyt65`%h^jG)V491|Ct@_E`D%NpZfr0HiuC z_sz6TkRvXKI$fLRb1X)OWAjF;iIfUNp*7aW#2xYA3s40vh5(NptO;O!OPRhHVQ)wk+6)8ivB^6lA4F^mk zIYb7fC9p?g}D|8oteX1lKiONL@V!70bTPuq}?iOgK$clE+; z)ac-ml?h6`3{>m;-pOooEs3CG@_+JrC>N#=n{k=w8MGN-VZHbY$Qj-V)_>@poNpmezmgCn5IM%v( zN%kqJXzCPN=EBHrgVo}>tm6|v>&BNzOBPbs(*yN*q23v5KaojTEDMyuPUbyKN#dt=@aY0n&&){31XJ|KDr6Mc==W;1<1r*JAY-)$ErWZT8%hd#eFVRP&b z+ry#G-UbulHj^zX6i(Bbg0D4z9ltOt&h2@Vf}Pw))BdkGz&cl`?;U-G;3IMY>u4aB z^R5gMWMtVa!GJ%tcz#9f6Jszj1_-J?$>-$6Fil5_V*qW+M*TG@CWZ85P3GF45iLBaLwXWa8gXp(FpUOlNg74%#K>n};b zNdfY)rVg7!?)sCg-Q@e<70**_4{(6>?qTfnvm?4G z&fe)%Wa*Pu!9Uz+<R zU>sS~2HpmS^rLiLaDehc=O> zW1toL)|TVTmLBc3N_~M4t)AWEuRp}vAH}iV$G}3r1d-LHWJdFy`O%!7W4v6GC_7gF z5l?pcYqBog73b-#hJjPNU&FanT%%jhJw_>__w{UA%Es`V*4?Wl8Ia>OaW-BMwcAhq zIc|f+P5R$Vb4N~(D_Ou|Hs?f=z9)%yu`@=OxmJyh#6Hmn4(!sZT8dQ6a+66qRr&Sk z$`JF5t;>Tn>krdAn9SY;wgp+mzC_`I5xl1L%*2pkvXFYR7Q4DsLYufGQUR!2pqy+) z9FyP`h??osu8j&E$JK{bqjYaZ^0BbXGrB!*gapWx3ClByklM#zu4XOUD&)NOQNkXz zE@&gTtj@6N2#yL#K7#sJqe-6)6Zpy{b~N4POPHxrzH@^b`ekq2Gy*7!ydFpySLEJ$ zp^?)kGA7wv1E)pG&x($i(sPZ10+A3g{(Mm~ASzcQR%w*%1b!*XX}!c08sXL`gV!CY4ZDG?G{vSgbwTC0A6WuSB<9g-kTfc~?vZ69zw# z!tJ)YtY;IKu_&1!#K^J)^)&Envi9oMc%!Aubd5QY+4CcJgJ;&Y0E2h9l0{d@!r0|g zOQiYn&?Nbv*%{S-Vr*71qWDRZB!W=C2ldU(z#gCnicq{d7pLt=Ub0KZsem68;JhZA zVA}D?-tuLjfgBd3acz0fe6oFbj22V&8JK&7O^XOpI4$f-y6?e`pG@k&P8-3Rw!si2 z)gZCQd8@$KiG6vJO~Wj{HW6zK&H{B#>|LFf)^e-J41NmoP!y3v{^)*XzIhsv$zWw5 zPNL~I4%-T*Yn4kQ^EdVqsslZiEHxXkvaW3wkl_rKB(cjsQotuc;hL5)s_Ea^zh&^D zxx182xZVa^GP~863OrFM5x4{)j^5-UeyyVTvN{lF)XmsA%afMk+9fpsB&tz2 zZV{NsfTLEz&b5RGjaAYQI%twPw)HfBtBGM2YnYVCgHZ4V$gX zZ$ppU>GS|A@QUAY>(5wy^!moKZS#zb{+wGi8$&a^gq*rP-QRW;O(h!M11xHTgAzLV z$(^jo=a=A5WhpS#A0_C*Uw{U*!}&>23+X-u?Y7R9Gk`@7#{AISvK8xb0;k}<3(YVYgh6QWJ|vL^6( zH+w*>=ZMzyubiu)@rvW8+SJt|<69LSxPqGmS-4deN6B^Wi20t$ovPywRJ4GOoYJGe zut1a;tasV{=m_>+$AVKxsZ@Rq^n*D%Oo+3%9%ri|XM50(O|fYP8RjP-1<)@3QQSiu z(Ax8nOwn#PYcO2Pe5wL?Wo19`f0eVZNLv&~(;j&8==FB9HKX0IA$90~^27>KOE2V2 z->Wd(Rp~8xHn;~R0rQ8@pIk!(_a#1INU#4+gHk+Ke?+Le97|G7K6)}~U)LzG&hfaK zz(C++cAZmYyXQ}E5N2%XHte*=j{-3$z=_-~7fNtpbO?KzxB>tnLh?bmfH=^$EZ6;N z6-{7jNXTZHi*hrztg6@|G2TqPNrSG4nx=KZ2b;2!eg`lH-<7(JoGxO_CjQcsv}hdq zvX%y{c1=sDCLogOIGuowD`mdcs!SWQEmv{50@wd7LLo9nc?HtBz+HmL_2QN6>WfR6 zYU{7CjXmcNS$Ai-oC!>qhR31kHdv^^U~w2sMElsU2Y+H0@9 z&p9ia=dI`Tl~c{Gv=U!f*`H@4$4CMI^KLENH3oM?ex_woawP6Njyf`C#@F1Cx5_rAP(1ezDQ=Q8*z{ z)#=cw<|0gqvxau7c-3Uvk5OuAQYJjbS)%r4PC!A8puk`|^+URhf#HukLO1AR_Q-1p z(xlnQ#Cwz(^fev&D;D-6N@#6ee_5bI3$(M=r0G=c^edCTj1gH34$m|P7IkAwo0aX! zYOj3VT{Qy_77iq?m;(*@>Hs(K=sRS(e3wnWX`-w{wGVxm4Z|pGdIIljQF$ZJHN_C)0^@jQTl;`o+N-2nsQB8^ZqSS3YVG3&s7TUVcNa62)TEY z#p;wY$P+SWz33$`9ot;msE@2tB{uiKy}BB|VU+72g8lD44~{y}j_jv&dd017Ps&#B zcs976Z3dmCneSztPJnq&y#GUxz}~vG9`7Z@U9*8eGs3M$zWoZhZPa?5d987Zv?%3EQ7r&m2)( z8+3M(sdbc;SGXI;c{qx)?bYn{c*Oa<;Ay9~XBfB}$$sLkU}wYlc_vfLyz92RRCJ$+ zWycl9S)1#%Er0JnzUMt4#t3=OI|dw*kLHyYq8GHA#Q^>C$?{B2L> zfj4n>9q0UW_8ha|wX$UdwfdqRF%8PcJ|`9E*|?2v68cS}(arutR^X_{zpEI8jdw9^ zWly-f$Xp%PU2(>bj+`eg6AtZA2Oy9Mm)yd;J-+vHetn6jXLLMiRx>y5>Wb|u1&Zr@ zskLk4uFu|*(b==##6Hm5a ziQ7=+V2$s_OgI_zZrDFD6J!GI-h`U+Kkpu^TT7|z_Ka3-zf(@p)eK9YN2;gOGVH~C z2JidjOdZv7e}Ly7HIM6aq~uMh07_Mr_Y9W#|!8S3;4!wiljBx8JMAI%V{i;kGfo*|GGAs|DF53bjYd{TFwZ& zOm;D^vv|-Q1QeU~4@KQ)huT`%OkEW1<}5YgE;BTm6c@Cvv~u~{WSO9Op*HXiBwuhg z86Utz{&h2ls0TDepvR_vU+@6a^DXd}JngBMAs095moqIT+^B!Y4XULm=tqXBa0CmN zCR?aefddJRzI-=*J_l1vFkHz|miv`y@~zS0MeIcRtbX|8L@7VFV()2MNlY{)=5d); z3}jXgRc2F@6i+@*+f~fDOmQG^<*_$e(xZ+n_DYHm3J!llmv)1H>U-u03))4{ipHJr!MO0^-_Ma{EY83 z0rcYd1DsE;V%S${#~g&fhS3*MWs1o!q^1%ZOX!Fur`%!9kqn>b$k!@%6xK|LL?6gx zsD0&!ui{cTJ-D+x7ELwL^2pa!X_!5?Bt?iwo&I~Y2Sb(*^&z81Jw2A{KydG9 z7p;|(c$o|-G5RXt)j<Xpmj3q2}u2#F(wh?;T~ep4QAJ1A88y7^N40XukYpyz zuWuwmh}|n3ET!cU5PdMO%WknSSkS#7m&rJAKFjJMh!qNdG#IyOj$6N6Z$ixD&{x9g zAB|$5b&XF3Tu%!xNBSkP%COEp%QVjlH#ENnf12HuANbo00%x2g{qo@vYNTns<+S}& zXiB9el08q-+av=)^>=#E@+QySPN|gsOlE_i-Vg8ysgL@oLn&54Q&fR-k9@OdCtuH| zn+4h`hS}XEtwpy-6}6l;du_qV8kwgcNntw2Vj=>NrH=N8XF(AnE8D>kee%7Kx?=k= zE!S#%!ZvV*K{<;EE;{E5hMh4woiXa6b%RV(hp37HY4uA78NM846s%tsfUBe*`#r-M zY5pvOPsyQVWognLQQH@jI$Hu)wCGV^gT0lB>j9nUo!1vi*jwe1^pRY?JzN%pz+5>y zZ=#7?-b?X~p14go4D8C#2R9kYQy$ySG`oQg#pcb|EKs11mF4`E6GDE=CnEDUovzEB z^>*`#s<$EfXfAdEI)?yLyCW@l{ktK@4KxJsz`W0&$36&`64-x`NSq$9P#unZZ}hoH z+jFKb9-m9nB04A~FS(gfCR$SthZ=3b{8aDTGgu~GybB&?Evv=53m*Hr=N?S^7UA>q?hOB=RX*@%Mc!&?Z(%7 z6=|NlAD{JRT}9r4e7OKy6Sw_izKi5B`c9?eLxi2#X0DbX_wM9`Vv}o*+G_5Bul@SR?EzpxO1eC8 zkJ`Z_0(sjLb9c46*WA;lMzLfCx2RL3NXE>Q@a^O+Uafe8=I5yZ#=6o-B z0vioaF2j%58%!B%MFWj<_v}c!KZeofx*L^QZ3+KS!FqsTy@yW!302Gbic&#<@pfI4 zb@T%4dIFH67{PxI$^foS5M!dDS>+-I;Hj1%C%YhZ)Jf|G9cAvG2k3K&#!aq$kRT{| zwVa90*3-=qFZ=5XxP7N#_v3|qiighh_gGoJ52h-HmmA%23I(Na8hXz{P(!*6dW!!VlIOigcaeGYYv(;E z>vi+g>pktePNQmn4C)V71LOQ`it-=ys4{J}_ zY8h*?vSW-4O6eMM47WeJA=QpbQj7O)pou45`QVAJ?oQtd7qodAO%+I2`;NzPPu*@m z<~*GewU5d?|DieR#{r{^%C&<2vn^MKOYzTo*-<#x(R;52USlmkj5tv*=fy*RmA+w%t-!N9&U zO1uy;0labW=7wNvQ0!g|CV@!Ju)us3oQtlIA<{5s|jc1B=`f1XH&%zG!0GHsJ1$2A-*sKdw`~8sS3kr#sHJwlX5i-z1+~SkNW{ z;@izAF^T~*V;fxacaZup)N&wJ0AF4(hoh< z!zvzGBLwxn??XS}m(zUwfIc8)_|SV61!N_QdZghd$lFrP9R__aq@t=(6F%&QYiH%K zX6_$+oQb`@REOZL6vt7n3}&3#dDqH7#6uWmFzwfykLpe-9pn)?l)@iA`*`_YejgZd zRjBCc*JMji($GORS}VBGw_%FTSo?Sq<>k21kK65b9gg=rH4U6rt^MK)-;6y5drv_) zzalVWkB_k-Xljg3-{6|;Pe*k#BEnlY@EH-ueRet4{3FO?_@l%EKGk<(%kY0gM2lYOca^qORa*VM~PpnA@l znJH@XK?UYv>Z*T6Bur!|~@< zr8mE&7TZ#zIaXGy`sC_5t7ps`TCLv;kCb=2l{0Bsfl37^_>y%D6nrjU8eHUr=cGW; z{`8@(p!c}zsoeh=#z^1nGReL<(5~;N%{ZT_@j0C&;=i1k*?9ust4*f$@GZQb`rh%{ z{!4!q9ehX2xRw<75!=j46C6uZ8}69eaf;v9E-3GInt_b3M0zEgaT8H{?lAQY2rn3~ z&L92s?ity}fEM&uc=oU~rRzQod_-Qtd!db`>q8!fR?F|OHLEnaWae0ZVRY)SmB2rx zJu_V#i?Di|v>*ZedjHD(&9uTJ$0_&-I9=oR zHMpU0t|C>b@cOpmfT^oojl)PzOY8N4uW+Ekp0kNO?-~3U#?a}=++?f;xRhr9Li1Ve zf!4q+{*S^tvS@kk>R6~<<3a73^LYRzYFNtbm^RJ7&-X)iYAjD+;E5>3``@N(I%}wC zT9&^$M{OO0gu5)gND7(N$%Q!!8W6|IH7yX|Z)vBiuSFwTE$;Lc$5(qCb!W&0*I^{iYYp>>`D@vdJ06&s{-S?$- zjOrTM=*KtC)R=*9&diUZ*7K1K(!Skj??l@A(xWnYIhwLAMLj2eBM>TVFrORT_EsZ{ ztuhDn6#BVhYOjyEJC(tXYZH1$YsT9~9Cw8-zqR-#=359Gdipk)L0yH2`firw9ZFUD zzR#jBStRwQ8!3qj>Lyjb$wy$+DNg#r?obvF)+4z|;uR%>!xi(w{IcpAhX&^&%4`U+ zVw#nE;vDDq7uE`GsoE5j%GtIZtrE_hUbj3u49fgyw!gl^Jz686#m0;4dLuwg4rXp{ z0yCY%5W=dQX2``2C3AE@Nse7+uocCBtOt13RtH$CF8j^T>qO`Vf`Y>Lfgdm%PjA{u z!GasmnTFE>J#P_MD8THItu4fLlF7<4DP7&VY{Puin96~#*|)N&b-&s5x-{X;J2BxH zsJs`Y^EgwWzXAn!M@wCTmY)-*RA}9jcz6pTq%~^Wxw-My^_1`eI=jHjVgHPS-Yc>N z%}xAs(IsfBFE9v29PJ)CYAC^cDe*W8UUvHy+z{5pV!!e>yp5?jh7D=e`>Har@kYe% z;eDx;4SU(-IaY11G{-({L{bCy?JI~#Yen{OEa>}-Kt^=JS`0xhkBlt_Y-qt(%W0ao zVP4R&^uk~lzzYP|b>3%K-L~a;}AF@x0wm=>8Dj~*5)5#s5XKFAsz9-vWThfLb z10v2-4m7S6(AIxIh;FWkj8H(%=w{w$3P#VA`^mbH8j!&w3(HIXz$Au8&!!k47Rc0~ zf<@?Qtu52c=BWs?_nB4Br-FnoR~CJnByvEgF4XA=is>a?>vlJEi+5~R((Z}(yo1b0t;Goblor%p19t(U3Lxh zhFs2~72h+zwHK|*@|>fYb+|VAn_mjcotyd(Y^n^bw_Dk6K0#V_*;y)K=c!B6J9V%Y z%SALN*J?Kvz@5+U++7tB)U%-XYvBhS95}SO(;M;|U3j=`_{~ox5t)c?KW6CG!8guo zHgHRr?Zu52ZuGQyYX7`~4OYpcV5fSLo7jY$Kv=wSQ?b+~AsEGTnYEukxGkmg{c2c! zG|$cSqPGwHloZ3Af3eD?eR<*?eqqjJv3ucnw*{1sW(?J@A{sW?#1PE1B-5K-aMs%m zFfGjQ^U6o2a7YNZt&6(|UL4k-V;nZif}EkczjNt(Bk$PO67x`gBqtaIWdBsV)Zrpn zYM;wvb9@KCq9n=xQfX#~TM~Z&M_4^_>{j5}N4|Lm7OXtpSFY@PEkV);{5RYYDaUu| zCwb%+a#~;d6Ppdr#P`KpHU)JIkp=`xqDAo8veIHSH6|@iL9)48 z97VTFb8ohEtHT;1Z zeweV!5R!t1Ym)DljfAJ5ODVrCpeHz=`}#Vk38s>dd#T?vi9SdIFq-qq z12DG@+OdPeTv#aCu^kHSg7N@yWcH;ew!*v9O7}P1~XU)R3373o{-0B zS!R`ki-w_V`+s7aA9-aQ*i9{&sY4AH(7%5l!aT~n)?Eqe96XP}bFTD?H_(JMWn#e{ zB3tE=*dUTXZdw0hnhhbsDBF~eEpdqv547GW_2po~f{4Goeio3-yz#)gz+0BlSgfNU ztWO!6+h^@OZ)#cI*Vn~=mie)$91Kz8{(96uABQ;?3({s;X1EU3PElz^pnvZ<9=A0+ zIEXVtDFG0qBKNQ9O>`G0=5eDoe&{jMetd(}c^ywc8rx{^D~(o9**MZmZ~r0W_I8-I zRac()AlhMllSSo=?+XzayF z{Ic&H9b1Hu0imI5dp80b>X+r^gRI6gU6!s*`ZWszYz3bJ&}9DyFmM|Bzmz|P&A%+N ze})|h5S=giOH(m?@OBV`{2LWBLJ(5uMRawoCLnnqkeBPKN6b0pWt1t<-;@8o7M*(V zelkE`;=Mg1N5&Q(QZM=Tu`xPC?=)JoU&wRuLSaWY(`mh|*N;H{O7O>_?|$eNeg9C# zh7fsQ)S-vMUk+0W9uuHdqgF(|*j^Qu%$5xCMZYeZyk*?^Z2`Z)YdgnhZ(`NwGp#3- zNqU}?*$DVTMptmdy+FlEms@)DAW z)sT?T{zX{JH9e$xhgtPJ3$@?&xY*X8jPlQ~=*s1|=db@sbh>57S1P9?70 zGie{ms}4D|;=@N!n{XLF}{!X`fC;b9h4@-?O@#cL_;fm4+tX;ZU~A*XLe1w5 z=oZgH8+!vkpn=s)rH?=>S?CM%yEnBV&0PgEY%RVs!;5epO!l9nRsTo@PzN2eWygfd zFMLrR=5tJ7bnOTiRt^R3t_Y09s!2?RJQSTp%<*8xoHTqO|BcZIOdPL2ctSa;50Sjl1D}jSiF~EUGP9f)3ZK?bE=cJ^F0?GFiK`UpuLBR2uDgx- z4^`j6^6TcP4ZzW>bF)QSJJ&p|Kjs?{)dZ8iO9@hu2MlFzO(mWo&BoU zLrgUz1I!?(fo*Jjm@&3OTJ5#K(co$N7PX&c8p?lw0`x8xtY*DhMQeiY6*S% zrL<%gCn-2}zCVc^(m7Y~EJEwgy_Oh(4()WVmO67eEmWD^_zhM^TMH*ck^8U}#`A6y z!>lGw*vi^@!#b+h9rf8z{%re=Hm2nWg35&Bo~F-jNi-?|&;bgPtIMHlL840t<5c#$#1i6$3h` zAn%Q%m~lb@kWXJI8bT5O(JL=w_OUO?;GYQL4&$2;f0d0PqRmx{T&ipaw-dRUwn=Ap zE5m|=l;OVV%J*iiPbsM3>ILy^x%3(dJlYqLM=_K3Gd`=uoG?cuy2vv^Pupv6qJork z$J2g1eST;M*5Tt84{pt%AMjhK_S5N!;F-A2u~hT_8OZ$6Xmol2l4nu(Y6u7kQevabKOoRHn{-K z>|)|%;JSjy{e&43@{Ha`iQ$?Wt}&kPVH<2LXsuQTu?HKPE14 z@Nq-wykfv3vT9DF9t7!Z#_EIjg=zfT>p4Zw=Js9Y6^NV)j?a4&xOEqz z15g1MgDqY||6yGhBk)&R8W35X=1F_I@Gk((2v7jRP71?#c<8F;tzV z|7GsiHQTdEHG%S$^EtK#que9#&P)Z(E<@(?`AhRtWi`ju;Huj5-gNh12q2ut{wxx2tsk>|b**`60(1OEICq}+ zqR)=4e>RWiuDG zzew9KUEcAQ=G)O(!E%Oxz5}thqo=M1{5@a^DGf|~#*{FjYBk9*EsRgLB^g`7$d&O6 z+n_7i^jKe?S?^0`wzYyFFa5%dj!1O9dt$RfwJIr}tUPy#pC{$R`DV~cOJjJkZp0jG&y*>_(z2h$n8@r14aB0qCn@V<*eE?&?2a|JL!Fg+CfUSzoY9$ z+?0qQgf*bK1D^(mcZ`$*IE{_3a!dNALksbD#Ev&|oX=_&iECA9!+(66vvUH6xtZpt zp7%*21`NfljM1PYJ|(SPSM!J$40~`dV3>|)j{W8}jk8^UfU_7qVI(vu(4mB!J=q4W?jxTj?0%~?%oNzN;AL2m z_BG#vXQUrnxg5OU#B1#D1dMb6A^F(B2HVB~`by`#;weSe=oc(XqaOh`Ao4fk{LKw9 zS{B8>FR&{pQPQ@Z96w$>COA zo9Lhk`e`7iM{TLp-o}q<=3z^G=)lxOUK4BiX?TivRGCk=s^3G&mgOTsrvMHk?Vamc` zdXtG~zuy_>#SSTEzvbj}yUVqz-wIfXI(G-fmgylk0R>I0u7J8hI~?d^`EItY$M`{? z5~@A}c=mtpF@qc?1{_~oF!Kvrau>fe%o0i3Hit=cRVO@t=NY&)JI`kJ)z4U!5ycR< z6S%?SxB9-GTjc^$;O4L8#b#AJA^A_3%ePLP#5t367gaCs$g3z;&+7%?fj4gKzg+F| ztOK;o4RZ58ogx{(C15?U`r8DJ{x(6Jcs2R5G4=BT7HO2Ih5rt;tbh3}i0R?-ufdE(Rfgz;I~=#P990LJIZ-!kV6Y4ivhPn< z{50W>6h4nr`Bf&4E;LV?-qI|gQx!H)7cJl@`b;yjRaMHKtV=}nIg+zgSp`l4*z&@r zlg1@_VOV+uI­L_7i$>X-`4wgGmZNw|sJ7NWBO?r$s#WMaGQvANkrPkle_^09o%m)FpgOjp;6D-+R8E5#10FKMk@U~TUnrnC4=@0LLQj>(^CL2 zvbQY1k^9CBmU~|K_w`UBiT|!A_7DRZ!t5BwNR#3ZU7I)OE+XH^{2~S>< zBk@uJ+0-NOlU1G8c_Q8Mrk|K70R)Nk_ZL@z$xtdF4{u)sS8kUo5#T~}ivAoVV9h`q z5o(I^3X$>)t{;XrslW@TM^h9LzQm9cvk@0ip>4< zbs)KAp!owgDUd+Zl|$t6vx@8If)g z@^Wy>9WPW=YUoO3jzrh6p6M~zTO25M1w$9=Y+rH!z1+37l87RCw_V!I5A#eyK{VGT z5`-xNN>_TpkjM=3zX=y*^P^9EdSO0I$7$*50g?8!=GI93b_RDKabEj~I=~2y5cL2m zaX3WZx{VURgNse%?&tD)yl|1kmU`3fXNC><;_J@IPZ-7c#&FdYfTQ(mQ=rG1m7vUUX!Lvu{kj=}x*LSDZ3 zD}C5TJzj(0dezJ#PXF#)d#&pYsDv6UwUyHv(7aPjNl32LKNR4VR**t46_&?Kp}C3v zzA~fsDbT6@?C7Wcxx)1Qo4l#lx>*t}8OvsR@+=nFKyD(G+vx4$rs*1(i+f(cT(uMB{R7~*IdSnf>TmGPV=}>37hdJM%o7VQ0`JC&KUMp*PBArO ziNoicTnY2a0PC0u2$O)kkZ-bBT)3cMI z+B>TRgU-8M76aLdkXYJ{bBW+Y4swP0=2t*7bOO!zIIpecVH z7(Xf5h*vZHNA&#jrI4QfZ@0n`&Cu&&5cP*)E{3%xSn6ZTI%H4+*N7ty*(KPCfAMBw zCAuU#1;RKz8Q2CKp%;hWOA#id_3evnqHIe6&hzV>)L_n|z@(>svc(M6q0#cR$`ZJf z=tA`0vdyYQ{*OsR-^E5tZUT?4btpm%Z*1b9{n{MAS^tiIyT!=y(2)p1JCE{BLF%wt zl|E^vWeou-E$JCzcCdl)_Ne$P@+6?Yq*~y&mH5- zi@{)F&84BAk*T1I_WyUI9a6CC=HfMY?{%|q`;RK%!F1{Z`F4k#PwDNIKyeVF)MXjI zN&sFus;e-{%jwio2~6&C?M;=#{zjQnvWrtD-m=sTEa_~~@TN%V_BOmf1(x9NnVBwGIu3n-4 znPn&=fwm{UsT*&zJcova@}4+i+L*a~>-&w6-{b!p1Ys)uYAGf}A0ANlT`YfFA3;AD zdhYGoHLfLqEL7vy^`ne@zTjkYPXBEBfWm&EpnkPG+8>qzBAA=ci%%DDgamIKuuHs#ds=e?RMB zc8#ZzN33o>!+7~_Ak&KOldO5mgpW^}8(vn2&*ragj?WZco>>DKr8jKF<*eNd+jW2a z{O()8dQ^ui))V?S##i)}JBWA=uFLQr!>JRfwfh9@C-t>XC&ANB-QzC50+gJ0GqvQt zl=!xxbPYk$`sb6)V<#V&f;#qJXq(O7Qc*8#=Y_a79yHpDL;gd|R2I36?FQ*=!(n@4 zDYqriaanS1^^&ShtoVH?*;HBT*|a<0cj(N=TR1;E@b=83>~yG;aunns{speUi6_HV z!^xgbsPq16;vA?l#cVOR^TuV@IqVCmNPpsB#p%L`+Bvql*EF;oC1QU$)V;)TWxa#B znR(t>&_5`a&oZlnsIhB~c&&HG+K_MsWP??z7~$iUUQEyOmjq3tg{Sf7Gt=jV-A-{1 z(l^l^a;9|@Dm2h*TL5BTWIJhV4Z;@O`d-oKhF1K zJS)w09RsY&r09av9R~{=gLq9Z^~=GeLMj^0*C6oe#XQ|)<9jCT7icKaS;uOq5GA$k zsK&gTr@Q5Y0EYtX=aurBl{&*&i0>+g>YXgOmB%}N$29LMGcW2#FE=X6r}jW-#*Cz) zK?}vgm*|J}G{MCZT;jVUO@X&!`rDDf?{R_Oub0h=Jwy#R_yMNPzr+P1^=K~vZ0Iv- zKnNW7#RVmo1Qqxn3xB7A3P=QaDKdY4F!@Y z+0zs31te4g^jC!C@1SAc(NeH=MhG&SWc(_22O-xT$8$OCs~cHFmCwK?3laJfn>>zp z4_m2e?4iwVognVFMC7HmhHjOclKS*l7eiPYY$PJLKC#{8+9y6@7BC^r@7lfvp6d;= zw7;IW5t{LlEF7J$WYqrD4ZcMIK~U9f2LE^#%gb5YG& z<8&Bv#5_)1Ufv-N^cN?3{36O1|H7p9op1?_))7K6!VKVGkV!8Uaz=o>L)`#v!Q&=P zNkeg`v(CX!jndyhYy3a_8>-gfyKN?+b1nleFctl?MtVuN4__~JrFgqQ9XZ&EVd&=g z+YW1^g@IpwC3{?+pqx&Vx+S8H(KO?wGZ4UG>&dKcq96`%aL2Bl8a+aXH6bAcov+`w zy#KNwRIz;o0$UdWQ_WfGUzA4vKOP18NF@;*Amb(WA{L?ZJUwALy1nXc-)0wt59kXeqDxgNvKKqETN2a2mGT2sytZ09UJbuw1otV#Cij!(EN`!D zUSF<2P@I>L1Df@zhR;eDIegeyh8d(UFoZ9B7Cp=+2bItEmyTW6JT5Ts{x9T*{E4=o zj4FG9Wf^q=js94(a>a=nT##c6n+kS0Xm({R?UY~rf)3$0ITIvZQ@d>Xj4(zXB7d$x z$N0Ur(h$_O`(8Y53JQ#BPYr-WxMEkB8+aGz!|}^kzc)3pAaU&C!c|e(82_C9vxvf{ zQLE&@pvp_)Ri5Ha3aiNmK1OrPxk&6atqyxH`b&OOlE20Wk$>m`-KmK85|@uHmx9hH z5TrdoG(~vO@IT0`F_h<|AyWYo0$pbQZeQ(lpwVFQW!$;!_;uETbk)0Msk4HuR~l*c zi2oNpdX}QYf;YWaSL)^&J4Q@H@!T~s!e+IK{>6rV4$EanpeE*)XWvo=cYM@kV z7!u;R=T3}gaFeqGT1fuS#85@#i^_}2-&<>o;ya)>RN1R)AD+_1K=R!F3G8?qtH!w$ zA9peRd_rFs@HSqPJX-=N2vOXU#>$*aGT@{rIADAmbUJkRtI0!LQK^QiNM@?t5gRlO zMN@K1x62)x$3R;Ix^Bu)oD9%sf{b}$q*Iu2964oDt)1m>KvsPh#bmPF3dSckCBH$! z<}Z-gh^qv`9R0US!|(y?C)Y)&J)LKYx5GEO@kWq7B3~!NbFVFarue?L4iu4#O4}on zJdBMm(GH9rI7KGY_B@#hMjV#M8@F50Sfj)jK_dpD>9=2k^riphcHX&L%pARR^t!1e zTF2JmtCyNWw}TyCGChOJSNDDikh-j;D0wiEpBMe!Sx{yDk8D;W#DH!~BvZ&$DTMiPS{_+6eJw%?DqX&rM9u+3B)9V$%4Y@cp{U^3Q^19*~X6HxRp zpKsk@+yLI=#EPkd?>TUk$_LB5*VFhO&Iq)u_ud_j$I}HQ1AA{HV_8v?Scno zP&mk3bOT&$ zu(y5hla$)2&P+YslP5*(BQ9UE)UT_q^H@LD7|4ceTYp|BoU`ONnp2b47SdHhdg2C& zlZcNT-#X&P5ACFdgvRHs?r5vXOX?_crctAf=SZiUMh{;*M&q`u^edOXDFJn1^8`0w|xxjZgQJn z>U0r2naizF!^N^{pwl9$4~@SMK$ula7ZcbW#hOmOdGC<%eNVohmbrViUBxChmpG)U z&@!(ly;+QHTRJL&6E_Y%r>j`a2*^&7Y{dpSEjfq{u~_Bww%uJEI;^?2RA}Qb1cq+Z zZ?H>i*fGO|D5}opNVIn2r6z@k;I6!K-;m+n6cId8|leZtIWA91? z;JgU#vZK}&zqixtzwLBu#&?%y(Y_8_ziKV10;FMZHDZLEl_)Gfyq^1@a2&7ZaCtqV z0Zn6nNeg#%;R_{L|AheJcl-;=m8p9;9Cv%mhd!WZvYOqdHY5w1ySW~XMyglU*FoUG zg1xu3_N85y#P4hXoLs{tuIm>E%p1~(cDsAMK@JckjV$GT(x67o0zUa zcwm&DH7R*bVa0R%)D%nqSaSy>{^)~1=IUPWpQQG2VmSCfY# zuf(KYPjme-x|=}7X$hV;k;d81Mw#pg5>z-r$p53IfuGz&GSz0SHE!tY(4;nR8Prg? zfH!0qyfIKheM3s;@nYRcRpH@CQ#xv>w8CGKYd@!?Dhh;uSgf?kjS2ra&{4`b{42>q zl{1YBjV?;OINKolmf_OJs@Wf|@m=gq*|@&?&y_?+!Y;wU{g_)5moYL`W)fT`zQBpg zRYqgSK;v@Wg9;jPdC)Y2DsnTG9nsYDYT9a`RDM9jA-A!=G#VgpBsSt3ca0!Sur(>2 zaS~1^Dm=`E2C9xCMR-BQ2m}<;itRZUq4INd@M8Z2bPwX zm9I~0zYKE?IY;kuNDL(k&A#f-@8ld1{uv*5V$`&s+w)h^`(lL9rmlYUXedXFZdZ?9vorxYE4Ot4Aopcl z7B6@!XO5FbqWd@z^p(gjP##WBhQ>83JoG|sbsR3trU^>$%d1wum}>I1=*f` zro^4tnpeNY=sYHiXQ5$)VFvwS@A6v^(v@9{j43dIE9RFk%d1r| zT0iUkDLR_^o=ST$6xkWY*4shj>-OWAG}quR(n>1d!m8A#Zm^+Y>Ei=J(7LhhbUp7r zSWxxS)n_+wx)*=U)P;rBZs)P{Iwwn~M_huq%l5GJ00B z@3wK(wKV>;vrTV!2?W(c?L)s+dDus?-j{PacZP=PO0509xKDR9T_?kE+ID)i%mCQ8 z9&_$Zv`lt>>z;;(myy!4WglBPJH5l|*VYUMAu4Ue^JsD%>g^RSX@ z&|b;P2ZkK8?B^EFNR^t_Wc^EZhmE$kTwtgzErsepadpjI{8!k>1Qw;#y6bq=q<&}3 zor~U|i;!OhYUuwgH8J0}t6(0-sv^Kpq?+$u=FNBYe&KSz@;uT-5g*GOCAQBCE=QvU znf-7a0x6i%fF-L?u$jfy~Ha>u7Ir|BaFPF|3)C}+QsSl6!5XsmY?DeEw8?WfYM)GYvWCx9Sau~A~x5{^J`lk6pn7{ zX&&D}bAMX8n)OjyEM($CQLlnpZ#g&h73hr(s&xRBMA~&SaC(7U>G$wKd)~hiMQtK{ zj0hbf_Hf`ZN$w&;(&ip3Y8~yDdXAs$+FqT4G*7&2y=<(W0UyUvz5cF!$J+(Bs5l^x zEyP%_{aq3ACldJT{8zzJB?_ql_JCzMyv83tKs=K=@lWY@;1%!fC1(toKQR$_@Y4D* z_gM6E6i&OQXB)_YQjYxw>-}YwgLPx0Yy<>Ov45KcWx%(%e8pz%YS z-#Ezo2M666Hu!A-tDqI_N;mwfQCMS&Vu`lnM}&VFynAONb2X?UX!6IvbSC5#e#P?L z%`Raf)EoO*A^%+=%K%W>#et-fJ?Ch06e9Pv8%osnD5~w<>D; zp`5-OcxBvFK<*_rAS>bH%&&!Ced`#*c-tE~8X7`r@Z0+DN^E?Yp8RO3XUp?|9Gw}P zM#k7%>GUT_y^+@5%En>m*gs$?`X5*_bFthX0nW@d{~#;?lQ-qQ?=>W!y86Bp=P46_ z8x*#4ovRF>`il4Zm05;%Y$k?Ft_zDTIjp%A;1>@4EDKxys?`}5QSk0+Pg`}c^R0DT zTMtO8=cgq??=@@OlN2GDxos5&&ov(wFWnfDpwLU>`4Oc}=+O7Z7A?s^>F&=#-t1{> zg1M%>k8aGows~{x1Lq>z?bx$7k<1B#aGFp}S>~&jTEt_U<;(SZk%9jNP0-E#Plkab z35*~3MaT17?(I&zde54&6AdtM1t>aSlLjiJSG zWS4}rg&__Zx%}ihIXr?Fiv?4(wIn05Ux6fJ;YSnzqGWzH`p4)KBi|0!FLijGDHRmFV3jA$R#maj0-r_z*4NdzY;R8-)lrrNkzc1%yM{Wt~>JutJE zj_*xw+;!c)H7T<0tngpp*ZeaFXhrsygBJF8N&h1gv<{9(zHW@P;Icl7^NLchU#5o! z^;~XJjAiU6t43z9)$cALjTZh6NY;(7CPbK+OqlEZyK5uNO! zT2&uxFD~q?Es_D_tLoq1+c}+=dgmPAT{s$0)guCC^C-9G&}33HQjp(iDd*Sk{Fv!a zCC{t=^20pHn!gn7N^p3=?JH;#*NL8{hoBn?;+299)DA~YB9~Q-QrNUxj^i$qw^cVD z%DAc<#>fSLf|t5SusQ++NXfSi!*o+mO`}VPjE5!P>VNDH;Fmq-SW9r(;6u9Q2cLrE zT~^{Peg9=^ONZRH2vb_Im_ksVTiq~`=kGN`hk|=6wJv3;IWL{*7M2f%Un+}=J@H$( zOoWxMpj{zO5n0; zEl4hK^p@AtLMZnvoL6`gqZ8g}TZjiDOQIn^FKL#;Tt)py?rn>bj_IzK*4aPVEiD8_ zL(p4e)Lz%DjGj!kA$T8r6rjAK9D4_pV9R8qWy!9ib4PXFn={oYcQKAj<8>21_#~4x zi3Yui-uH83jN(7&Yv=G(y|FX8_+#ydjlfXwrHeVZZe)u4dqX%w&ikZz0|NV=lMylT zX^p6&pI8m{v+k+lK4YLX^Ljg z-u(m`Oy$^e)3ArL0tWHYVkVMnX`ptdAnw_9O;iq*`eKGmROE1P8&U%k^PfAr^Xckv z$@?^l17Gj@o#8A~nE_tcNi-sF3OtGtQ);x@uBvnAeSv2$_CXaB=a&`_;|0Ux`AE#o(eBgGr5r{!Ag!7|y0z~F6fH!$>P^`3a9aMZSa!_J#^V5J_obls*O-7J}+Wqug zAK8C|^+h_-RLvR29o^p^2%5;9g)9&>iQ=|DE zJy~QYdDk2I1BvWfHdG6>iAmj)d8mYn=GabYhNEBm0exz^wi zASB%DE7{n}6&PUCDcVe*eqH&VHShdN)%dYx%>Jl#hJ2*Lyvv^b{@8fXT5N{GbL7@9 zN5S>&%46pQ3ScVWb2|XN;_mm@-@O38e-#x^bEbN>HGQrwuoX`csgPDJLw>xmR3Y19 zLNg|VueQM-t0g3*2R zj2c?^FekL_I=qtepiWBx%{!QFtSK;2SbMkW{vG++;&p{@$DnOUyTiPj@%A^kgaIG< zH>$TPp}3tqMgihCxM)irJM`Ic-Ma$r`~6zk$QYz_1(i90PXIVtbX`y8cg4AlOqP@+ z0OiBbOBwu*bxjQyC&jax^IefQ=P|BA)dywXb_M(Cj5!t44EufoM;`f@9oNA>|Mb%T zB~yZ^(^%^}{JCf8k~xLV@dT=cL<8^g?*BiozB`c0w}1F#ln_FcnH92S&yaDr}gB9 za4A}QLZ~|{!2=dB?%p&LVJ9PyFXA#L#xfMp>DMl)o?5eCbk1BqDp>tI?gxyEg$1lyaA2sj8qt3qvUrphy z4yETkw;@UvK3yi>aXuWq+}QS83K>HuCK|jtPxJsOJg~Z1B#4=L)8YN<8!JNlhu%M5 zL2f;feE9kVPGU^m)?{aUJnGM7XPlz{$Z zeH0+VLi}a>LnYGbbRLDEY8h`>_u+Qv?4?;c$lv$M3k|00qet@|B&3frghC!fmvp6Y{PLr5g_dXNVUCQf z+2Nm|NVodlr=4_#JB_(J#6(IVO{}`V=cHiluhYz*@r;neP2%*>G|T<+*2NuXLLR@8 zpobIP6nFIpXz&C{;!b-e`BI%?cf_4T77a;Gm2mt!Wo-|) zaqg6R=j~_@ITgSy#Na?eb^R*&2UqSyfep5e78^gI0ZA-V%Xu!?-t$7dF6$ew9G}va zPW?e~dxw(jup6MBrRaw^{FTHfj~}9LitCz~)hv3(peiMpilFmIW%QrrvfgqEv96P? zrzvmcy+_aZC21`!SF@jp_(@N`*x`xon|E&EKIIiBX`&3`K=g*}2Zy;1Ta-$j_F0s$ zs%gA^$F@Fh46p)!+^{gz1Sje>FYt{)#tUVDvl?{tX7RejSRNNTR+GMtYy%gFhCd-k z{@ZKEdL{tmzd;JFOMoCrepPzaDVL*(bS3=H@Iiempx z4fxP{8JerydRgqE^9mKx<|6Pj3--HEF+iYhV5&O(-2}t`fjJYfk*`FuGgASH!~Tn- zO;4`>#pA1$qCLshV}g@jFWEDBstM4T7vG7a$f3V*i~;!*Z+*<5Rq46#j~~ zB}ZneA&aqCFg`)}(04TQTRe#>x9JCm*+fidn!X7Xw2{%}eeZB?*RZ1g9F|1Q`eeVB zaY1Y`{|9Dw0LxtwgRgLz z>|enRlZu7z?zIE+fp(*Y(NX)EeDB=l@(%7b;(%^anEyZSr{1jc&|N@FAXrI5V9rBtPC?8y&r*(jHPEwdYf0L}pBK_;fv=Td6fwzXg zrOXJ&(73`;8mG?SYl-mS<)5;`(8V|oKz%3egpS{*owMli(^s5*W$_7o3RVV&JvFG_ zBJ?}*#(?W&v2GZ|d;?pZ({%Xe;4{maU(aVVI2rdfz+Fax38EKIY=zMf|1E$5_ozDIXRxJ<3d$}(BxDu-@GSDbzN0%}b=^1o)`Jm?(i$WwQVG5^FvUvTzwbMO-X>9$r*DpZb2I>1ZSYy*T zGl()CbmkboDEU$wAr@`&okyR4rlQb*N{l0claFpp;V70`{^TjZp)H>ShNwRN%f`$E zKgV&m{xYARC6%Yg#;*`i1D<~XamIgf?E9kEr(iluWrMF^$~jI6$&V0euI7S^Vdd?H|?-A z38q^)VLc(k--Y(k4OaIbkLiRJ`EKtsE+oC_?vE$a)^)@dL3a0j$FEo?i#y?+zFj>U zDi0zk{CT^cVOKR9(8uUip1Nx!hDYDTlGa%ZyGGyb9Vw;F{lYPB0omHvvOgk#M5Tv@Tb;eI+hOQ~mr$8t6ZSZOpn~y<8OD!1{!E zBbG6#PN$Dj5`2|=^+cCCZ}6qi8*q>+$QhL^+`e(xH_H9?2BdWU z_OeR^sEYr!MWTth+kBb4$Ro~V@#O%74zkIU8Tt~ijJbPy`_c>fY0*`5 z*e*#&#SS+}t7lqhtCpj64;HcXDtA12>3-2vs6R&yjBrEV2$(;cJ2CY5zOPT$dfq~w zaP?CX`!0gFf`Rop(eA1TQESopIxhwS`D`9RfdX;rxqlN>3b6kfH_S`V5sbIfyXu`I zd{!)Q%%Vq|={;}mA)5c@8p#bpt;(zg9tNG{?D0GdLKS;(&-Ee0w_YtFGhOEct9QOk zZ&41N>*&K`@CjZ*gD&@*5 zVbW+}cEH>9wN0}1HyTvg?r_Q#o&Z4y582&aN>c9b)kGkU#Xz`t6A(h)A<%| zeC6Jvq`VV?^>}2h{BS$-QEEHL4I<)OMVL4YA|3Y7oQm`YC!BeD)iQrj=hRf{&A&xo z$4FRL>Nq~P9L@oK@Wd^113lDRhem&F?t%YHH2MAp8^bKKB4HH=lD`Cqz{yGGNnO)v z7fa$%%W~eH7xsmfrq4NBAVSgs`v~}t+JWCVJQf|U2!MGn&GKf7$-0wJtL)NrPG*eX z!3z0X7T;}(i~#zgu#J`tpbu#`BwqtPy^+|)i4wK*UFOH3bQSk(tPNG~Mx#9Hxumoj z_qr8>;+o_8`T4hMjrC^pfni?sWPiEU*-#@%9ix(HM$#v0*$=E*-P1?*UjLlD=sXG% zoOHN=OGZ0p0LEi5RPnG)lvR8zW}WR&V0Y>z$NI0_d#HjjnwST--k55}F-P4}E5Zsf zP~^1|z$;_w*-b%7_g$#*^e7`Oc{{jC7Y`j^JltnAWkd$eZ+cf-xjf#SSD#Nz=~1~& zpP+jT%jhwrw@17JTm%e%pZezpw0mD9XHPD2*+^XiX3{BXmt2m7_nukhQQy7(4uph2 zLFXxY+oi@X2S3Kp!tsyWaH?_`?`x{p-9HNiR`-Xln$Nq$$n&bV-<Wl0MxyglmG`e8)kj-2^UARMXS!8YccAQdV!h zb3F#?E9QJEqtg>yvN~xhod~wpmIlvYVjQFF;bjB7wJdYHYgJ*uf+PH^=pCrpC4N6O zG$8_BQ^lq2ldTMrH%jjB``-bQsHd~5srR-+NDn-h2xA0aJc8iX+mf{VV_`)Kgd5(3-Vr$!L*t~Q$h!?5k<2XcMITdeN;F+N&g#t+_Vy-MAr#$M5YTn{>>`5(Idk@uXh-*ZFQ12<3yt*`9bp`CzeJM3~qI+dgR$2#xFn%BJCT$%bMnepurA8~HxGeZ}@X^MI1ilNNp zoz8l$$kkn*H%MvfgP9p2(w6>VVGng*<0cLqFxi>v&f`DR(rV^-qvgww$sfnVDO37O ziedTLvdyrmIs6q5ZC8L#68`slP{~3`lJUHZ=w?=|+8_se^d1TZK8CPd=7rpHEQs0o zvbZa)?@#f)O7$5gmeZE;-Ux-(bo<|DSx)s2m1nH4h0Fh_`i}2kzYt~v9K$*TT7cbO zyqo@DIK3c5K6}!dD15%u8Yg)*@78yUMgkHV+dgdV5+XvReFRP{R!;I(aBvXx`8 zW1msja=sl45XXu2SJLI!CJJ`gLrZ^6EZrUto9FAfJP2^kkj9y~tcfXAev9!Tl6LFa zDzdCwPM!ESESs#{k#53S&TSW}#xi>Uv zsHk6!u&+Ua2VN|Pkzp}Myd0fa?SfKxLtI!-w1(@ILKN#)KX^Z1)`bnw6(jre?){~U zO}|V(4y3y^>tq}S5)NSKImY}wM;i3a{HWhjq6L;YDbpj!ij6^z20(HW9@T^tXt$Bn z)w;}H^wBww2uZa1oR88rk4I)*sx3|US{A6U1A$Bx9zBDOaBLrWZeDR1$56|sb6UG& zI(P`YwM~3z9}+qKfY|AxCC`#V|hz3|R}JH|REbdL(#Jw(${Pr`>C3J;~RG4ZnNjd zhKHD4o`&1vHd{?k#T5_kz>fH`V9-g@<;M+Q_&(&Q6fz2$YsJR!<>W-fG|2GsEh0r8 zUKGZ!t_1?M83^U{d2*cVH3G_q%q&I5-pKwZN26r|fR%VRc{XYKZrYSZuQty&F4xbU z`0RyGwFdixWq@IS=bvM{33K|z0!ddRbKAALU(*??t|iRa{E$Olfb_NEkF$)Ov|LA=JN&sqDXC6;&`L3eAzal$yxSkn0 z@92^6-lF`O$4p?AT6KszI4dkY28kF(;v=w7mb$|vrS;DDG3@v{{I2h_<4ZD!n~gtO z%$Z}GfkrP&aG#&#tg}!yL6lpE zFuwVa$;0`p#-QDTv;IjXjZ!tJF>zqpT3RUSdh%%oyAvC!qV&`z!(8@a^vDLMmaDYt zs8HW=`_nkak-$Ws_D0~lQ^IE=JoWcGbXPA{Y^;C0En=@<%oRE4$vhWiej72TenIvA zD*Q19e4NI4G^z-IbBMmr+}yEU(=;dfdIRm1En5>KWH9N}%mU`*D;Q2+B2!UIbfsg` zf4(j{G}H|rsq6U+0%NuiN`@R6WoGhu8aqE^f0NknX#CYRE;K$1nECZbvydDdP2@yw z^ZsBrZ;s3esY_U`_s91aZ1GFGQ*YP^-EV%`=rqQEb+k8sHcM9^?~`s2)wT=&*hf5j zA#<&6@=&(a`6Kc+A^dt#YwWU*FVHPHw7K-245hpQB0!l`qRG=+quDY&R+GFv<{u`$ zR|sqBS8g$9w!(=X3n@UEONCwUlje6+aS=@?Rp~GCE-U?*BN1_lWoj{u48_mSXIC623p(cN5U=VJ6Ykk+Zdr=RiH7OOQksXNZa^$zlnd0B@yNaEPKP@ZTaG&Hnq)E# z(stgO3!QoF4X&P>UsK?B5RTb(cvK%%=GE`w4{cr%V8T&klFWXs0A6 zlbo)f7vN^O)$$MPsL!LRADHt;`uMt3>X;KFZjCGm?22X}m&>Q_dUW5~ysS~CPS-i; zNvB(yL{l*iu}Cf6*J>MDAtmmT&G%yjJdxxj>qks0)=j6hB@zrQX#t{q`64nXNARl0 z$i|_Ee0iQ|a_5UKg!p0bI{)xAaacrP%uK2k4kzjffE14 z9HCGHGY8~9WRXpz6$K~3GDP+ArVxXgI!q?@A!w6XpUJG93)yt=ZObUEofw^U($l!9I@}>Fwc-r?;N6FxUMv@EnCt9JFyT*dKK&r8 zg$et`6C9BKW!F>P)*W4h@$Iff5>Lq~b-)G5QS2_y77LT&>x#BeCFM7P%~4dQW6*Kw zaXnw@$xtLc$)wD2*UA=I^ocT0CjFAN#zMc2^0}?&uixm(R0$0C5m~j|eBtIfT@x(1chl8>Nn&>gG8yu6@)0jI}OT;heaBECETucS4v!7 zBH*(b-_g~5?eQTNh#f`&sLvDc*HJFicef;aPY+D#c1MZ}x@rtB|6mL;?1nEYI^XZu~zIa$RqmbPO zzX)fd@n9>CynzoA5+IECZN0C(zy|F)bk#*<*g~G4%XArQ8<#Dwq%!utt?yQwt3;Vg z+u6%zIGi2fkooH(Y(_%#rCv+>`c#;R1L86GPsU&+&03{ny>ZyiYZ!ZVbI-Z&W<8|* zb`B>6M5DK!r^`ihwKTC+NpG*)EkxkL<5l}P;ss9qM5JaL=CS}v0OlCmOd>F6qnwaW zb3=N=EHKFlnt;85gc;K&qL@>4F&3dv6nR3{bB-F@WtE>|_p=FZFov^ck3$#|nPB^P zQt@dPhS|Q0wK#EqwmqFy&4F)rST=th#k>GUt#V?#vd*|p`lZrS^ohuU?l^=iknthG z^)f)0SeY(YZJyniEHQb@rfb*?!n*Gi@P@ z4LMFQZD0?{bZ?v>I2%HsLbVZL>GtYDPXC5dC!%o;r{o{%RTRSE#g}-f`vK z;Vf8plu0dC)CopbC3jjpsIooj)5W5M#gbC+PFKx|a|0rsiS3RM!X zCf`_`=VG}^&y4GfYO6c8vf7GYsP0Dn4T%vTx9&_Q`a;>+mOyJc=KB1gSs8H5% z4s*PVKz_`QN)5A1K!yt@;DC$98P!m-QfdEt4rj&s$fSS@111A6}>Vr7n(9i-$ndwU081v%>iMjUjE1&AJ%O5G18DxT3_B)elR zW6D;Ba6F)P1y@~fa{jrEp3wno`}Hpn5}g0E8y3t{azObwab#=PZjx4gM(A-pN!;!ML-RFV&UY@PAijgZ z^7^TNw|xR-?CXAML26V3JH*AWoZMEk5rw!)eyDsHw6a^$vh6P6F!SrL+lZw{|BN|w z!^~ZDCaOtzd2RNFnWUSl-K=$OCSTE*Aw_ap+4AE5YKtoXfS2rI}4{p+Kg zw>Qbt1Ts@pHTvzW+F}TLYybc#&O})4~Q5-pMAmKbx(Uv6qKVxo@mq1f?t+i<5Dje!k9oU z2lu{khG}-JHr`p4+yaD0T?%Q6rKx)Wp@WpSS>2-iv$N}uB<%l4x&2R|r~RVojWs1@}c9tGw(-`2-PU%$)52VtUsdKK2DHS49Gzyj| z{#+^W!Ay7Xqy18`ny*i>yo6PnmFC+6J>U*Y$tuB?GUj@95g&+OzSTs@A~8l32)3$W zFrD`A##tr*xmSaD>8c8ha!EA?u8kLTFpDA58(vFZxG|r+jrSiLxQUv3=CTsQzYBY> z8Sj0u^NumdpP$9{R%y9v(I>dJj3uo4NGSROAol-IUT9%jq~Hv!J0YA?i{&ow%zglCivr7Ax?2& zG_D}VMMGg;YDGsgiLoxj(0&9+ab zF5kMJp(F(&zRG`Y{C_vi^3P4%3z#D*K@MMk79|#_)dUW813S#-S| z*mmn|1Cx7;Q82;N-_{tq;LRmL;m5)kYr@gXgspnkVS;?-zH(Ohd0pUKleYPoNe^O1 zdpdGO*E&}!m3nqhJyc6GH7gsIoOEPWeaIL|GxkCMn1Izn&&Zfztt`pao8D#-`S#)? zWqOHu6`z75o**RZu3 zLln@shwe=LGP}{;8{?&Wqr2-QDVD)zy=-~TTNM$*Mfq0D`TW=h5j`T2;RS2Ocl%m` z@(Cm|0_oq1>;=#fnbYq_y}q6KQRnSamnU$>6)hwOsER+MBrlEDtGxp@ZXdT&RKB7~aXTsNz?9)x0307<4Qd z0WxKs;P09PHgOZ9rk`9+9)t{Lcw&*3Wva(IiH%OCJu?dj1{h9 zaKGhNY1WLdkw0tcxzK^w*RXF$XI_l@r}xH_sp=;{v$Kjrmv)t}RcA)5;i=huC&z)K z7J2J1;~s%NXQA8NS-(isP zj}~xwU-cAF#)W3%aGD@9hKN2s-(I=PHs+&_V7ZnQa$TSD{s>+%G!q-^<+m z;DmlL53&0CynIzMj$U4=Opkp2v>43E1YU2SRQ#Ayv8%#i6ZlE;d>acqw=9?k5@>^5 z?$IyiMP%Ra=lmk&(r%(_VD33!*(z*+d_kpRXI%^C)rca`Oq^BLa|I97Hj>B;N zBQ#etCKMVR&X5#!@QRai&7NK+SgDo|xD|50ZvR5kryOawHO-4WIQE{?>~Oi4w8fdu z=6j%}C*9OnpD=BA6zU;3&RzwV%aR!NE>;~?72!}nzcIQ0@7=A@(3kz;7M(gN+c8MB4`gt;w$AGk;lDJxl zX%&rC24k^tb5OE|P=1G=Qf@(j}z`cVXX>w)qMp-vo9Nr zJu|kga?vVOD>M}$u%qH(pYD5u%hP#-qV!eq90a@kFJA}_GkI+hn6ghKRAlct7t3)G zu^xT$mg{}As>PS@Ni9Ohyxz5C3p4j|d)7n0;heJiVc@mQP>N}H>Iu$)dg!``bu>zC z41=KSWBo{Wf>FmOba&s{Ldd192Tn;61v{nP%4?iRM)dX(XB|uE;IFU#+Hv-!N}%!#QBp_jT>afZ)x5Q8`phs&`4UUz?Z@+9UZ0SQxJB; z(!emX$YZ*cJZHT}uSolJ%XiG?To$gAi7rUE7oX z9I6J+fBdqXyW3)b3A=6kSl;csN%eODR6b$$^qIZsc@9! zxpfN`w1}NszW0wy=zd~fbgHYRxZEXtteTMVgh_#r)Li99amm$o-yAHBc)!~uM^7nH z!6gB%S2mY5J@4<>T-)m}x5L)j1HvC1(}Kn}NQn;s(am){mbMvT4}00r7RFKDtCL(K zd+?@*()SyeUSsBK!vQ-#Xx%6lQ$ z&6y-vz5k;3!*Fpe7~k+{N{v{~C&}G- zNlhM7ebb>}9J@gAK5vxOelcB416?2`GUN2doP~b(YGg!g8|npdjBC*hmiNMwe&mFe z<=&N?3{~+c4*#NV3RRTs&^%9(=cg_1C3*`%TTP=cYLdqpUthy0R-rNOa!^~mF??@H zHcYmEvpTH75~o&&7X7ScXZQOe*Sh0lT>?rMwt7VuJ%(KNxu*BZYCG8IedSE)#ctOy znrIyTCv4#Qh|3NB6KxFK1U^fMx7nKHU9)N9u&Zwx8E5o3;b=>Sri zgi(iO%pqpW~pjDC6{wV5~6b7Oio&1$JiEpJrX?BY9b58^e^hU z3t!u<57_l_P-NNub<>vtv(DF&Jg&kcgQlP1D~%P$I26L4_O(vHHmq~&wA176D<#73 z_3vXP4e@Jo{IL~REW!sza)0%^*L%)BpbD_jP<`c+oL=fnqK@54L{4L|%xtYHW-8-7 zhfQ#jlH)0>D4lpvPdkTy0X-qlY-LV+->Q`9eN9N?`AWOdN{4~ftL@(LQxM+tzhQ9W zA09uXnIoVCag|p#Vdsa%KQ6AW%fpzU&q2?`C$J1>jCiIS2r2D|e?TnDImq3*_uyoO zyHy0|%z1G;b}u{jC}i51VHpEMIv!O46g~q+#5U_VqT-n)u+(=H3SX457i%W zNmvyPw2h1V!S@NlDapz9vxd39C9H@OS!&u=ntoA}17cKjtC|~l^5{a9_IBHdRL#d6 zI*~Sg^o*O9F-BJcwJw5DOKO%NUxi?Qo&p)FoG8@Y9 zvV2k0xP3m>6dr%TV^plFWd*NB7gTnBWHtXn;Jf>q<>iXE0K{Cg-?|9ZnvS@vM1pnK z-E`yoKdc25F#YTHo~SSW)?v$_1FTzK8U0h%CQqoGhw;{8k;{<}%=jxSK41~NWQfW5 zMOTJgnb~!$xOA ze#@FkLk7&o7H)knHa$jmx&h#*XPPUtjTd=-F_O0^M6?v38%`nNfm_CGIvN$$fR;BJ zk>jdP7gWbcMa##cYNSHuZpv5g5`vkzi}W>Vj&a;n?trRng+~u3`9);xiJ{Dy@4Ul| zX-;=<9TAlnIJnS#?wkgt{MZeKZ{0Z=Fpp99wOi4gLk#C?jhND zB-`iTkA>9NR#c6-XB>+w611#p89B3RPK88-mtM&%g#vlzwS(d}{SW-M+SCChx#GN~ zD>239fVbG+xlXmb-ZJ6`0jR6_*Il(axb*0Z;G-aLu_nhvT$%?lPmmx@P~^!qXQ8LM zGT{`2y`OEendQQ`iDe?o!8JEAh$ENehn)!m(bjJSP6Xq*WyTSvHz_QETnc2$e3SHR z>n@M;HG3Y7VlVNfBkafMjEWrW56w{mD^aWU(-ejDso3?+1QZ{uzn;8L(gL` z82G|aRtnaU2;3kAJ zdF9>01-kFw<}hz6PEZ-8d=5x>?9K_X@k-v&uBu5TQ+ z@9#<1JTGc#tw3=ag>`brzewjg(L30GcbTzM|Nhc*VSF^mWj&TTK2p84#rdR8BwJq?3B~vjZo*?ND~sed&bp^WLcUIri$Zr zlI!qLkw+l4W*i0bgo=7`mStbH9^Iao7S|l(FQ|w%5j&r|Ivih0ojboNvN_yLe*C_; z>G%L800W-N4y}h>+o>;a43~3e%`qi_?Xq2tY7TMFbZpJ2>3H??1 z%MSpSWQ>PT>S-kg5l2DSX2i{M(CnUEjv7CSUc`CT9Dgc4`RKMa4N%@Wg>#n>!eMF| z!<)ayeEs>4D0N4-8tuk}o?c<@X{9Lc6OJa!JQ{Q~qzU=t12n_k3HFHG4i22U6b9w) z&ew0Q;5+?0ms2pjPO|BPJ@tN>*<Qr)qODLwAD=n*(=FamEMi09rh~cyOLCKJn7lSW&;}wL`=8D_6!zYc>=+q+& zeZLhBc*eU2Scw~|L>ShVE^XBY8t*5_X{B%~==c~Wwz5go7Vfg)7ik;Gxo6@3?2qB= zmV&e??rJwTO`#`3fz)(SOcz_MgvfF5-vD_d|DG5K`1u>fVed1f)fXSa4`Q6|%%6t$ zTZ*LC?3Tzjj%?we0B0kms74!`lBsUAG0F{{Cw{#aF4hnh-Nd<*5`CICf_1AUNBvv0 zv&{LUw3s>{1~o_!qAt+rY;_sm#6$$rRqek2P~>Z;i*H(_Un-N8<{s;s+rZer@56$o zJ$rD81=H03P-oyZqMnL|a%F+J$rnF9$nb5jF@ z>QT{gpj=!^p`Zo@iZ#Q);)v$JK^@pv9rORCwD!0EqqI7iYI)J`WpLUEn%Fn0M23p* z*ovp(_?O)4rykOpv>|w|Ymi3pV!}#tvl!W0YTr@CNApog&XJq`Wt{hZ>fFOOx;(z; zTqjvxJBf!*`u+Jm6Xz3UPXC*)UIqW2wZNk;q?X>LPxRXP+Lzyph|?Gyka&=YY3vW) zerq^J&e><`Ve)CaA};jXncvH7ENVGTyhwwULLgOxc1IvTrG6MmTd8}6i`0>c84!*% z3;pBs`T23eXNZu1zr%k3n03y+?Gchp_ZfK_ z$p1?1izgf3p!z!@_$+tYx?~@ZGS>EJ8rlFX#vl@9cH!5cTyxV9&q6-iKi~9!odZ%w z){z?RuI7BVyr9?8M23m#T`k%aYX8soOp{|jSu2T4ptTX`Bp*r{W@TP+IX#`TpE&*N$u`r*$*2|QodoaJ#>Mlw znvNmzT>Vd?$&^;7z71@o;W0n_6MuXC^`sjBqvi;G_tjf3X!I|B=pxFeLm&#$VMem( zZ7y+^nK)*#>W^e{A=V;TZ>V>t>GVQqyNjrlNJzqd;@C0|43+#3gL_1e5G*BldsnSe$ZrfgqZ7er;_kk6O)Mimx!nQpF01KKSvvMeEXZ^L#r9@ zvL3@611XIIJ{9yTxp>|!oi?+cOZI{!JfjHoxC&ILLDnjI_e%btXbg{*-_f$d-A`C) zb!WLvyO+1Ryg-B~GQSc5@2cnDje^e!3fNKJI5EgF)&5Y%8|z(-NV9}YfNZ6Iz62>} z`sYO2G#NA%si|-19L&-!3egYNd4mMBwnr-c$FDIuOxW|k-NY#AeIkx7xw%Py4Z2uU z??EvB83@J)GPt2Zk2ROk&_9}do4iXxa0@MkhyjDRK-%<6V9$bV;v)*{{Wm7={=0yC zP+%CQr8jme3iYQp^R}+)W{As5!>f}8!L3B6{r0>5iH9Y4dN>->^`b)AKMvpcTquw~ zdS!!%bx+41PbLsFnW*;!8Gpf2|A^B5TOKVe&9<3dkIVBoSR`v@`4J%KKlASYQht8W ztmm&(LRmYQ-B27x?T@j?k=1K1ALp?yb;CVo$S9Q8A*4zzh64&k3Zv`WQ@kK+8&)j1 zZ1!HL%6#;O>06h}++pEI;3U&!s64(h-_bK*8kyc!?peC|bywgFY|)!(CTguZVsmNUhRK& zYwZwRJtw{OoBKf8I78L-xh%S}sBV|$(}}5tf8;`BAG?s-{ZDT2-vCkbKd<{=qEVzj z>Tj5@{BEI(c1XjRT8ZuvPg4{#FRjSOM}eC1UfQ+zZsY_Z`AHIvUMI_Wf1_*I#(ZA! zNw&37B;vNg@VCPGIJrD2J?G)v^nT4GN!9c&AWZ%nLMu3bmIU%GFei0{WUu2Uc@WaXDTHr7h>2Ot{@SzS}SF z$Cl=K&L*PMC45{!eut&?YzH05O6d0rK-9$Wy4+AETwJcoTZ8(gDil<9RH_3FHGdEP zL=YYLXZr89?aJ&k(I^pDx>BxOx#cEj&U`9Ew;T6Uv$gazc)uS`N`CEbBEC&p(aLl1 z2B$Qexpbp>M|4WEOpKnv?QXMvS*p7?YQCDtia*ntl?MGiLX3kV*$WlB)7nGWl@wlP;Z~ zl+5Q?gtrOO<)X3w_f{7y%Vy%F0tlZFMRgAWx6r(VhU{MquouIhAQeL79zRtc&C`Wj zHc;J8DNNZ+d;7_;Kh{tNo#WKaplK!+iKPK6&Dsv%w3oWQa^N-LsS=Ntg5QF&sQZo9 zUshKt4y4@0N!F?GKRcNx>YN$1Z2da>7DfHZKp2$wyC$NI0=M%f#ow7BwsA;}9oKz= zEec;$ZXsC{ePFg_3>&O@Dg*LNfD~2`^DZPtQ|SF(HPvlBSy4b0lK`Wc+0V*+_3pc*;};zmHnvg zN~H&dZwcW{;xm$)(}_Y1uU0{>p{*bM>LHq~_h;_e?Q4|=F>k4eozFMRuA!2p!tR`f zTt;?5z_+Ja!+u9{fG-?^QWbwEcdRVw43l^e(bG}LNC{;;nNEmQugXpXR|_>edEcL} z3$bzVd957-XX-j`)x3+-i|2qby zM32!ty%>XJx%{>3bLSZFwsjJ_k)Wp;)FfT2AQhO%;TtMI79|NF5p%tw_}kij9ydM& zec|0aVewt#7Oh)W4K&an^Il$BY@oj0D8RU>FfXeR{JIo?uL)I9eE^)B8xC*&C!z2F za}HJ}B8%Z2bX}>eVOj>4F$W+(m-~R+Wh&ptys9i}4KsMVnj+!wCmB^)S2c5wthUG? zF7ghjU;>T9uOZEkt!*m?=Kaf*3m|N+0p3amlFou>(Nx+BeQfPFc zB-n%sS0Oknv#0x4tgp27XwVK<>s(hwEkFO2iMaFA!{Gw~4{oUinD_bn+FWxk!z zZc&~d2a*&~&V<$VG*Xv?D2)j|QKv`r_YI{`M@9*s|3Z#{&C~j>Zy6rknzLXn7q)8I zbyqP}Mos^7Oy$^s@+`Y=bXuHwXP9+qP<~d-B-E5=&Ugz5`Yq^xHy11oPRZ-s>FSgK z@HL3sb09vLc|=PEimT}B2oa}g$D^nh_9Jcy9a{e5QLKqhKKvfk{`p9HRgtMC{n^q) z*%AId@+#xrGQkI2+%OKIU~=Cxe$1PP=AS=mf2p_0_$xK|sF_*v&-l99aF9d}Jmyii z{eI-8xqRRe?czZJT$t4VNs%Oc*JU+GUY&lLc3$0-PPu1nSuV9siAR{|G+J+y@N0dM z1zP^TyU+P;)JFhKB4x<5Q>%;Fn8_SGk@=czm9zZ5%o&%l-R3_LxP@cu5#Qd{LNfmN z2iQDf_`g(@zhwn4F`taJXj;0CP0{Fz+? zeqDYCWd$OVDC5}23a&$4rqSXfJbKyb<{ck;$gP}j+FhLZ-489zqu~~UEqCmr^ZlU@ z^KaudCsS;MKSm#o7c`GXe6j5E`M_9vdfxLmmG3ILV;&UFnLqGSXH@@v_@FMwNFGw7 zo1Yqj+iw<7!m@|E%(X4m!gJdlIFj>UJ_84AETon{Wj;P=#n?%bICOJ=capoufqJ9O zd72oz77uFwi)BVt=sPbVEJ{uX=7UKC^UfQd@;i!}!&CG78F3Toj2#v)UiuD%8(xn{ zDPGcp*b?(o_^ySHDn(+iQ6bE$80HrT03x`r>wo4V65cD*)^SlT-{Uw}y#|;_2_hmYwSY*s zqJV&cbhAi`l+@B;0MeJ1Sdf-ndZ`5j0qO1r$z_+$Wp{rMNZt4S{$8K?hh_JfXU?2C zea_5SCi&QuCsYL_Dn_)(Kw1ldQ+dGTt$Pl@!b^h@Oz~0%)+d_UyFMen?Ypxo|3QoC(p3$uSgnY+ZQy)57U>sZaIHC(oa-?}BGMJum4G8m%Iu?bz?23O9P`N88 zvA;q6b{HKaEJO5n^@}6$Du7)Vz~_DNob7Qx?FA``J|)VJ4ZAt7lqhpa?{IJ&mezvkDemsZO{AAE6CNwU5d|B%!3Zx`zl~@ z6F*Khs(*bs7|`fdf?MT$26@!Db-g9RCG42%(?9120Yle|Dv{Ar#g0*!390npd)b1f zQiWlb#kLUTxLF1uxfjqF6x!E9Ueo&g$a)3EbFr$?{yyHFO2O9Z^X- z*&KW%6sO{a-4Hl9ZorQHr02If9pxso$@tm(#=EAUilZH$WhQY=#;uZvRD;D&(}L%QPt1-J!y^IF|odP zWz)r3i56g_F6Z(>R{z>Z{9A`*!Fqh>VxGF2M z-B!JXn-Qp)nTdqCmAg72$As_QJp?WwEFC1uEm$cR(eMATLB^#uL@_|z<&K_yqT5cMZwG}Q&R^hVrcJG?6 zU8@s2H>Xx!Fw%R?$bV??D4;Ndey_g^YINpvGt-WI865PepDn+ff_}(ILyR9Ssb?93 z9qjTS*<9L=FS|mJ-NXs?x3l;fo=k1LXt3HnTZ64!v7U&>EIIwC#3RNWR4&fS5FLiW z-1SmfbD8Tk=q1Qw=l$xZ;*pG3`}Bh^BiAUPPDBJ%mJ^dF;tRMO1(^8lB*9ymm)Qin zWI7|y+}wQS^3*{nduGZ+iSl;JK6?Y`Q!)PPc&~(jMp`sF zhh}X85Y16}leKFAWpG=SE#X$2L~VxLbO_$Rf;9Qq6&dFLDB_ zdg*d>w2}6@wXD$c=yfB7_(K`|UQo$^;o%Tf&6?Z5ohwE48xChg`KpRD{^^@#nVHJE zVhrTXVu~q_nA}}2i#5k-$PLd7-j{#`7ZRABar45p$%R{1bwSs)(=8v5+yZzCrTrRR zhr1p0SX!Va%Lpmo8qe8p(WNGQ+YHLmYz?Y)=96|z+;NUHEZLyxGlRDqyYA@-YrdY9 z;em8jZdnYQ;jPW;;ZrNgd6R0LVdDKP@l-DJ9m}!!d6xZkC`*CyZEWkk*(W8zBT_;< zriMMxXj?~GCp6q9DF+gqrCW}rnoA13+6Ug={ngWg0*&I1#Dx2 zt5RCqoQUnkLHitNuK@}1g!%)(@r>vtO(ddkx)*rAI;c#sv4nkiAWGRFjOa5}7;vKV z;6PLhBzB0wH}k=baHCR?XeoAhP@gkqUock}?z7Rs%{q6S zY#{U7ki4uIYuS}T`WkXv8=lK~e5BHG1dMU2T+0?GH$236j_QJS!s?HKkd2bF8xHbH zq%mI3XBYPB5`WkftqqqV0X@%~J$UaB2Lw7d1UEhHoM&3rL}+&V5o0X-g$h@tf&!c* z`LE`W4kndB?x71ND-`W3O0S#7ynNVWW1qm}d&T=bsD2(ae+}N*u8lA*E-lrKu^L(E zEVU8rcQFe+FD=v?@?*ii0%rmn6V#lyZHXxV#>wnCuw4C4O`kp~cN}A7A0IU2G7Giy zc;A$9nIQXd{q&S``3PHHH*!4oZ60;S?gbjcYa?!BSA^QmF703@P?fle*O0y02Zx}O z)tGk-zD53gPa--Dj)UwX)nHv#GCyp;zU+D`-1bN@dH*QQ04^fsqp6a4{!t>*K>;dT zQj3PDF#qn_-foDrbV{NOA9ar%R7JCTMJ0@u#=^`m1(la?Dcy-I==)sF)nXe0)#j59 z?d|wBpLY?E!{QzDsR;iFB|^Uv5Od?aso?jS`U?RU!ha5Q$#PkhjV-6Z4U|X|7_8j> z0B0O|SW8Jz1iLj;4|a&^;v+v*~eqYaBFJ;A3kXANOOP zWFBVYNgjJC3oX^DHS(Pw)tlbYKE7iX^)g*Qhh0R*KJt0?d$bMjMwQdPQ8(0=iv8&Y z1oCkLl>+PFwYbKEeK`Q&9*SfRBoBw^LmD72G@yb2^p<9|Jio;vWh92=_@rY#0U}W} z_uG*dq%(1Fg4}oxpdOh3OX;$NrAt0u(#ark&Q_fjq%B|OVViG5mQu5EuWfhj+D3Bq zV}`r}twlk&oQxN0m;hx#?1OgvH|KSCUrh` zO%#m5@ZCRZ+J0U0Nf+n0pDU4N5P!&kVHz7Yz27{(nB|zQsincL!n%geUbTE28{Y8V z1t%kM4>UsIrv0XO?<+l1y$02eeFgVhyT*oLjv?7l0L9TB+{6CUqATdZ~XXT7sFLcJA>O>%D!RdDwn#?e7BesiEdeC zkXE*1i@Nq^t9nI>lkJ# zs9{DIGnemexD6dy=Q{HwYJ-Goj*oA7J@VI}MQ8aZ%7}pHA-&-fyFMexYr&FADTy1e z!&)=`BG6$hz7EvMA2fH5lmo8Ui)VVKWzX*Rd17y*xQ9{H!fbecGf_LWkoFthsF2dH zE|BahC=1fGkXKNVQuk_af^gcV8%9%8Oqwt{m@@?SFGGcoh5Q|6So@wkI@~fm6V>8C zpL_uPme zgvUI7>|vEtBO;(-a;ZbU80h9D<2xd@mu5jtosX%v(j8?o8hb_}SUNO&*3;U&#_;VH zUM(#gUO0rvDsJmDekEXu5GsJDJF1U$PgV*O10pBtFV2H2EAB01y-I+ zXm4rgRq?2ZngoW%dvP8NvKS>{q>_Og_*vrf>)B6T^1m?MGJP5H^sBh#monz5Vt6>r zM!>|^D)CEQi<26Aqpx6en;ok7Mc=9#B{+7CaHZ-;=7ymp+_l>y&eBb<9|g1F&r-cK z$j;N`y8?<-G~ic{s~jJ>A2ib-uHiq7#x+EPSNqW6LF#cUv%nIS&SW0j~FN%guX5;oob(NQ_q5wcbdfsUKKHNkueW9QsauwR8$+h zrc|QtR-Q)$TstPuN_H5q0O;(Ggym&k1ra)IZrqD6ZO^Wlce`O*7vB?UTZS;dEg>bF zEvMw+95p?a2b#gRO)S6J~Ct z6*)4I-o%Hz^qyNf|F!;za#$9cw8sT;y^!SQ?Nv^-&wy(Y^s?yL;KJ{fg@y(xco}7F z(9X)&Up`j+(GS(a0(xhWbzI(@dxbXp#sk7?4Tag%jOe{Hk7ifN+j?v3DAu#^K&gzw z1U{JMnwqt4A9p|BnVxO+9&4VqViL2HNo678LSOv$V8}!WezLC`a4_ibY721_2ZCxV z6;Cd3=)Jj%Gp&L?3u+K;I5e(p%`SN`nD@{pyiAmFBP$#<$msFWupAcpVgh0X2fmJr zxZ#sYJv;v{D0yRt6}bs8_p8Yypz`}q3;$zwkTrzyU}fnego~V}@Q_rdL}g;TU9npU zYN=f)Wm*!fOxX=FIVbXufs+jHT2@WT8WTvB44AwBwpHpFLI7oSTf}-*3e{2e$wR`7$yAXTA2|{w%kVb((w$+RYvrV24lt%XbFF_! zvl(WGU8rwR-DWljDr^GWosB&TIKRW3g`bmkqxUs15VfDT36{uj5Lf$ci`)Fmzjq<) z&LSndv<9uToyBk%N=THX&!jfNPoQDXKeGqjdTk})TR&PuOYXH`G|d|1S?ngTH-0e- z59#ak_-g)Z6Thaj4Y)pixx0}-&gsW8wHpdk{mN~M1+rgjwBMRhvCML0Sf*%n?2_${ zv-d8g@2+MjBvpY-iPLvd`Gz_wov>q1At52kO$l4PS~7WEeM6-su288G+LjVes)YE? zB*11P^wF9FIK7jJ9&+UN!iK#4X%Qu-;JWBR>B-@Yf-Y!N=7*G+hGp$SCwGswCJ`EY`j~Mcpb|gG02;8+kIsK zZS%FXFuQHLyCVfpESM+I7vqB(s8Iq!=IaCIH3!?C+k_H`>r8B6gC5e!ke#&v6AhHi z_XJ+%L}f~N*;>s2LmbU)(Ug6KXgVa&z)8XqR2H|IAeEQ!wdI=6RQWIDvq`2{*pANt zr+IykRII_uDF6GK!6hBQTG=bZ;2X^4hAkDz7Z6i%dmGoy5nTs+o`EHECszogjZ0qH z%fb;s!8e5PT`*uzGzKH@17y-zG{=wJzN*fH15>IVXEfgXov#aE98sUW`*A^SwIwdv zC3+Uv|KEqj!Wh&Y+1Z>r%!(&b)vO-L(TSpJnTigjRy%fkI}aYvnzxB&C@9i4@JAXRWH!^fYu=uJvI=02lbTDrBpli?HkgT8R{>)XSb!F4I;B>p|x+MZs8* z=<(Nemct7LgNP<+7(+UyJHuqb!*?c5OKT;~KuK9GRu;*nqY3+a7FoI5HDmE}?ZKPx zG;4u<$v>f`NkVO%%yH%hODin(l_lW%v*aj2D&dttH+H~B;OiBcJ>~tB`yG1Wz*4*~ z)@(mUxBNk%gJ5iQ%{=qk`)?I;^1%>RH&aOMn45y6B#9TKEMG%jURh3CNl6Q$;>pV@ zfRZV@EH{G99RkT$ytrm~TND{BB44Y<%{=)IZqFK!&>pZL6M`^7Wy`mhSQgHzh+ioG zT=FQEty<={lK})^B)PH(MHISV2n8=g^-2lxNWNPtjAuwy(@ruF_7x4!40Y&@Z0kY> zPb5>ALP@K2Y09)&Ew3rzs)?%JT4-?()h_{urrcD?#z1CQft!qz7we_9H0|(bNcwsf z;w+EcBFK@W1I*Z~v6dP5bI?G4A|nJj-_lnbgM-mwZedyyR1HL=-ajKM#kOaNiQN+; z(LS$R9x}hdy`ZOEY;~5qJqe*FLXC13@H=P?-l~^N?ef7iMLmlmP2>+406{(OAq&$@ zx#E%|eA9Ptnlp5nKS#~xF;XjW56d>2Blk# zAk^pG8=Hivnc&x3gN35Q?`D;TB{O#7*6dcz%eq)H(oNx$qn4oJCSRroA6+sDIl-oU zP^cI)i32lhzN^}ARB4rkIX1eYj)7pDpG6m_e2&{AuOu7AA!)7}NPv%#0HEaANq$9I z_ApurBpwss37|pRBygqpwpEE187t{9%4f3O+)k8KR9l&rIe`~x6jZW$TM?aQJlG-mdRt-mked>#Rx6y{!i461{TH3iKa1;^WN7bK`)DBQ3evs(^K5~jH zc?u3?6=uL5nAg*0lBlh+#F3$}k>H{HY%Sa#GZos0IW}Y135ZnhHr6bG`zK4AgjXhj ztB3Zy+?YRWEEPOE;RfFKxyRYkw>~3h%HnV(A`yo+P5Zfy)_hT&v{!Mv&h~RSOt`Lw zjL@>Sz`-uKeW3ma!o$O!01(Bvq(4`6`s5q$yEU7grfq;POO(ha^sfGh^#Dd3KQTYs zdH$PTivo65#w}Xcs6?*`~UJX7;uu@7M1)Dh~@V{FC zJ8|BlvS3Y3-L_*WFRf{NLH?*D1?b58;w0zy7IY9K1ir0$++=iwx=;(gdT5;Oe zW9|suysQTb7Wl2o3TZan`3n^*BMuRkrjIi90tzlH(%>s&E)#MBNA3!M-?P?0)=lYR z$;mrpj^DAmkU2K|3*`#9NGRv<))F?{m~^Fo>K!)_3D~K#^(deYMC6|QJPusBOCR+o zke(ejzLmo{X-bJ(?z+aQtHBnFyD4xYINZ;kkRL(zw?Dh<2nfPuox99{7%qTjP6AcR z5SZ|d{j8#{M&;`7n-Jb3oB=UQ;H;ga{{#=u5(GG%)gX1O->mX|orp`GAZ|N9&a}BG z)^RWQI!e$a^~e_4FJm|%k1C=g;wNaDj^#ll10k@5{J5euHNt^;HZ)l&SA!{%4F#mw zj@qV{6YhJ!B$dP({x1UGWcBg5kwM_y?sc~-+o(6+?2T?|{wnsP2$*79IfJ_cW7V3oImI!5T&wQg3?x8WfbT^M#Cku6z;B%c6#(T(FQ$t4 zsI@O@;aiUuxe8}F#z4SZr#*+G$dabX&>rW)dj6a|S`GIM%w8aN)yQ?#0uOiFuj1Tq zs;02wH7)?DzawE31fYV2;jW1eFB*~~=K^?S@$5A{o)}2(EQZ6yrV)TpmV?73EhuVo^Fq_1#OiBF=zk@roW3s zw#f0|;;Gg?%5$L5ecS+{>6@oa`)e-unqEZeg$VeBI*&UabL@R+*q@`#4xavhK`!pFv4tq=7y?Ip zx&jE|vmf-5`L}Gg0YilTix3j-5^-XL5b$0BVZ7S1M99QMDbwmbn|JRi{8$}w?v38%!TIRS_~u~Rg9o8pMv4?6=Ix3$F%`()~1 z^w!wjq#sp5j;j;b2qzo>!6kb97_d?Ago_Wq{bs2ScXP9!X0FU%;dB0tUApvU_SV^t zbnN@k?+c-yYvq%zeg8uKi3xZ35_j?4T%HQ0i`HQ5BL2a-t7AvNm%HQYSpE+Hg0yi_ zG&ib;pKXni2dCb-dCu!$WAO6t8enK88}kaS|6}U%fCQSb71?!s+Kk0{xe5S8dzY8Q zNY>@C;O_FLkHt|T@P-o%xS#zm@O8WKWo}XztpP%-R=IBAh|GI^>$$Bfzh@QRk~#xpDPh zuhRWjkvs6Rc6~T*qs-&IN2yLGE9EC_!M!&v1IJSHEv6CGEhMn_v(>N(5$~IkmnJEn!$%*SlD-iC^na*-t}z{}hr4M5`dc|Zj_mYQZ_ zGk~Et+nd z8+WeIUM&qVytuYaUYJMB-1>JgSKk{&zsCaAR!>bN?n>P}cRz_#j!X>nLWx7?ALSr{-Up9r@s%2jqkGm7V-6!Z95~3vyn)kO^nAf z!fwn-)=0l8?hXC_sviOxlO0|7jq}%Y5-B8$(Jz)BPL$qD?uz{4?eBTA{yP2M2e%)c zd_z!GFYne)T(Wuf+2u#!XCab)s6}r&nU5yJOqcqo?TstheY*MGKAa*s2BH=IQ~mcp z7XNByv!R+GuG6hTJNua-c`7IoNP#K+u~GJ0%glz%6Q!Nb+#EHh*gDk1{@7GJe3@pF zp_Kw?VUhjk1HWYVktzy})qcCB;oH$P3t#$*M2L+7HpN;Z6=Zy_XHyYw_;>lA0P#fa z%YUXt&^0q=^tp+G=&!Pj+WxE5i@qpX5#ng&-;*O}$9%5^QnNa@s)nB1`;0tK4{d$^ z(v;^TUqo8Ci7)MB^d&{ z3L8oo-ghE`H!ar9Ss68X+T%aDcu3#t8@<6{-c-B2o|!&6t4mYi!W-+dY9fQ9eQe%X z@C)O5WbG2vWIx=YB^CL8hJcjWt)#LU+#~`L&&mY=INioO7oziXzvtIqSIM>L3*g;G z&?n4vJ1IHfy&h}wytay#oI}AX_(fbt;5@ss0^|CvM8^aIP>X(TtrB&C_#ZpStpt3i~TFQw87 ztXKez8@+aa5j(d~IWNv&sgBpW0QMftq=fh8(HjGgvT5>M4t75!2tyU1hc3Y}e#RTK zqoaK_F>h9~P1bdnVqf4Dz#z>cCIDrm4m1)>0D>mAX~w*=lbQ7z*Gq!ly-WM*@4B}8 zLG*24eBWR=%TM+bbbpKai9CMupAX}d&DzVPE2Z~ti{NBTfeEN~58UjUwN+9~%8;+N zJ&PJDOneWOF`8`sd#f&#Z%x7!9;L8UOT{L#6hkB464yp~@_P5Y46c*^{=8pPi};2{ zh5091pMB{2*Ow=^+uTOMU+Vk|q^|U7fiB@u10~5hLncEs{u~mRgqcqY21E1?*}-~5 zeOF+T9Ohi7R@6Y{zw680*U}=Ejm`P4a%msco%16rwGXz)A-6B}0J34O{YORh1Aw^b zA6uITuFR`-#HG`$>P^d5P+xFchZ5E6Z5I?75Iuc)f))mz|A;h(>cxNyQ&~LPfm8Kk z?BYSeEwPy1n;nCYyXscb_jC(j_Cty4C%>oWg zY6S*!#wQM?f}%v?PEUzW^xs>e062X9iEF=3-Bfv}O?Zb(FZ5sv$%QN$;a^7HUIb9) zO@IbawrrXAhFCP3(@A?`7zBwJD|fvM%)diY%`n7pn9>1=?jN;BXa2M5-(Ed=pjjbz5R!PPXUTJiE9?G1`hs+|*CgNus%!g?y?jKf72jufbw$!8dMi zyv*bJo#`+^*&R>uXGcQ-2bA198pNG_2`w_eZO2RiTtK(FETWCaVd(4C4wuoh*FVdb zZVR0&MND^;_=nPez^iIsknO2ITtV_P zRQDPJoFL|WTOHxQ3hjRS4Oy`Z3uWZk=GLhLOXyMtiNRP)&|c()Avj#O#!?gQw(Ow# zq~jc2>Iq}V>2(4Ezw1Y2qSK5iqY>Ql0`uFk>{remv?sZ%Hz_A&`^?Q-v5EOx4YNU!MeqIFtc*YB`9@aK`@yH|(*Ez4D* z1LDjohW0CR4;o1ZpdSU7w>dm1#DU3pSK{ha66{=5_DU@**5mB+uYWHinc!y{066wE z(sa80x37dUER`Jk@=ULYb1dV54gl56X^Ub@jW%EnVgaAgy3QQ4bad1DFshI6-AK!$bfSTUfkdHP^G_iIJbEG z;+`u5=wAq@m%Leio2Ws{iK#S&)H+~$$y9$X{K_-2#^#cdQ+9!0G5?XYbq;nvHW8Ae zx=K>sv*@U}(#ym=IzyUK$U>EtLUx)MCr?m^fACkCfNRl?`5`qB5WM!oDY`VH?H_f{ z`?0$d0W5q9>rce4AJJ9u<-hjpXAhcG5WtgKfo7yRX9?AZ@&GZ*eoF6ItuVVtk@&w8IA)Au@iY5{kOwUk5L5SbF6h0^MkFrp9#JWtdDTp8$Bfq~AH39CG<0xr3<#Q|EKH?X5 z;=OH)q87xg3LBTk5n|kR@3UuQ*B24?|6m9&ujsNHHaU%i;3FhF@pdgX9??3P7zy)O zJA=-J#Qti7jC&&SKTZ#M|9Hr!r%^Y176O>KdQ}X0fL;I;=_#A|o9?kq45;Q4k^{^< zYyQ5A0C2zrb$5lDE*~knCt{Q;A+UVlKJjD1p*V8_UTA`d68K{OMy9ISg%9|d%^~P6Wl#EF&{lYMH6DgIc2m%)NY&0j(ShR7Su~0{|~g2C(zQKTD%Pm z9P;y-tc$=tg@5w_G#s6^3Y_+6tq2Id6HXrO34ZqSD40j!E}tBwo`B5F@}MAly%XI3 z8zp_m8>fh1|9^I@d2*`bG!Y?5 ze(lX=3Wp8pT>k#L0m<=i+E4d6TK1|(#K+xq9_^b%J<*%u{80AuivPrtW)Q(-PX_zW zeLT6EQn&vp>b~LYV z3*FA^PT707^90}fw-%)Lw1inVa6)riYwFgAQX#bM8jlcUOQ>=eV|XI%@;vLljv$25 zVE7NR*AD>=1ipC6KYGHI!SNTt6Wd#Orx0B^qd;1B_KC%T{7M1qnPxZDgk5ag1w0pe zyv@zgrEp{^lEVmE!Onp#FuLyk?y;rRj0-b?V#R$OyRpG9D(2eu-N(s`(1p^H64f#@ zncEIKJG{%CuAizNNmkn`VJL3r=OFm%aJcHcwU5HzQV$8Y!vNV^))pKvxsiH5Ky|*qa?k% z$yd210`JBu0aCEtNXjVYrUlBJphhP_Yp<2uFdZEJ9Pc#Ng`X(s$1mA!0QU}L+Tm*~ z_AqwX1-IqPfb?QM+3rBlq-$zjJ{3$gf}q(HEy&F9|Xf2vdnApeGqcEfN>9zBqw*aJ5U+`_ZP`Hn!==C;H0} ztc3Tf^QPz5?F_HPN7!-67c`ETf3tQjGzs`n_2@923G(7(7NZ9WVCaGK zt%kjIa}n*{9y0Om0ix`U#_IFWLFVNVVr` zkS#wZoin&pRNrpRfJ@tB*vJG>nV2<$X}c<`<~mV!GdnLGJAajVkd4ulXnZ?pgUroC z+htZ)ZC2Ed;DN;>8rl91+wsLFqtT{b7fE)02<_*Ob$%UYp|oX};=1mu8OKvM*swDf3V0+zQ;cCTXEGzA+icX-LaJfs=;Z`ngX+Z9c|nJ&Y;&(EBEa zYH6wrBy`dt3r&V;d9 zjSzqfQw8u*BReWgpn_G1HEV8aRU>1JvnR2D>RAlBtPC?Xl55b^yB+E4#>c()v&1(! z7+B=PmNR&q%B`O!cio7pblgp=bZz<|fm^?CoO%0C9{$m7GGFPuMjLv@whbvLQ?kwa zoUBrS`LisQ_hBHz;5+_PUbT??wXB+!nLW{h87ab89cXg_C(+Ns49 zu^L}$GpY$IPKQq?)3De%T8@$qT8GJ4bE}MBaw$%kCv^y4P1BWEXNbrf>>zI2o8w*& zh-I4$TZ8pze>E#ow?_3k|J-|N5YGih+whypR6w>I?T?IM*soOt}mJ7%!CY&r7D$-ORs9VS) z{Ig2!V?L6^LCPteQdt{$y7aXVnDujSr*!*ndsu~(7@DN_#8}wQq`X7T#PoGk5t9;n zFc^lF=q7V(G)g6NGS0+jn)hs2!Db!qI8yFyrJjNWCH+{(Y&`$E1kdSr(e zo43Qu6h<2PA&iqzB|%eLQyEUq-%_$O(=BSvjp8(VN0epwR4V6l;pn`PEMm>aj(%xZ z0-w2xs@#*>!=(zdQmBdnMCr5wX$sHEotkxJmvIhvf-# zY##ULNu&ztlBKvQ zvMPMA?J3Vz?V3U|3F2|tzOFELbP$QMC#|iGkya>*<8CeYTqrmRu0{$C9bXRmqwevjP1))#TX!> zqnu&YB?TS0cojne3piQBb#R z4iP1_uhFexQIDF*h+eLCcuPHi-LDme&F9_^6Bd>rB~mMtzvVCWKpo{VFc6t$Xk?xj zpL0{@rFxoepUcKhc_=hzRm6pGC5n6efU5^7JVTJw$1JdOB)0)DbGGeZ1k| z{MYFc)2JoyEnE23USr70F~z=AHMl0ST{YQjJs;LrCuvm9@joh~{?(Dn$k9KcS5+qj z5D;GtYOvCl?n+Xfca_=^i_1`wnv!D_b9$4>$0Nei6)UW%@s{gm!y}N7T3V!XeF`~| zYd~(*XI!TMxCiMk)lJ3D$AQsomf;+1;e)Y#)>GXg1tOId_e4 zfk&bO-*h3up^YZ~^70_R*yTaXHMJXVJEU)_DTm5t18RrN$QQpn&sz75YW=*7NQyjK$+t5Qb?``PTg_N#hPe<0?QiUugFN#fz^J4B}z zjq28wnJ9|__)N4(QOZmzeFDI-NE`m@H}7Fa`SSVvR-K~3Bqq`>na{4_ELJdayTz~H zKzWzvaJ5-R|NkZoQvN7V0;2jGk|FV@5G*rRG}xwda672>qwg2b=bq0PUu7f*t-S3K zH!@14*C5KjY3uRuvQLtHbc;#i$cpk}Sa{g|$1$t&+{DS`GsDB(6Ca5M?Bfeq8zdew z_c-z~l4W8%pTMdL1^MrwJaT86o4aj{Ai6g3BV?C9arG@w1$3`E>+{`_wWQ9p0Ep(v za|`64%Yf2Kc--Fn3mF0FQ^g_WK1YRXI%Nk5uqHTfTpLah_6Ic~OzIk}2^Q$J%& z>o#O6>=SLUjIR|{hV@7!DhJLF4A5nz%~C=kWp{7wI##kyTkrhx)V0GaYf6l5 zUl74q`@-E;mnuMh4+ibVMn-6s0s!ZsE+7t5+i$b!L{|qK{(7v6+{KQ38Fz!!6Mha0 zQkF<%>TzUbB%|#7ma6hrK7%I@QaBnD9cjv)dQ~M^w36X|gJ_y%=gZ{K4JqVf@8u|K zR>p9o9+jS91z$&$b5T+IJF?{J*NYgn5@=7o5vkK^!n@?h#9=K6;<6e5e(})$4m*=d z?Hf*JdoQxosnxRU6*cRnws*j#oZO~30XdQR0tPc)l!Q;u=!SG(UH1?ANfYpn{B3)i z%A9bky*vCAPFuqr2s;T=!1X9!Lx|86W*JHR%kyxjO*x9EsRC!R9cdv|VF35d5;E^n zCFLA0!O~Q8RkFD9l#{sy1XeWTg+vs>34vXke)-B4>xNM!b?gn&YINMDK53DW-kZPk z{bf?=NX~aMH$t0VXeXeVxq885L$urbsjVy1+{FO|Ul>jGL;x$1S4?ySQBYxJuh$ zyf?osa5X&6PbQq`B$^1=^+(ZDWxq3JJ%{FPxM6O2QpKBn5s&tYd~VNSET7q3&t13Z zoUdXiul1J8SN@FDzT|}`ppqLczeX0G`OFtW2DG*fKtE} zO+FP0hmw1Qv|T?j-mCsOE?mlFIFSM|U+*)wsnp9bkr8=#a`I}2$t%N5`$-f+ZiZyd z*VuaJ+)3)`Xi!IV4ACH5{gR<{z8;yvrR>p>(E^=BZ|AxJu z>sr}tZzi;FCMD3hvba44j?WqGbyFB|u~BOxCGA_WLVV1(gTjRx9fay+goJ|S@9fld zg~Ps~RcBWK&paHx8MLKEtT5&%7`xjfF*$L8X89b;w5o{BqfK;)-ij;i^YRiFYgb=q zS5D90!#;7$a|D+ku?YjgEu9gj=k&m>*#uQOuTLz76-nfjLgBlthnK?BRYqTTc`X28Bw<#4;Kg z-lu1k^qH>PW@P8!;TZr>P%1CmTWf2kHwEZ|h(bRt%aQjxxikWFttI0wzFV?R$N^t? zj{;7{x}t{_(&(=*6#msVPcYqL=+4rdxzW;Y+~fr}Y|nNZekrc@gT$7TXvDXOF``?e z!~$%Cq#~B1tqc}B4YlPbwt}ikUb3(|c{MP@9CK2_gJM@5cZOpzIZi?13w2%(jg${( z%GMhQEyE}{)TDfkiur2#ibmP5CS59TRa4keo}H1bfH3DVMm6`J9)P6R*Vpx}SJgNI zaD#5rJDS3I@jP@{SXDBI5>1tb26biiLNW1|_2Ks0PGGZfgFB{-xyTl7jb8~_!KPM_0Rm{E0i57PT=E}ckN z9hVnd}Z7_R_df|#ff+~Yz@(-!+JyaV5@&;D8WjiEPM&fQ}F{j1LKFUNx z%8Uf{tlruD&h^E$HpLd+U0rcNIG4^ECfkC_$fbo+0ogMc(#GBVTv-8Doc*}S*s+9Y z025z~rqL=FXvNIpCzCr1S7-$2>)CbENDQ;h$U85b0W1r=)LoBm_uI*MC zC@X~?k<7I*Y)1t6Ecb5oq6T5PmVgwzBAFBHi0RiXHMVk{ywHPw36lC8R-~%QQ(;^h zn$o1MJsenT3yW;4tE4iv(*PABUCXEEW}Rvw>?z8`_r=(o z*kOLP;iPWw%z%G_MK+fv0pIXSP;#^PvCrG;3#q-eGKH%nxZ`u2Rc%ky z*LJ*a3AY;6EtvGjo?sFpHNCyiuY#+9ZvaVWx)H9yZPhtZE`KZRoQah-3rXifKV!>4 z!>mTu0Ap=VCNn}ewR4V9Axu7{I6z6RwbOAB>dg_-)@Ik|Lh79py!Og+gqRgcmHHeA z=x|Gv+kXqN7{YeSR!-&NH@v`31#{@>l(-#OM@%ID$_A!MYEIixM!KiA8sS=8krim> z*WgX3fQqDZQHmW&3lN)1h13;|Zpv2PY!h4w>&H)vXoGa8ehTf4pS^*|GTAavsZD|7 zx^>^&J)SfH_UW-D{_w<*y&lw4pPJDVHOb%m+(o~fKO`)5mOfTVr#^2kEd2LWv|%16 zpl+iU!oGHk*XcbLm83_$6IZU|eie~d@bHSV(?dv~%Ycn~tf`DJa`01_=2@m}jVltq zXxHC^=4)!%7F2YFX`In-U+sMpA=0hqu1`Tl{6wRO}!Syj2=hh z_1~9}!r>Z&{r2`HeeOO;-W!F27NParuQo6-%uq`i(*XxD=ig|r$vzQ?#$x%~2zt9T zj_LLv{ebIGjE(Z0sxq?p;$7*;OW4(R$^z7(KDN3u8Bg?W4MRqt?3Pr`{U466vlPYG zR$k@%yj1nsryU=pYM{7yJ(Y(P_RD=$X5U&{z33F_G+<@4wOM%_F^RS`O-1KTO=A|c zWI?lffNW=EO3vhFu+CPX_FWh%suy4_Vb3mG^Id7nE@1~ufdxtJeaADfZDe<7rA$SO zV$6AbOBa_`pV%IAmVp^-J+V0bpwu4RG))_r6U1I14n_YB!)O|)#^%6f;I-Z+tv)U0Fuxvnb9-r3l;MxfTGJ?p()b1gr7@3>I5^rtA|K%YKj( zdGy7{xHrAKzTEJmZI()o!W|*ClAHDS0aqlwCw=DXt~kJZgUrEU=Q3!s0%dzv%V{t5 zqJ)8n*v?#owH$~kXR3I;vFhDaDhRp1@DD&_{r*=BKWNF)HznHC@vQ_%oBIV0V_)y( zo0$6n?(FhUwhq9UsHYirklsTpk=KF8+@$}TBT;>z{pB#6l*tS%eOsI}IwfuZH_Rgw ze85zne%JDB$@+M_q|CINmQRb~=9YQ!kw^YzzDKz*a2Tg+7jrNQU1dGT$ev=ufL-48$(PYEaxVi5&%=z1F&@tTTXQ^P=ieEk#e}T$h{9Z z$lTT$j~N55;=;hdnFqOD_otms)_C3cZ@;}Odtp;=bClVK(ub zL$_;FdJ@ZnM{c*b#CgZzlciDTnsmlo?CMj69UT_SEbaD-D4z@BspF3zCLqXk2NE?% z5bkg**zztw9#{Va5-tZP@$=`#SfHWD~?D7N;5`rTe zR4YMcG(KQ_zuA834C0yGn*B#TJ}|GGndDs_pwiu?3Vi-%*Wr}?01DykO?i>6z;Ka< zVE2^>yiMJSV10g1dk&*;{Znpe&b2e{T!cBE_3a!3zf2b^rhS2EvF|m()zrow=!K_OkDqf6wvxJ12)R~*y=0<-Xf=@)U66~Zk7*UE;9+;*Y%Gv2VD zI5zx>?hPt>^#4SXh1X6Z$uaKLL`%ctSSkV?L~I6l3d`=p7E>01-9wF89HxelgTUN} zt%1xZYDpoz=p&E~ykL&s0NZa_kG&?|F93Nm#t4|q#-^r{A6>)A?lA|N#xTAeou1Ro z2ryUF|5f$9k8(p--CXM9bUX8w>F<(B{#_?lWs{90&FHXmu+ZO$H^VrySnBmQG%Tsl za?jSuGG4}Pn7whfjwziAwg())eF?gxJ5MPMU#cjZ>f&*EB#hT6o0`XN)mPia5g(pE z20&7E>BRMO0=V4kPf&kXDVN`sSK5bEvVDokSY6hH>f!yTy}ZT=DsLGsotG5O%T4|k zk}QvIc+yf^XD|OUFW|oY{2+G&8Rdq!9^V~lOKKAqMv~6XUyKUD_D>ym)p9qgnJ0Ih zDkxRl7K{2FI#}aD9Y6v?Zz)z_60Bt>DG2GiV)@(Tn#8}U?e_65s3%~+VdMW3;%&Fs zCl|$x#9*D*-K*tt&8upXmtnfoTAUO#Fl0_s*m@$BoB?*!hMKU5tPD)Y`5DC<(po_gx3>eE&^ZK`=A#3t2_>BSc{85>Be-?92=^7z{Y9vz?Y zUCb&Ik=pw1Hr&FKMN>yejy+D*ZbM*quTR;kI+{3F5d146?h$$snAhZtX@B>Uuk*F=}J!+GHOWSb@H_c}gcS_6B>_ZNyrYHtCn zm6q{|+>8pTiXM5mp>01IsDRs6mZJ6Zu}sG7$BPLWd*))xA}MuXBWQ!VxC`VWVpY4RR=)SN39u7eM<-SHok%q|ZRJ#OQC z_M0MfwNwZf1x3VmFxQW6aK`oSg&f3-Ruc+@C}>YJHobd>?^y`vK^@@od}%7j~X!Z^=49c{lpG5G$6SheF) z^Ri7J&-AM*AMUsZvIL~C#VEpD>kaQykJVmg+|I4{cQGr^l}n2^d0Zz@t%{!nZxZ=q zQF5nQJPaNmu6(O%6ZWXuj4Y3h<@Grf{e{mGnk`k)S(`=U6_y#n3Qz6?w}~ps-}z>y z_t`+Q*)Xdh5O9QPCy(NXqvxA^GUyB_;El_~?Bt`%+Hb*_LrtHgbJYw=k143v@d|F= z{vuXJ3EX?q+(sOz^LM_NiCi9-h~7l8efc;+6GgMo%o;*(Ju2TYRYET>XVc?89Dwp% zpSUv`M;2;X*aJGu3Y2C&(YN%jmmBn-{jDbj7>Ig*nPg-6Mti|*qd?6ls)t@T&zfe} zla|p_!+AUc{_w6j04a)eG3Sq_z`;Pey-DbO|2*!U+ceE5e;$f>PdI_^>GFYs9m@tb(PmdRyAA|2WI_@-& zjQB>|9$h0Pi#E7p0&gDW(-d`P?U%%ryeWZ7Hy)#UL>Gd&-&d0*>Tol1Cyget9n^i( z6Dbya;zL2;;|}a%GpnlBm$}n1o*LGr^S%X`xU8Dzup5C2NafYUZto7Am08SovUti{ zY~eGQ=b7o=9fScfCxgJhTuMew@Fc6#+$gh<%csMEQFJm;q+U->9aI$hPFrW83jQb^ zNDPYsDAmkgl-z>pEnOYy)CYA9GQeT>F00s*C|ztu$;}i>*p+gm@0;kAkH0C{iefbB zK5%J&&Q+3=y)5y?%lWvS-J3`ipjc`ZL;;^t($IkXluxU z@h8T{Zklmtfs{AZ9C9@+R6N7eun;uW1G1aV zX{a*2s~2-g=%WT^1nW7#*BhOGgBZDNy~PiHC<}aMZO@M_xjD2yge1uq(_41Wi7KRT35nBeL> zd`)S$xn-`Zrtmm390%%yJn1}ZZPhz!E%i(uK5sg1^hvR5_lHAT++B2d1uc|9(Cu%9~7lO`?$}5r1UkNDr^hSm2(35YAI&!4Rv+aBgb&Y6k$|Zgu94JkUHC6o&P>RQ9^unN&xY*!l(yK>y}wBPuR(6*m93PLy3(?q_(QkFL<2#-leUYeuLQHr{u{6<5x`z z#xm{5_a&WfH~Xijs8M&eYaiW`T8!yO`Lm=w;CeY{#InP z9P##f^9M{8-mVLeq8@m@P@)lXIi3ezPe_;*X_U8Kc8eg(AWfJnIm#iW;MkOOdm_M| zHc(ICu*Z3vZg>Gy+wcUTna?qaBI%u6A5K@(?~YzIp4APye#cXT(ABI+#iv%XKZsgA zJNIZq?(x@b1J6Ib(*mJ)ozi2A>6N?>^+22DXp0t1E03pz@sR2a(lEH1_E=v+ zp7x#kh)HCDcgK6tsd`g7Ti`#D#;se+}`M+2~B>Nl1J`RYVuA!HvH>Lsa3i5-!!@M#0D8JHOAik z96!%rKi-!dsc+AGMQS)5yP*z>f&ai7@wpx@mEmFlJsmH7-0S!F0Rm$2ULv>+kgj)& zfsg90g&_(=27G+sq^c8Y+NL^(<~K;+>$!e^IeB;e8TEjpnMtA9_Rn$O@U9RB3ct&isD-;kT@a@)xh^%<3g^N4VheMpbtG4nzN zYo2AOJh-%#RB-G}opuVZ*O%s$!0K<8oNLxK`x(kzH@EHKp@~;~x(9Nu!VPivjU@6K z8_g2VV^R;5b1^G&e@F-lc*&aHlCV=Zuf9=_4IwTW6gtQ4g$YecY5&J1(d6B6?bF}8 zLg=O1RKXx^3C3D6XW2Umh^HbWh zPh>!sb#|XjjHn$)SOG<2oc!u|;oKntNb{Q zzC8VpR|FLvg4f6jRvUGPR;>5~aakR+!Fnsw)8LQD62jx}abO(3o%%NLdZBtI*p&%- z?zVS74Sg--22U|P%~jWa`Sm3?H}5mi*Z}SKtX`O~aQW}`(i(asS@s#~bu^vFd~Q1O zrrPzN95?i^()&BiVRfotY8X{(qiH}-!cxQuoTh+K_aH@cIYu30Z@L7t@5I^1Ss+(3 z?~E^q(N-H%TAV&7S1~ok%<9EvrSKNvLG3{2S>k8y<@d z)qTK`U1F!Y`MJsBzpjmS-0#cWEBtZN=^mXg`~4KXN9SqFHpBi{kfwGh-6AhFsR8wo zofW13QTz0%Ck-49oYDHu>Ge}O?C96*-{B6lq3NtXgSU80Syhpu5qC|ke5A_qZUf`Y zjj{)k{T8YCZC>4eBhojF{_uP^!m*bfR}=RLS4Z?BzeTAPqk8Njq;|| zj`yu;eNz^UJ;6lw4mks^f@AFOH4S*eOy}PVOb00UFMTPP@m;O@Pw=}JK9Iq4LP>*q z3${b)74@RA5XDuN8zG8^?lbwyjV%XNp1G}ls5Ujs%#?enxiG!>Cf1JJ;{u4|TC+Ei z4RViB`sd<2HQ;g&&(pWI1oY2_nSKNVcIcEKgOhM=g$raLz7TMw;^q7h-_E8WMHBF( zVPLc+y(gHM>AA5u&$Hz$HLgc-17cx0yb)jT-)K=h!o!pZ@bBGE>9{@w0_Z?Ywf;Qe zBA$z5sP^~rVNDX8o?AoxFaB?Mn^cauK|SWdNC5wXulL4&kfMYPJ#g(v^+O%f`%Lod zF~{4>jZ<1eh?$CWk85Wqw_4K!FBy&rsw><43Y&RTYP0zFBg}cAk(bK(RzIN@JNf@X zsG2vr|CE~d-PqH7Duf6W=4Y$ixodj&nL>oAF0Ex^=$YTx7nhqRyjaeO4LEGC&#ruExaDD!bL8~ zgMTY@bWL{oh7R^{O5P#2f4-MtG{d{T?2Gr;z^8bBH7W=XVG9L|kdLyAojBr^M>epQ zd&Fmbje#I=fybsqFqEo6wKnfzOY1HwO`*+7pS-eI?{cbMEK z;&zI+{B-<`4)XRZ-en^EoFo$`o@rNr@Aew=9}ttOHa_#rF*EGF2zQ13NzwNYhkNT^bxY*DgFLPt1-B$Op zIeLt*W4C8!U*EaW2)+GAdwxA5(pv0opMib(_iyn7u_VFUCk|@-;2w|jyD0yJ&8%Yc zu*L;x9_i|Sgu_#8_z94Ip7Hz*?C z+Uv-RnGP1H9t%G*yv}*jH{ZaWBSZ>;|3DlBwaM<$=7jykPT}B>&VZPML9w??@(<2!T9$ApHJSe-dIllnTWEgO)=j{%U7DJ>>b zdz&9Gs;gsO>#x0N+;Uy_4986oLLb@xWz60g5b_ZRrVX0Fo2OZHw|Nr5$_%hp!7^Y` zNQO3*{+~t%3S8uF7Qc&HzP|8^#^~O{`WBJ~^6Zsic-zl98DgkTlkH~yKptei809aYgdBbzjMiW5#BDP zA}X%id4)FF#)54d7$ic0a*it1Os>y_k*rzfEJiDBax&M#=-a}9J53Y|H960pO(poZ z43Vf0u8yr8ZWc4K{bA5cF{8U$yAZy5RZT7Dj{L)kics{#(<$Rc-*x+i0TXn)UlTon z9iOd=R^6>4yn~VYreLe+%2%$Ji;ng%dcK9Jp-jLD%?NA)*nu|GDE2i?swTgoATimk zsQUQ)%Qg%*5}QZ`M{>MedJlbjB92)37LmHK%B5F(FM`d-g}Kdc=vU;qxpu8Qdu8{* zL1z2K86KN+WGl1N{x*gN%x>)heyG6dK$mTr#662ZGA9ToIS)*-7LQ$Ala4MhucXAi zev9l18KLyzOc;A7*J5{oKFa+~;~^2tQ$u__6)JPmjkMvfyrw=S+!Ue8Oyn@Q^!{|? z_lZZP=WNV`1xn7h&x$dn&Gu6tq2;?E@AK%<&6>)?fNc?}mD^Z0FdPRzf3@6^%9C+H`)uP3CKjZQK6Ls!DQbFQ%; zMiI@&H8m^;z?X^eEw+g55iU zRj5Sa-L#I?FQqi@!1S0wzg57(cVZ{1Rcozt@Fo?(n^eK2$!SD9dqw2z_t6083foWh z)}X+YqejU=0bk?7&*+gABP_ImDI1stT~F1^HOXHE3Qbw)$XQEB@e8}2XOm~2=V*_6%ThLtw<2MF{}pGc z62s)PZFHn{PXw_0reCOQS=B<#KbfBYI}%C1Kuqa9yctNcPCQ~!95 zrgIhDC8xh5w0eB5foH7t`_rInf5T|`KVNXu4dBtjgAYufInq(>&8~g7;ml~TO|(sn zjeZYoCFCtu&E)gMVMeFEACb{WW2>4ndeQQ0`-4W?C^N?B+jT!SiYy+gL2>BpMvUir zxRB|*&V{-5A%~w<0uqdF&Q1(TSEc(u=FlJ561Ax}`4?Pn`QrWXEa!jm!=t!CD0<13 zLxX%=|LA*^u9DtPsoD6-#sh5?x$}eLv#xl|gn7H@p8#)03x>d0Ip*bD)7AJidlIA6 z+#=r1#XkA_;)x);UV3J$t|2&`{W~C42-XPy@772aeOZH~F`8)kM+1WB8LvxIkqLl@ zPaTu<+uomcf_XI^JbXM1%6{8y6Y zEztWC@%qLcQRy&vN; zcH^Nl^ZA>HKW+E*&9{mQ1SO?q`PnO-_j7|E40p-!)df^ZKRgxS*}D5@TY9u=R(kIJ zkH3csOy$U~10eQsyTJSU!EC@mEBNoIr`@eMDEQFg*`^9j-S}rysBb&vh|yi(XDU=A zlV~bqRRvu*FB-bIT<0}(RTdTzVNANJJkxtyg45bSNZR1ir%M}#Qnm!m(X#PH)zk*- zMZ4W22$6`Tr{s!miJv_-rHG0bc8*C%e&B;V9Ck*j_jzjADoCR06ocZ)mOh68NoX~z z33JV_;UnLY&fa)z13F?6jHdL{lRcD(2mQWcc^Q(P?WNKo=RXh#lZ?{0*E<$~62v7W z(I%zDPNSSSx~5Y4KrSSoSjFmKinbp_Przoxpj2R z!4vlC*AAgG7)=)IywF=zl6|<`M+Cv7&yPu*2$Cw`zmOHl!bvVg zyDh*XO6dM42JRg+ArnsVF>UwYmxOjUxkfjyRF%x1FLj6ph?{f^-x(c9P=&#Ik>h3n z_o8ipDdTF@BuQR%Lw;87cfpS0ob#BGGMa4j?N4jktC$xkL!m$J@~`9?Wg!R8z4QgAP?!eC3N4tq zID<#MPXR0{$7hpmJwJ(9cUdZ1ssx$0njiGIa&p!#`Vlu4+gs>ivR~ccFK;0{seb_; z|5J5oKU&%Jm)R|h)NiEUlG3iQ9f~`ukQC#V_yu<^MR_JJ&TU|PqdGDK_TXTCvN@d%$E{Ilve%T&zwbKMR(6si8k z-f?+21A@r%g##9!#+SS-LN*`I+?=MH4Z@CkV^0CFc8nLDWK6uXk-oMz;OGcGqC4lg z)IU`Cp_~dtkiXg!>+*cjA77Cy7TU*$qs(Ym@jY6k{P(?>HF^jtoQ#?7Ri!w0?fCzM z+955!4$3G=714k*5bErI48$|=4Hk{{Z^poIIW-{Ud0Fql%#+B{BG$5w>`Sk*N;spU zqK>M)y+RVl8>bJ4R2Fk5^WPywb4zd+zAGkxCH`OBB4MlLMkBdrYR-NYs}MGdS45Dv zKDNp53Yte&t>73Wn=|rPL51!*(p1wI8|%&84486t6JJJ-Nlm(|(CjA-kU*_$5_eZ%m zB?zm@i1-WVqv-lhz+rWJ)y@|mRwkO`ul_4~=}{Bzb(3(fw6d}{jif43JIqaxVPx?D zE5uHb`Lru6$-?+Ra`UFMhly}wBqK|?&6V^S33}&rZ5H4Zz)@#2O?C=RkZ!(Wr1|24 zL&|ap^kP5~U)KGC@W9NK$aVrgtFvPB{7YG^*0wVpxK%i{G*Tx5WSLN%F5{KSz_qWH zmyChz;D3%RuB$lBMRubm0(%Nh+b!`WcL`~`FC3p?0*>!x805kY5^b<)$o{Lqzbq9z zyMEv*(&FL!>7GWq?i*vHJ75oxkR4O7-Tp^ZL$7FCb%=+XMU#nsXW?g4nE6@kcF%LfoWo?bN{bbjxwO&GwZrH)R&-S{ z(>fUWl8wqr`;qR=w;#se*~s4qoVl7O$9+`NzB3$k)w4^nawj$*e@TnA^`nqVn{pd= zX|8n)1CG7c8uj0u-&S#hm%6#)5z1-UZjP&FS-RY?Eh!!dl+n)5^l@J_--kRRC3UO= zl2`jSUZcpycLe3}xvtVt8yd@(`aG%B{~8kf!J!zy12Rg!bq|%Z^hdr|y=5&Nl}5nt zI{?pGtJyF`x6W=;eE5SPRM6v3gH=h~KYjKJZV21RcIW4`D2AWNbn{Ke;i0H^JR*W3=w&`)qH?NNs`ZTNlB{}NnX0- zXP#}BZb+MTvXj|<;}7-a7d;*qga~!6x9zE+5*nmVXqMHDbO;K&qT_zzb~NB<$T#1V zqqW^V4f2QY_iR_>X??txeM|mVtHU`bM_Zo;=ltr{?ylhgbMk9{DJz!9y-2N~KaFRe zS6WrLgms9LMJ%F@X%P*?9#kDP9{3911y6E4y1lhfu7a~#IZ_0YD=oe7z9aX+ovnM= zc-khLzXUda)uFvp*i2sFZKPMCClvux>XsY8gncuoDY=$!synPEg0nHFE;(ah?@}=} zPeM}-wYGs86@g6q*DDL!tjJ9 znL+&eRo#+K2MGhW!Oo7HoK`{h2~aN=i|11#dRxRVnf-{O3(bl%^e24$Kt7Qk?#@9+KKLfO+8=fD}QL&-!FozETQCQm-S02Qg1K_86AKUm}*dT z9Bp;w3VhGN>)orf`#|<-7nQAC(rzx9Z-lo2)EX)D;N#YNl}0Oo{vIlFnkJXO_8{!K zZB==N3fa39QT<&`>o15;0WOFZ^?}35lI!koz+I8fn&9+m!;()lS^JQ;ICjIrLBqMK zD{EFjYEBeayn&$5mKe6t0pD{y>CXFC@rFEY>7Sd)WaxYqL%g*vd~uv(ubOqm)BN*J+#C_AO!`73g1Z}G$qY-cF+%*t%T2~P)!_M4M0$dT87uuxk9!DTWu)$ z=(@%EM3~^%)(&bpVv`6#gHxdTduf&Jtb)$}PdQTd#a_@r#7;Eeph@_C>J_e3>OpLB z{vbOj|1vI^of(eTr2~0Rr=NZplo@Gu-N&uU!NkvB5d$-vB+xVf499o;%FepMKhG-c zbqkPZ@cRSR@yOYzNFKEFhaY4sk>MEXS{K3q{G?^)vlM#^P+V*GQmjgpB)XU-fL9Qm zXu)SRfuRf}KV3TL`KO?GRtEp;4Jr5XGla}O&F2Y0FH=VE>nD|COLABse+pnBKXY%# zOUG)#q3?dm{Utp+@(^(MDwh0y2G~IVsuj4X_OJ``4A>E~$I5#iJ%trg&}Go{kV4%9 z^)sc*6QQK`O2^l1N{hA@5WR_j^)COv(LHXWKmKJcXw{Sbzrjn$U#?BYioa#wKVaL- zauBQG4#%8#q4-zw6Bp)+14pld8rq-P^8W5xlAb?u*mu005XTC2j{V>U=dJ=(It~Kikn~^NvF2-qbHJ@_V zh{7yS@zo$Fd5IvE%?E|zLn;z)!pnKM$mw;=z6~^vc@kvoqh!jO1-Q(A^+*5;b*evctlk^#=ThLW^UM8dY2)s6pUXo}t2g-hOFA*nGOoeGq+(L*LqA9LSs~(V=4rQWMw~ z40LxhTw00|zIk|MdYaeM*3vT2Rg^!VUb>yKus%x|&%XpY@FmCnW<39b3bcSEFxeQ3 zs6XCz+V8symKIW31S|up;{?Jfhy{-^DjT#}6IyJ2ubcRUm$)F!K>>~0tAE!g*Q@WH zf=vTo6$I8pWlLQ9}uPMtgD(BL6rbR z{hf@84$f<;E!q*otLGWs|K2MRG(d?E2TFu8r9VrAWQO68+%hIZO+28UrrHBkBi1r`RDe{H_4Kg>-XlqIOmZ!!hEn@hj5 zyM3USl7+`v?<@a_!1XG1_APdoTj5F-np+s*mK#f8>ze^GODzD8!C zq|_iZSM&aVmbc*f@aKyoKM~LiITgrx{rCYloe*K~rl4)}hm+t3@AscQ2xe|89r zuHyAB6(>AAzuxAZz0kwKUM|kJk7R6iUM4hlvPc z+yxTQM&iQrh_jdRwAtu~f|3ezh+d;xK7@S0vgIv}%Qh9ouLVW;Z7lqBfvDzovX7$P z*3csK&PQ`|bL&F8YwjkXAz-nJ8G4QH94GXU1_yp)RBf$VfdnW0yT<1pQe*o7R1cII zu5Nq@%}ab$#zztm)&F7h_?4xlXF=O{Z8sD9w>)c8`{xLm@Mxb>JZ7Y;{Nup^GI9tr zd#K{xqY@3*CxfmOGh1rR2U%KGgRBH4%=ZUbiEN4;4zo4VVqrDJVuz-%t8}U2daHA3 z5_;p=N9D`OFK!a~AM>&}KV10~Rf_7TMPP@{qld@?Yu@ZrW=PuKd2tK0Z2Za%KHjre z#P$}VzmOv&fLIx@t3;7SUtXbmxU~fisMaYQiABV(=*N{ScuEOG?j9O~louDjQ^O6q zRGW)gbCLF~1Lix2mLr3MWrrGipt&<>j7G8)3?^j%fFgk<5|E@5C7Cw5G#}zN4G2v- z-_sR_RZv84*}2Su$u8hN_4tlJ#m5uDqN_0q!+d*9I)89l{O)uSB=`V~q(E~ET(5z6 zqiM+HKgAd*0J@@3#r={NMrk3A{M_oEFKLcw^n}On=jc+qxwJ`#v3u|~q8-%K9NZT` z$gS7voN--eK!g{t{sTlot)HEH88h9yyHF=|dj7pa>P zoBhL0C$}A*0;+U}ur3p&7Q3gZ@G0Vf4ssb*Tc6{a8- z>D6r)%Q=1!mzQ!78M|43II1(=_b|)0<{xQarFim822U*tl&T=pB4^E(cpZKu9)6>pw4KxyKpJ$cv*N8Om&hE--0I6T;y_0h-p|rv@^`a+GdGz}rBeHs8C)8)@jRrz9^M<$l@Z_cAIStbO{PCf>>`aOuF2y-f~&~HYQGaD#uD;O-$v@YUgt+ul3h8;~&-re2890#FUo!ec)S%VAWw z(&;RHGDwgb-h$@yGbm#PJ_CrV^g20~OB+`yTRDdpl-b;`apxeC6(n3;#fGaovWh)=NL0=oS z+>A3Yv-td7xE}}`cn$rfc4+I*0lOVw7CdLxghj~?Fz*K<&$mPP=L3|K{*0cclLcjp zoiK#Fa}J$v{6In1-E26nV0@6dI_J#$?wp+Sc|G}O%E~;o;bIf*h;KIvUf6pS%;>b2 z?7$P-QjanqC<0CWI1Wq_iq=kG!S0%#*3(SU{5 zp!#OklW4NP_K}gaYicsZ{ zXzkRqsk3e-@0z98QX2EwA(;b>1|UvGfL3_PrNLlDb!#N6c-XDKPqWRuzuBm%v2kcT zDQRqNBtT(!A?Wkf*##a#Z$ab+p2epUumLPeZ*1kJDW#2HZT>UHvlV&UoB5dbMJ~{-fg}c-x37QVbyhN}W{r|B5 z{T!ffvz#oMjV%_&U}~Fcv1?iVzJFA3TDfALA58!8w~Es4!Jkb?N9>%x2de}$9^uG@RfPAKsj;FR5%3DNTY z?8#Mp|D#vwY5Z=U1~*mVwzz71AVK37%@)N4NF^9`>vz^R9sJPqH>nV5E(f=N41`y= zV^-D-t9ObK;HlKo`MHgOCvwKBM}ja}gbE$m{11MUZe80WDoA;S*4%!0_+ZWuh)W%- zD+usCEZ0K!$zn<{r$dv};7?9&uxfzN-P-nRs`8T-V*tt}5Ldt$43EKU(5b6k>W^h) ziIL)I*^nK^?GpHh3=Le&;4Y(IczT%-(kJdbJH6(;K@NZDX<$30e%#aG>G908!0tqq zh*kZ=kf8Y8JDyHM(Evi62`MFE6L*t^14MFzK@65p>Q$wSSMrcAN z7~R8j_CqT6@b0OE7X*fh6aOs4Dh|Ev->)iWcJAHFjGn{m0E8%Zw*qi#zIMiJbjF|FPI;(}oWB zEv@8tRSrxEytpPovbR;aIFHP4Qag-%fvs@wNs4`*w}~P3{G!&z6Gfgj{YwvXJ)Aw< zF$#uYwA439(^sfM#3rITa2Zt_EP3h7#YYwRTrrPf4;M?}T-{xRN}DfH@kNxK%Lt2I z`HG)i*}81sneba=9oyqyP)&`x=r9rRlgPRo)u7i{q;{UDB0l0>xN8eI-?jRFZxUk` zbta?Dsx1J;XTtsT%jTYEF_!c9;t{4yTd4RN0VmslO#Mp%YEOnd%lkjlAKd!JDMfX( zVVrCR&mhPIl&5$1B4LtdpHqCHXCQL|7}NaP<$P(uhZ)^H5|x7N8{aEetBdA%{Yc6e z+twP+lV2TNjv&lFRVFv?4LSaLVq9U{2)1LrwmWNkDB7+pIRAzzSOV5{emQ4RL&9`- z&B#G^JyBn~=r?qrTGSpJIX@KkWq9sjmUB?~QqEcfcGcaw>;v2*neAg-b;@LZRBYNl z9l4%TC^SR0=>7KbuIV9}(YuPf|1Oikb#PkBVcYw9(#_a*tAIN0gVX#Sp5518?fw8g zV9kjJlbYO6MaM0~*oPrjIz#4}Sl!_+MpV_70xiS)tNO)GHN8_B*RM}KS*zYgNK+qD zd=x}*^FI{us53^Q5@6qt6kqrOKB)%$TGr<dXcF6jWF+zEdD_y~5T-V#5#r`J~EV+=+WBRywbZYgbncm-FN5Jz5=)2Nv&2V?X4k9c@V3c)71w{ zNIXp#*iWcKbM{YrKi^?-6)XxNieE?}nUrT!sR|cDzk}Kvi4bTImEC?F@2kweu953( z8<5teajibRbJu3xx*D?Z<}8OgSED05&G6F$YtSU#5%_oxPLJu84+bMjwz~w%*2frK z{nTZJjGWgUDU@TE3nklko_nB_S~Wm<&5woi_VLVOv(Z)KA=kxTt@6;cG^<>I(R1uJ zQA}#O`~erA)=pm&sGY*L&~#%5YnyvZQDW>J|2tf*zQli3@^j|DL29D9)?5dsY+@90 z@8X6b)0f9ep^AwMfjEB~Tm)h&{N?pfB!9IlRfeQ z#Si)eq!h58d2>Sit^8L<06ld9z&}i1jxj#Z%)(B#WL5otbWm3K$}*Jmqp zYrVypiF^9Tu^S!a!)prCe(zQz2|Mj93%sh9b@&Jo{A}P7oW|c4k~wqc5aezIX92;y z_e!BAJwGlAnRm`)Kj=+FhqsS5|BW_qY}m!Qp86{`OblxFz{a1Q*r{@7007)*V4Es4 z?J#i-sKlB^e#5330>N;yh}Q6-X_`{qKwsnM>=p0#*(Te|Xfu>aFq5Pa-g#>9UqORv zm_R7(yk`UX-}VCdgj{u+|_p zgM4vu9l9!kS?s3RC-duUrM38-sEEXWzN{jW4L}EO03Er?v&=-2Fg6Pu5_1j~Vg|P5 z7XyTB$70q-LhP#R9D{0Z+oZiUZMUuryVp&nYh204lW6kW3q8d-=Zo+ zJA304KBoP(@z!yX-f(k+H9;_@3>&}VaI}PEQl1`z!>itt^>)3~h8Fs^q33`@o2QrF zvDiZ0_8V%*tUYtA#1d~JS#^#xDL-9d+6^wFY08g`CwB%;D>_1`tw9w`H(1ma3Y-{7 zWoegYV#G{mX`0J^|9&&IwjRMNEbmiPyb5D07y+v{uHBd#{uaj!ZvuWs-xB{7Kgc8w z&mo{1Ut#$BpKCeKrYzUb0b(pW|3tW7>>)GuJA1$HN@Iq7L*3jCLfk@S#%2$`3U6*M zI_0@NqHn+TKK@#Z+Yfx=R{vZ?|62KpGF7}AIYbu9c0xkW4LprXvBbn@<~8~!=Q@Qf z#->&RuJ|N5q2DEb#;(G3H!?ii` z^u}EjgXZ&?L(R&B%uUBxfm*_D1UHsTq7{eW93f-F<2^OI(XN>aD>z`f)mYDFV<6k5 zZ)n1Gy>P9;uc@5s&TthqD{|FF@6wVJKwA6R14oR9YNeQkY(wmK?hk(r@5J6K92Hn~ zvJU-^pB96;)smRinvaj0LRW8n`P>;FzUeUVM5<)tX4Zwewv!WPIN9ohm)%dP5eHU0^7m{8{_6C00GF=CyJQ5csTh~va-Wnh#khH9K&n+D#f-TdpseM@M6!QiWv39UzWwkE$T{cT2y zA%H8mYo6{<$5C>e&OqPYaznBfKt}Rm72UsjW_}p7c zj@0TC5%>oOw(H3NtP1wvyiv%i=Ut@B>@^|h`N*7+&n`1`-NOVFQ9fBFZ9IR^Hjcu9 z&i%BML=O8W&UjmT2ubns`>$&p(R|cre#=dQrkrM>BOV?NsK>%H((R)2?LVK07B~6Q3K^!HHU6rO^v`}e3!V8RJH8p4$b>W;y}J-_{cUEMKz#i;{#BCi~gkR|vt-i)>3DA|&E$YYEi#|htF zc4KFpy#=j9yDMpb_3?o@6C@m}ikB9tf_c2BA!vndG2HXHN!N^p{waEqdy-5lCl=i4=%Z?qearhMNNf31*F;f$C9(Vx~s6JoVLzM$8_>P#M2LSdsm!Mm)R3N6UA}O~$ zD?wF-j_2Qgptzle70eX@f@9grkGrkbtyPsrmjep*F0>vucBE<5iin-x%#VIhczABv z!)@cp^Ojtdu$7hNmA0cxfpgNH@0xvaE1DlS4gGd|s05E{Dqx^$j}`(Nbr8lg=zTq? zhZI>Py3F+%BsZOE1+W&n)^5grcjSNemWl#8_-JAV57W}aR20J;CrBXr^OFoUEDfTu zVeKf>+M}59{eJ%ZM;%{(>1I2>0rtjYRbkBL~p z5)!f5e()~JxQ;S)}6`+ z+5{n)HXhlja{-*p45GG|g>*!}oM{{UmTmHU^H}M{?>qT;9&1mEnAuV z8h9}9r>twv#V37-@fD@V^R!aaU$BOz*%H2w0O(Mh??w91VUU{#uc+q z!efIJU!NN-*b$jP{nnJXTZyQEueO3Ev2yhbF1d^+(g_5tT*|NcEb2t&h2l~Iq_nvc zJu|V^^<-_-MA|!%)+e{5R=^nBs#rVNLV z-UYcFQ|T;=-Mo~rh2I89kb%bA076EsdFaD`!DxwIlp9Xm4iUYyu-HJzuAU3?+b{z{ z4>*@GWZ5DFH&$S^LGY~UgXL1HB#eN^@Z^;8Ct1gf?$aG_zGmmci3VH)`$g`yct40& z!^6ngt3Zy}9c%!iw#w1LqS5@Gi>LHN7tXyF2M$>wsK61=&^pc+Se?e=3nzKtcOpCF z--8iV)5Vw>2q$3CqP(31Y^0uSCGq=P)pyQu0N?4i^aD@Md8Ez#jHUuZZ}7!Adj-6S zj{8^8;-dL848zn!o=uf4m-n+Qvuu(d$Z!8ve>X=KFgA)XP=KsWR4c$jh5bwb^R7?< zw!(h3sBMpI4$sFiQqiBb0Iwwzj!Vx*vb4121wGGb6=&aOZ5-p(llTn!`deyYzp z1l}mgRIwZ;XL@GJ}5 zJAtkA`cS;*LjVOVH%`B80)8x5=O0boszX}?^Wg>EIbQ+8oE{F-kLz)bIMOE_t|^LV_Kg3C1ndfT0r_T6;DwM~ z!Lm_WMD!QH{aLV0jKk>K3qf5hZ*hr*Bm(RLoY`~j9*K9^8nDD;TPPF3i*jyuJ*Bpe z=@!MjaoXi)j?Hya*pDRKfsmiR2Sq;wO_N8rjL5XKmT)#!rz7zCnF)@pMVE}x6TlC4mU9rqR79=hB7 zgX6D@3l6eGkbFpk=!!q1=pC@}DD)LwJAsy(Lo2!PML929UX7_2IEn+kcU@0S|?9oez7eQnVG+vnnMeNk~0vId?w;U&k3iT@$_; zL&yrme?S5ygF~l}2828dzrzFxj?oNTwvq%@FVbFbs&A^cGjPYm9%AH7`jc2W2xuLr zl3w}!2F$~Op-JT!C$Z?N{oux!%1!+xTnx&*9zB0+Wt`XS$Bu0P)WP+O5wL|?lHx_% z9jO(_lR3CPG(;9*9r6pjw37-5hG_^+5d~AzN6lkcSV~g8!TzQc{qj#R#u_C;vyD?P_H2 zH32Elyq(>GjQlBJo}Zw%aJ2b;&AR<;$n9oNpem-?+|K`R|-KqXF9Q&Sa7`GEofkGm@Fq5I9< zSKilWZI&VRy$`2SG$)^SmGQQPPs3W^|#AV@yy&@J5-;LzPE(hbsS z0MgP8(%sz%0@4B!QbQvQ-8FFbfciY|`+dLjJ7@prFwTANwO3s0T5Inu!P`ohdsR%i zcBbY>Am8@DrC|o>UV;`@ho9!w$Ti%rQH84HmwExL@*+-QDr=IXqU8X3;r(k66PeJC zj5!iwD)p2aGQKI>3tNyO+YT8?PK@IIbu`#)5ZTtGkh_SuQY(b)tK=79vL zf1yTzg)#IRJ%loQ(n>SUc(?Yg=v(NWJK%5LucZYAGWyg>L9bk@QLPiI5+xoWmjcKk zYj|6EamHGSqXE*7yUtMbYshv6jb&l zcnfg0u=e?C>@YLdrC>mxUha&Qrfleo1QMtDbmI$l-h%;t`@%#UcM%usv)>kE6vHvj zbir+MP7IJ=n5eUj{BGUp#I)Wyc?(G4#6l(5IXDALU)YhnOl2nf)$`j;(a|U2{B_wx zH$nHV^kroM_-vIxAA~!#_4D95b{Litc=5A5>o5$8lOA6bF%W?u4+OD_KQ_*AH2np@ zj{$aEj2D$B6nVqCc?|Y$c+!RCTk^(AJ~Z@Qv7bNO0w;!CjEE@TGI!UE?+Oh&zX1~@ zHPTaa;X)yrepyfNS)f4k0xKr~Y#fx5&#&V_vYa~R<@Jv1T8ka`o)@1E*S_kH$p2l` z0NH01@|b=$W{-Xr1j{?3x4<^PoSCsKca30_;7_w44=x^z9mZCQF5hWaQ1j&x+1sS& zu~lSfpI4ynAXfr7E&b6s`b+uor`7I?N*(Qk<3dst&shQzc@eg?%#BO~KI?~zuBHlY z8|e17$`ePM;5H}smWMy4(0$nReUmUC@&6?8U6Ij07+&4ONBFF@w;ECSzp;kN&EA?BuiSvDXU=E*i4v%FaEIA&TQt%xfuE7$oj()<)g+p!qyx#>q zNGe?3&~4odnBWbylS=!_yi5xsspn4%}XdXaAMvtDrLB-7jZva+3?aK5eZg96Fx}~ zXz=t>{>{G?QC{Qnh#Vj~tm`AJSZN_?C^>jPA7H1YN^p_wR<~Ert3tj#?BwW51w5;+ zSQ!dhIt-RL>I^MhES%LeM=InAeToAg$;wb!xX>HWKr6QU^g_ippoWo5lV>wal?)wwkS86%cjKs9fi=9EDjEN44S%a) z?KN?ct?2M06BIT2YrJxt24eNDq}tg7<8lpU-epMWiv3rj9ANL~-v!jc2PY;x@?G)| z#(JkNlM$T$74=LWeUPY8S26_9D+%F`Ogbz7PtiI|SlO9rH$K$b7{gocM+F>Qn?N~b zj~`g&$(fCtzi%vQ+BE%^Cf{XEE)CMIi{VKOHiUw$dYAuVdG`T9lzz1msA@lx!x)eC zajWu91d>Ku_Q zd$y(_7kl{-kv3yHbPA?D(!T&-=Ka6X^UyYE54TSL8iWRQ92D?zRj4w-u9N?q-^Llu z|2@ZYcRyd@E;AHO6U8OQ@MLA|IK;~;hmxIM=2k@a=h)EY#Rb|wp7!)?y~LPsy?hUd z45%Oe>u(4y%14kEdid=?fa5*fmPb;7T+1pvnE#dQ1xU!hIU7OE)e7u`4GW?tM-{hI z{?c@LKLEAy7&RWH(uPHz+V!o7%woFp2fA}nTz(Ewm>Nf`{rD#s@}bodI0&A0&zHiB zez($xqx$fH4P^l#OYk0~L~}WIt8S~EE)tIGoeWcmIvi-th3o7HBs?#Si!=OMcTM{v zZl9U&YDXps2H2$-$H#fNvE_aFG#W`assymQj}0zO2xPMR_D$<2;|#Jq8&_9v)v@#t zqrMrC_GXg;lmMtTFj=Sq`$pWpffOiJ-T;7mx2f5xS9{Ou%3|<;w%nmAQZHQT+AYR7G4`KyKvO4pZKY9-;^10&_0S&0i^OK&J zp#h_pSC&6HI<=$SVE7wAPnKn`%4j$sG`Av5BT3S+*C(qu z*Q;h$MjPCP>!!*n2U0P?uPb)xv+XHm(f&TfuIb}(uH2OBU#oBX*BCvE8DWo#uRvTO zm-Aq=$xOJ5qM$6zE_sI?W>uqbJiE2A`woTbWMn`?mktVpo`V_?%F%eP)JlCbAkLTJ z11|YOTr2~EN}YWEe~Upx(7!H?#hwzdQ6NtqUI=J9hidqoumf?9h5vsH!zmYF2J$GS zxL_R|t%e$4Vn+W%bm9LI-Dx&-Ygfr#wCdJ@G5D_DT(SIMTJ#%G{jvOMUOc;xIZHpn z5PaEE1PaLiA{mgjU}0(j3rtn2U^4umRx8OiBXZ$HJwx{T<)(fbHva}?7Y*%y9rh;E z2SnDL9d%=Lb>9*t*rh1K*shFc@?dfhH-yUCaU4q$fG9f1&4peM>)O2Yvu* zPN1Ztrs_-_U<_pc8Fc;C}X^JiLi;U3>?<A)Nf&=LYq0uigId*+HgmjSBO> zY3Eu}PklUfV>G{NXU32!3F$3-@tP2#FwnDZ^0~3EkQRK9qlH2@-SKyKFoJo+wfy0y zuUyRF$8(?y%`_elbfnq-va{U@h_0Nzxiu5R7$R`=2E54Q61!HR?-uMY%wb^?8`HUU zlo!9P^EIB=k(4*Yp?ma_&jp(mocVMPkmiwD@eWt)F}0!%F2FM#6m$xuY69Y*nTS$D z)LiQw?kM<$&#oxQiYjFi04fz>@w@JfM*wQ|0Q*#GdI+Ne^ew@2g-h2ygA@>qV|#`p z7G@TFNm}W=kmTui!2b(Hrv8o13ek=U<7hfR#2X{UBQ!{yM^yd+@GWi zW_%t)?J5K%ly85tfd7{`{kLkL75$7(OWA)wVtDP6ih5+)?Aws~*Ntvc|J5^3v0pq> zE~8lBOn`?PqJi{KSQ1Jo-qK)+r7Tp5b|NS5pju zF0Dsjk;plDc;4nH{!*ZydH*IGp!@DWJ~Yc1m4_WK8-6_>t`@!^@N*RYR|+t#JeJp68th#X&?ti%L`s&J zs}IR*=HhnpW$%N?rt~+#y!^tC4|LZ@G?51fBK9ky6H4J}g4!EAC*W_77=MR)0Y_KY zGv&E_LJ#6Tp<0d_`?WI38z>l+;)tz=>ISwMu71vk-gJX5`tv@jit)#<5p(xD?D}rX zpv9PJLVr#aKhtdK2Uk#OKx5KaK^<;Ga9`~B5V6dBTEUV)6eXW+#sb7UYd}LEG4o@~MLz39c-p-h)k;bD zJf~o8=e^(Q-y584C8S={|h?5F15VpPs|rrJxVok-K^~qW*@OI zZhAir?Nd9ifo$`iO014TpXY~+_o!l1=0_`1BObqA2z(di{7fYRK683hcN)tr<-Fk4 zHobID_-LW?<($?L%uD`Er}i6Lgdr^#4Fpje$SJ`pAzs4%0Q+)1AP^*#a)^f0b6Ef2i_{A<02u0Hj>cLIIy@Y+v;SnRZ=nZ%y7KG>iBcvVn(Jx*qlM~6 zj~gA5T#vgB#2j1l-w!;2Km@N!r%A6$Mg6?v`~2OXXX(hFx|eH%qw7n5CrCkRA>7Hicz z`0}m~klsBux+9DQ@yvcP5q3m0~mJc*$eGR-<)m!Y;{d zoQ=6{!U9}gr-Kz8nUD7h^%JO}!xn!!ro5rGr|S%K+4OT+3{T+CoU#HF+0vJpRxh7fq~?XMb_Za9Q6v0I80X2Frq1`;;_MT@OwjyZ z*!FS9-R*h3;M?8A3Y4C~Le8(P+}$?>f9}LEcMhxLVvB(~antL^;(spzfE3XN6)vDw zrQjW~f_KBuepTb}z{9;m^zM(9@{ioLtX8J)*v|SvKWh=)D$t4X)^uW>wq>1e96=J9 z?>26Ry{_EPhd-kE{&D4SZLNA2E`=%+ES{=9jbcG~V8@@Kn6~T>W(j!o-*w6JrVD8{ z(ja&NfkYF7tEoEmQ{?1O)AZajT&oiXD#xeI%TPZe-3iX-$Rc$+Q+=oU{w^~)1$Kzf z!nAgX9B4}aJSgDif2XCxzaad@{~g*i78WJGfFzb5;^J+Z z(uy^=fF%j4290kZ<(&`dS=u_eyKGm=*LA!#WSSIDnor&oQO*k{+Lbx z`~R5B=~wH4o20c*@gP>l7rq?QYS*;Qng8MfrLe?=!^5kOp1-$VLY~t!x-5Jkb(t~d zaXZGJ$@>x(EFgDw@^KYJh0`zf9?(*XllWi5x89+7-dG|UqxQOCz^e&6u9N!nWKW#! zKHt5@#{Hq%uyWVnoH`3OE$qIVo2(^e#+ml!8FN4HNxMqYbbU`GxSDwN?F;J?{7SfW zNt$ICcE;@fhGVu(bI=m+Tcw;aTpe|;ckfnMjf$j%pNBF8cd{{MU#vlar{4N&Oe=~j zMayUFsoDatx1d^~pmPAdX0LO8xtbcjukdhmo>iJhbMtEi^7$b={mC;Gq%Nm>6i_{B zqsc=)>QcC?B}7|T|3)LxW#tA?%bcs5g=gC{Uyj}%kcP$y+GT#=n&73uxeAd;G{Jcy z7d`Dp*#+An=ec+dmRmozyBwVunE@C%Q9;gZ;04~aTeoyx?;ANTm6*j)T6YxlzZJW* z@>HhY#OrY;?aY``PeKey_;ca4Yp_(#YqHVYV=OmYa+!Gx3=8Y5-kVPl(H62*h+q6V zu%F^5ZznhN@kb}6FK@C1>>mccrh1dJUum5*R@3$5s#}h@`4LYqXC-W=Tt~9;DL86w z@jX0r-;}wF*?lu0-f@fjXWp0or6huEk>xW?iqJKRdbdw(zZ{*i{rxaV(VgwP zAt#lv;{B0ga9?FOcKe2RAY-J`05ot}A>z4eU?f!c(F#+%tkZzQ%WHGJZ(6=>H;gV`%NkRppvc7$zaEQ9y3M*5uJEblZrX_pP` z!YVStw&Uc+OSNx>>z&VV&G$qFbrcgOMh<35-{~dhKN@}Xeo(WvAPU`Kl6u^d@1L6T z_d4M1b%U}I0_o{AHqC!#pyTMLeB28^Yy9eJE6{M?a{Y_Kptq`H{+jsS;yrEp;+Izy zeKqwAdTA{Q{m06j8U@>eSHxK6F zXG5W%xwcaE6P7qvTz&-XXxCkoG`{MLC;G3f>E;CkpE8-lci`1_p; z+9V=n;b(i!ZhewYw$fB|ODkUuO6#1*3pq&h(?p0J8*?_hCQBrFCwt`v1eNKrIMs>F z>C^4ZnX?qf%RPZVz8p;kYD`6UkET432beHD?q0&twZq`^omxwkKtbO>U-Gn;Q?TS{ zbp$#EDS8^75{8n+T;G_J|0+|vL&F=DNG)V`-EkL12T&!-Xb$eJ*{v^Gu1FG}1@G~F zUu6S^3USaa7;s(RMF93N2?{)2)nmq5x+}lv^`T=W{@bph5iO%((7S7TPH)qAu4KTF zhtP0jJByZja6_4v)1Py#yP&5`VBF*rhM>eWX8G4G=Xx(TrN~`Lye~A5CyPja#8oKK zLI0G1Kt~Y>!VNi1>w54L+=H%0_e0p9i0s*)lKwpn0#R1D{e=h!p(;fKpT7A*Kbd;$ z(<=-cT}wzSCz0knJBXxj^g<^yUU-~&y|&T<599&|D9$^QI)>vc$ne4Oc%D7_V+A30 z-@tzk*gW%F!1sF0`-;bxv%8tb*qo;Q$DY4nkLrDrb-8rM0`s9MWY&ISUoZemU8M}- zvl;^pk5utq({^1rvL@)V{z}rh^laVXL9v|)jjjH}HumD*D)3>JR|C10!E40DMxC%P z$G0AzN{aocr6~SKzNN3(;I#dXKZ`4Z2ki1-Zmzw;UF-5rT<{l>+u-sq&yFX*wZ5t5 zdp_A?E)OG?2CH9bb$csa+lQ&5*9`)D4Y>jQT|Me1)JNoFzBrP6_eF*#y_F?*fkaXE zW7@{~dG*T-;eZvU!n7br4O$Um5oFzSr^OAOu=z`^IQ>PmHdD5yu8<#gqPg4=R8R`<@c^ok+Js;z5nbS zLE38fM+7=)vN~L@mp7_ke5OM~1NPE7$tv7@z2k0u@ljhq`OdxS0#f+T|06K`7q4VU zPtumh3DN_Q{606OOg3LR>f`boTl2O8^V;gH?#E^Fw>FSTT9XmXb_WfyNkf5yCT}}( zrlkzi`NeNCdPPuMJB3y+v>SvNYS2b=!y*rutUa1P^k*b28h6`*{f0U%3c_};c+B;A zeT~)jZIa`RRJBSS=tkD|%yMOeZhE-K8?04P=&Sy?HL8sAN-UjbiYm4uT5&^8D)L@S zS~BsalboCb<$DaHDtg%0ZnQjt`#FN*rHyL{{0%=X@8 zP#OPO4o_=v-`u9`#a<9#<2z;e7+s*7%#$Ov%7WnqtU@NyYzE^Zt8R)exddEVL2(fxzJa=La*zCLE0}DU#qSop2uR=FpGdE>z*3n?N!!AH z3f@VVm4W)sxMkE1k7h(!hmEXe!fU2J&cN@S=pp}PiIId_;M@6Stz}yGQC)-$l6>RW zGdR4K<{aBGv7KrKOllQ$CK;hJxy`Bv6o-jwwXYQ6DW^FMghR~dz9r9&RqeDC6ncwG zw&$v3=%jB(ynbl>fX?MWl+gRZtJoZt+-3nrFMXz{t!oRI$q&4km1(BNuZNH5zEWhy zE;3QSccst#6UMOoURotG=AJDn)cKjB%gJEvH1D2)H4$IQ=|DV_8%p2KmwShUlF zA_NtOg{lsMU+?QB-JKkJ$|C=*C|-i^>A1Z{s#;lN-8a?yk8;&E%&LDOPD4XBn1q1x zJ8UyVJX|9Y9>4`4&x#S9=vv0yJ!{Li{}j2ObVS~bsUR#|aG57$yeE*cy>0nzghQD& zoX#PHbH(I`+^^h|dW^1~51liEop>{;R&?}!j0A0LwRie|i zx6Ci+pAmbvg)t>XIps;XI<%Bm(aGgkwd9sYhyTO1UFWrwN|nBW4UTSS2e1)vS)Z(E)=vj%(9yv%(=_$)@mj0PNsaTz5^MxN;DtI_HV8! zd7sXLU4eIX_#rdYH?%B2?K=$SHzA|?3Kn^&sCxHAvgsF4cSVa)d$JK#roDT^_bJ-y zRB1~WPb9b8mRmcXjhXTp|FDOlB65?7qP|_F+Rp;jN0S7^M|+AhB-sI+od_0d6qqs% z^c?5neD*!M*jDxq<`4^mxADSEcZCLhtJEb&34S5^I{qjQ#kJo>Snz=g!SD16A`;{< zM^;ix>d|m6XxzA8aypCI_sy3u_%29J?UNKbiW*J{qQNG;OJovgXn$O36JG|%J`WCav??A7G)bfQelqH%}G*mbuQ zuzCT9406V-$m0}>AN=_r=vQsVaVV9hM;WbGw^JkE9B)-eJmd?;y8=P3ZMF$BjlOVV`h&+ZOd^j9To2azwgmT!EaY;N{AVK>#T|!-*A2#jIMr^;i8^_!x|tC z$0=dgCkIMHH4qRoa*G?;XT~}xO;giLbxWD1Ep}mOT(|zIF`3A-y%+CB;t_B98tz+p zLUPk3YNh{8+@h)e>sbcVzuEe+iFiKn0)(j5f)B$(A{-z`MA1ej#|bzT7|626uy%IR z(FX?Q6E(B&@3Av;bJ=*L^oomf$N061XpN6r9yv*%LG5 z4zK$J6&s+W^a_dCW?*FQW`Lb&IZZKa2W$c&@MUdpx7x|-nd@M;pw=2^$hX(vl5D-M z{Jsi-zB!${B7Ww?PnF_~Mg0w{%x7bb2bnAd$JzfiFyrU{F)$W^S$3Ec_2|oK6No4M zH{s%y&g-A6ZmCd!d>iCPU=UGuT6RvHCVx3>P7d21&SmcUPr82g3%H-tDYud(Htq1A z!ERD-OfkQhu?*s*ex7{5InXH-1!=|EAKWOX#=|(}td!08RL)5{aJ<7*p}uQDoc zY=p!)O02Tj=U~`W@{HJ<`xD~muv5GgV3v4T7`649w!nH^DK3US2VE@fZ(z^3^IwJo zqN9;5_Y}LSCgpc2L5Eib*chU7t7*z5{ookpw3a@%Js~d*Xk0+V9O@|CnzDUqar`4e zu6DWfAtw^QWpUVWe27>Z%BnHMt5VKlHvcqwH$^L)At7J(m5*JuIV>5b>sRqJ2vHdY zT+W*UlS28=LQFoyui*?4l1krr;@R&S6GoAd#SjQ4UOqnNOS^S!d8!3p*GU3~FaS0>(e`o6 z!+ev!=nI%CLfXRDxbC90dFiTE1J|YQz37EbI^KA+sXhyQw* zh06n}8h^BG9gYD8@!_opcymqrglUzd(Cd)F6<1%)c`tutdg;@|HjHc?x%(9(J1cC> zV>5&8w(+sDz2m7~mG2lNX_(qFa)T(1$4ysO{svHez$6ND4? zY6ZPQfB@@_D38gxV&S@!Nx6d1kmcu2WNmtS`eUlxrHss6YUIW`8VZ=b$B}mlU~ozt zjUZhf>)TgJ|0N@SuEbQ z<(2iF-hDbfFwT|UYT9k{<}ax`jrZTmmFJAC91(~E$}ebpFi;g#7D2unbd1twp+J^R zG%RF|h4G&ewH8$+7)quSXWlCZ1)cky50-AO)mS?-EjtLePKrcQt(-17b4@*{?b=FU zCW}m0_Mii_yQmE?Tg`#==Jpbr++?4F{{1g+xW4= zpf~}N>8A3kNiqA$84(X7nyr_5HL_YhAxZ=zLzQNkRUpznE;GgKv6$dl3d0bzI=LR_ zzhIsw^*0BHM2Y+-zydjOK9{{tuVC?yAA%~D>XP&wjsm`6hAWDHWUoBbBzetO-E6$F zCu4M|gv$OQ5OvtV4OLHD{A#g?NAQ0r$E@ke{o^Cx|$<){)q$v0yDgCBPv zE{v8VoO!H9+)B**>WFM>Z!F?rwA!(~pXJ56EuvEX(s|aoeyaKY`)vY^Avblbdjm<& z#%!EbC-k=TAS$x?@}@oAu*^XKN=jEZUhz}FaZ0ULO2rGzi!+#}T*hTyapag!H2;JK z@#fJ6&-AfH6bv6~VV!FJKiCnd5y)J-MQu@Xa$Yi) z{t!n7$Sz%yFTckO=#O6CO%tU7O?;{~M>r?b%~Q|!ze}V*Ocd|_Tf7G@!A4et>*sdL zx0e_3*mF;}M)$R|F1$2f5mLRdfdSN0KagBhR+re~K^Cy@y69iBH;kTgN;Q*bMO-RgVf^FeD~XB+imXqo zw?0Po+9b^Qpdiz78qgnyORI0#^Ba zT2Qj_<{M$@o-pm*pK2xmcV^a=D@R>c=O)iaw_4mgE2Ih|`m_SZ2c zN=k}wk+p&c2Rw!bL=9I5&e%l^~5pWepU?oTbP z*6(jDt;X{Qf9pPlmybA))E+pW7hfmpLTBr#&EIPWsW?sRR-Geh=3b0I=(I0g{@zJC zSPd|&-jFjFxok{^5+%65o$T&KFbgCjRfI1(QCX^_T%KNs)UOb}!Vjdo5Ryj*~2jCD1u_ zXw+)GHs9F7*|Yo1T$T95N-EfiPJA`+eLB0_1dw}oUA%4C zP1q3ccSs)bQKuidnzr1SY&Fdet)TvuloXf$Q$(-D_auycFz6X(Psy&h1VeQvm4P|mkg^ND}pcgWN1SMXn?U(<}Y|4;d5*vxCp^Ep2 zNu(x5;BV@+$EZT6O^0(32E!C_!^32anMp%oXI*u~CYgdl@lLIKGh^x-SnA+7$(dEc zdKDw|niDn$Z```Ml}&^tzmV(6l(hGLC3$??fqrej83!3oShjYf&weG2<4b`TlD3 zc%-`;r(N+45r4gVHhlJkxz~j41mND&?_l=l{cUACxRhVy*WoXkxP51|jrwj5rT+WwO6)J6ftiIQfrf_);F2%6Mm#7ZoqVDl!?i&%+ zbL4TV9%hM|zM*-KvKD_z2<5KS%u$G!h%M1N4KFoM?6^~zH5|LmZN}zSc!fy| z3R|HcANn|afLE;(Hd|_+uWXJS!0$W5&vUmMxl*}*7z6|4+fkt)Rpi+FGPehPU|Mvq zW@>hjF1v5k=g#!?)oy=Yz!86UiH$w&8FZlL{nEUj@=xj^$YRh;91XA z@zkd;J-Nz*Yxb#`sFowo@*i*-5Cv3#O~~8hE~ui)3@VX%g0@zR(Rau9#02RB7qS~C<9ICp9m)4c!ThA|JLuyrjdhEP zGp0$S*FE1h?q9-ySG}6 zry?*Q5}8p7go!TChTW5)j=bbAb<7liaH29{@_6Bj9?1+nrZ+>QEh5?^L@x@_5XgH# zIbW)P3Ox*DqM!}yvbNeZBP=@spEHpzl&j@i0o@rz~i5DRlgeWzOLL| znxhYYMAjMRw)h!8!|}9KOcZvB+MBEZN)q@@X$Ay;6Y-{$&z(;!zW?~L2IWJT>6BSK z^Wi;mfWsJ@c97M^_Re$G2))gJC9C&#gzlGnltXe#_+V04_ZvDjJ zbU1$oeWQx^bbqh#7QEpgEcpQ082hVH+RmV*PL?rKB!5^=ryZ_!_gRRTt}}ruQkE7% z3jDLCobhVdRa5(5PM7Ypn4fmTvPA1h-THp9?Xd^2BE0fyJzT&*< zZ7%$gR}KP6d@QO0z2@lbhsaPiOGV{V2 zb9U4p^!ldonBWa;bw?TF&FO`cbYIZ~w!gK^%u!6;Ia}Z;#5!=_%%ABOI(jcd8l7kH z`D|-YC^EpnNkB`da*Gvqo3UXbou!_x+&krlr+##dI$VLNMJ=nBw6stuzgkoe8f)7Q z-Cs1QE@_(}Hx+Fe1i?r%UXL{VD%b}{>UBskgic5;ntcf0gc zpr+#Q6l=8({1GPQ8Bn5#GhR8nb(I5eQY35G;-o<-$0Oh5K2{Sk8??_8T3Q0T^5tpV zPw_~H>eR31MYy-P=`Tj3H;lHFWe>;o)(<*<$!8D0cj?OlKK_kmEIcVPP&tUsmC-ZzZ?5JJ`NMee%1{Yi9lmQ|)ODngRoipC?b7SRb$@~yXp{*7PMtn@ciDY#%v51zR z%+AG6Fn1|DmhS#mXdw^H!~Oas>@`aP?uv~e247PVGu~ZsmhHCq(08=MYxZ6&YjlC_ zA0S2iY$QRrT@8Kj2)@N32u6zOa-4=G==PAI(?-DU^U!$p|B9NYQq>0?PBMa-=?Qw$ z-DAw*S4F!z@0wB>7r2zgQZm9=%(vN%RSuH`hnxqWdxEzI<5Ak5wS+Wnm(>c8P(kxjMkUY6TUr1&$gs=_OF@d8;)Oej66K}91RDWGA zDiLr~zXOyk!b>NL?lb$?WTGS?8qtm4zG?*iUB!BGEXM$rTYXkF^*N5*kUHUx)P$>Q z)v0EskLeWh%Vx008P?3L{}Z9sSXU+F)iQ zg*HBd@tVq)qtcMd;f;u^sh^bMd<+am%AsFORtRkkdQC~6mh;emP;_J-UJOc5rn&)H zuzqTHMzLsJ{1lJDRIBP<w*>yc@o5;9G9L0bTr2#*WJ%6x_J2 z+*}T};Z|s!FgK$#_Y>xu1H*Of^L>F4Z*7mcql+js26wg^I>$E7=dgrkD4QaSzqI{g zN#FS(HpfZ}VbD&UGHO+AC5@fYiW;mNk5GBaQC)xVtz^Ywl~FZ3R?i|Jd`oia9E5=hqV3mnOA+7eHso^}{>WB%wYKy*7x?>bD@=`jgp36CDxhs16ObVcnSLv_y6a9t zcR96@4V%(Jn=UgP%H}tzlU)6ZFyFLWP7+_}Y@-`8w?!N7Vff4KyijRDK)t8*{<8D| zPYSQYsurwi7x;<&1$33<;hI3-D>~lx!S#*|<--)}Kz-A`sAZQ8Q+&GOQ*UY1TVtsr z3{XzokikCe3WRFBi{7U<@c9gRuzu;-*A;Rr<0<0{EnR`%l>HXUzN0XT|8W*NZ#)1z zGio%g$o)YQM0fJlSw352GJe?74by;lgL02g>33rXKt(_x4}L5L3FwsWZ4EMK<^XgH zr|Be^1##s9MuE7Zv9pfrEv{XwIF0T+AL7$u>8|5)7&THyH*xZ%(z_mh_>ATjKW`|U zKD%c%gnNkJR58}}gc5Bqy^&el!$T0FWFH(+$r&xq7Jqa&QS5Tk9u8GOoHRpo4`r7mux914R#s{g19Uj+XjV{aC?JhDq!#4MAr~hApbls%M=I!_ zdCBRd58U>9HAH%O4VP?8?|@07VnxMq4V^I+!MZ8m^&{&HUmO(akn60ncr^ zyy~u?P_pQ-ouys!D^x8Mrxb)9$f0q+S4%+%rtmhS-J7dgLk?#HEzTmG3LT#x#tEH>9rh(1 zK_pGkf=4OzrRt5`$&|};kuyz+m`O68kh4$4}(x0%41X7d;@W7vN>C+uF{|O zN~*sqmIx;A&eGiK5fh~LEtdrgYDh3_eIGXjnFa8^ zf;vLt$;=IthzXoS_V|*0-q2`lfIDMeM|ce#BU7sHHn){le(0*)z_x5yu0Z8k z_dlTRi9>|WX2@ocmh}%W3`F#Ne*N~ohsV$J#5B%Q=~#Z*M5-P!y_yi>lqVuox0D>Gta7RMg8wa`D=I|AFYdJ5>-o zze3CMonPZ>o_C&H(gw4c*p)=9D?!f|sp{tS>bM*HmjnUPaxwHk8|*Jy)P8s!q5<~O zrvx&@^(iC3hUn9)f>QfEq-0TfheU3fU}^glQ&_s7i$rCk?3qcI)NfW{KX@Im3W!Ln zFZ2~e0cexw3(Vf?mhPg5d*>$$7n#(pvjy}ACKS9m=jL`HSC3?o@5F_b1|MLB2*@~{ zs${V@GGFsVTQ7_)by_XywAlz&Cm}D5Z062cG^U3Q6hJ@b23Ft?J7TANO7F2-AA#sR zBaPZMFdUeIM_onlK@)B=d5K{2NrOleP%hWui}5$8>L>j^xwy^ePn3c{JPaEqQM`!~ z@Bv^(O>784QjWO%`!I>fGmIl++x6n|W2Ao`pa~KPdh2G7H!E=6I5nJl_E0pzXcP9Y z^}dPwf}4FFJaq@1J1vzP$k#?5h%cE)!!UMwe9Fx?E2Sg{;>o9eGB4yl7b;o4mV>BN zyBAByCAlf!k>*2l8Q4vRRADR??M8Z&HNS_>@Hyrufy*d8P4TxS8@80}OI(u7=7E+|) zhfoRnRyvDXwCud;;=rrVdu8~Kl>v8@T4(UcIZ=tSFBbU>2NphldU}dRTeO=f9i|kY zCIEwATd5BkaUKf`SwWF=X@V{R2qwLJ)!YJGskm)hMJ)juudNWSky;N-Pu8dp4}X5L zPolqpk?8O5DJxEb*cU@fT!h9i-m~a(J?nZrqI#i`V6(;_)L0}Ze7!*%96tX8luK-c zlV74Nw5beMDpuJTQx2t423cBiF>gi?9|wxzvTCih#J$kPWz$OHv`bwK2H~jcC`y|E z#c=7u0e(u^PrkiWUhu||syqg#6Vb_3f=MU+iK~J6s%M0M>LaM`Puh%%n!|Mi4-L!bDyA{ z^tXiRuDNF^S}yE9xs&&ia{LG9)bwsoUm5eV$FvfKV(G6=+s!3n5d>IQ znuuJK#sr^ZVZV={6rs!gac`EUYUX{WY~P@r9L@4IPN{c0mpk;E9RD&;Dg`Om1!y7q zcZ45+o@!B4wdXW}8;g?#6EeNL3gTRI5Hd%1K=48Kf=gk9TM)c~QL0`~tf*cH;57x4z1qcq7hxhk8Njv)Fr)~d+wJq&|1 za#fI~J2VA)GHd(qP`f~*iLLQ{4Du_a@D^lEdnv>A4SRv(HmlhToLQroB$#@0nJ2S; zLLam1o1Ce)JZZIR=}WkOhG?IDsrnvg3rd@Q=D#G1HpTvYA4gcYSxpp3(+np2fO)n3F?@nA^Xu0srpJNkNGAh_7n) zwegl5-e$KSckw6nHtRq+c+llqME~=57NXg=(PZvv>OY3?qhF>>U3W)fgJH=U$1dUe zLv1haG2p9muuBUu|7LUDng6=!&$o=0+AVK39@8s-z(sBgi<@TMJl`RC79&^AA18_O zu?u&Fg_*9ozY+Wd%|763@(eW*U&fU#;Z9m->djRTZ94trTNRXEK|zGr%H}u#wUD-U zR#>5;q~BfWmm-=%z1J!1%HOVu+Rh~`3ebj2Qx>Xh{ay!_e`hdoGnxL{XZEGC#P(~D zL@9i~Z1)DmOQYW&T496>F(&76ma;5+_!zB!DB4b3y-7aEe{5BY7J{82+cVN?{qTCCl^aJ= z+v%r{5JO`{thrn@OWG9RdTk7be?qS%I^HZ_Jip?|E2||0y~bT)@o`L!X0FOR=(jyk z1^=-JNYgHj+LtKo&<;%l{d?v*8qbFK6MVzUlp`CZ?Fa79eC>(ys`PlHT(ziK z`N89KN113IZLMZ$-KuM!q!~xZ!Jum6{djYORqY(4HQmM5 zV9%=y3dvTWi@~3!k@^ZFh9$caJJo3YW=F%ocBM-=GrgP!o7K8Q69`<>B>FV$aw>Te z8gY~KUfW^_HkZzQ2f7lItOR?d!!6}AF~@NqK@yOWu3PQv>slr#d8vV@Y--6bWl2&f2>(yfGacL@?IDUGBcAgv%S z-6`D--&y?C`(5w#KL3&XoO34bxo6HyhpADT^9vL|hgueS23w{^ZKf|8Q5?iD_5^+_ zMU+TRRT2)fKRN(=0zyuc=9bM$?#aWUSn$o6ka8x~JV^YTr!|n{N1l1_SrN7xt7KjZ&6g&=bCw6Y z{1^tjul3fIipW4{&P>J4pl-D2@TCs1!pb~|d;xZh`VVCmRX&D4Yl-&*vUH{{BEEZb zdDG)c7P%V8+i(zfI10543I4RDOV4jEofBrQLEG3g*Mb~rfx2EbAZDT=FFu<*25kH3 zyyy*I#D1-ITSyu=UXtB3Wr;h2YjzM}>kPqvcC;DX$~A6>eQj}(LWZ=sL}cskCOLc3 z&O7Jd6VT&L8x3D5p}_4O@>VN)*phywp3So!H$-%aXDwDmLh~((hC)AOLd5mks^rih z*6Z<=p0QAh({zBmmO7ezByjCth7!et*@DnVf0`3-QA3x7* z)+MUQp~KCylejU7iX>nnHp*XBDue-}j(kN;bc=K{x{Ieg^Gd9hv^*kseQIJ?!j{dg_==0~j$x@12Q z3Ef@=H3hL9e6cg~vI!lRFyFWAIDRNgYF2~76nC-_Yq;jP%!*@uLo&1EdEdDO)CP-I zT*jK>G#%X&7qyb{FRD&4cpxofeKFE+emi70L~2q$f`z6v{=^cqkI!M%as)LA*0HDY zNahJhngz(E)~`DK$)(oSPx;0$fp6zOA`Z=j!WS6_a3c~jwQu3uMQX@o4#VeIOJ09S z4IXC&;T>FNj@4w$&6H#@iP_;^WZZ`VhEx#-8&OZ?TCcPI?WHtZyrd?V!q?^!^{(QT zmAanumdgS4wx4;=x419VRyHmo;Vf(C8p`Wy57~`h2#ZDlqn9myg$9RNRee&&9bzl# z+l)cY6V9(l-5Z6jU`!KcKrgC1tZN}Ty2; zUH&iz`L0QlyKe1d+4#>84_t$%kC(61YiF1H@vjcdx3JHe9PF_1&M^2;Vo$^Oq(fw~ z-{iIo^<%MDp#ea-ZJ0JZrj@ML=TXdzp~PIsiJg6ZZFg_J97xpT%13FrC3J5ilO97( zvYtSiJkP+_Uu&ENR`pqS2qU7hlEiW{=O2wIMpVa9>@ ztT1nAZPcEKH7|!X02sUJuICrKpHu1crPC4Pv(b%FS&mup52ZIMD_T=75Q(O^(3z%qV4!RZ3Iov_3lNAl{oU2QVi1q1{uq1|vO^KZ7>kOp zUSNJE3A*5@*a29u;=4cazN;9sb=-pD>Brio*bdh3>^l?ySs)lHUAltv4xQj`FWvj4)o>=k^}LeQ zQtPc9A1n$P>Ojsu_DMBQv6zniH|%|lVdB3OU-5Ru)-IWpEg*_U@}3Xsw_*5IX-9;b z=eDo{h_e#Pq&^QdzmEvR3UV0oa`Ce%qM>X%^e8GnUiQ{gRs%1D|=it8av}xgCw)>a?!@`Z( zaQ|8@k?$gv&38jc!Yx_XUw0EvZ5=c=N}u(jp{2SF$cJ{;TPLb0P9WFT0LsD6D0VZv4rpC%h6uwg(qG5g!cY?m>E+0L`lEcX{9N85-tI^Rp}Sx{1;DTsEwU$Cj~ zanNYHR&D>=K%C}dT0cqetELQP^CH%2#Qb$%CJ1;_wLwoHQePe@SYg!by(5`6f!6E;3Go z)s0kXQ6`)Hdog43Wx)y+{uN$LBY@ zW~b7(KWXta0ZofS!rb^-rjN;p*TEU!=g&?4NxUSXO!}-vZub{IY7MT=ByT!6i3;3w zZDxzVr_tqA@Y?BXl) zVD6zzH9>fgLL2SDNmdLw**b!@2XDPvz^fpimiT{IjeL0|t0BrbVD}|@2|G|oY8A6e zFLdwSobX$_rbc@OB;ac!FG$FQhKq2J_hk@WXHbBNw(qOA#X*{A4NPQMHk-I15J1H( za%aMMC}H-@^up%aM(ZjjeytMR-La;8Nk+!VX8%=4vI@!BVhTpdF(?nI5DoF_mGB2h zSmi0s$(4PLzX=)$%qmA?1Wx)k0KjW?XmB*r*29l~yMI>09V&>myg@}5r55v08c6}9 zgq1Eg&fS=`yIkj(Ri`^{v%gAeW=%(#0FsrLb#XA7^rB8Q-D^ob_}riX?+LnxVv{)f zqI29`0)`}1`Pc$QzRlnw*#5&-`XXxk}Y{MuJsv3vd602(A?+&F(W-!_vnWQk35} zCkeTV>6+(naO1g7zO+1^Ha*R_rUCFZ^R$%nU?(1vk$4Z}1-Rey(}I*_x23^Sst75X z@#r0NC2?*QzO$*MhtQM3zFY$1)G8nZg?FM75In+SUgq!18y;(t{CRo54~K64#@HgR zMy}cXa_>yxu3d8jXZ^lC#)HUTfTufqHkLpkne4c-{2{)!?atwGCoX3*bA(jH;h=sg za}=zG;;>OS^#Fmmsi;!G-zQaIzBNA_|HphE96Fg$5{RB3Y(G7^lB@;QQMgYa^_z8` ztHVdX5$95F{dgv~QUOaUHAU19iDlBYH$WAWTYmO%t?%X4mj|yP`q@f}_Xt9>&yT*l ztM1&?w&zQx#oai`r|)(v?k?0yR?*ZIDm!jUPe6x+o6wRPkYLckczBzz2kh<0a<1!` zkjqf{Cy@%7`4Ec3h00zLsOH&3>?jF|ZxJL%Tp<0(a>Hf^QO*5Z@7YL#qsOMe{a(L8 zrNPU~)BCxZTC&iiv^A(svFxG2y`O3#9OId|}rQGtu2QL4xpw>lHUZ@~qbxH&-pKM#c* zQ+0DCR+$YRVK3?gNTDp}MjFT81uCH1`AM;q8ADFdokp6pQ<3veIR|Kr2d}wxUD^<@ z{y_Oj9)yED7+z7bLlq~33#(<6xzEa$@@y3eMfbe|lvF2ZvfsHe9v@oGF?ro;8U5N{&cY+Q3~1653%X(;FR#V6-UCPcs(?6u(x zh=?;$`KZ8phzbk}5ScYmEGi+DzsANV&l)KeAw??jxqI1&hqk)E>Kvflq@v2NcInnb z$oga1rE)WTq!z;nHj~gGMM388a@a8Bx`J)-A2LUHzenr&$su(W=Gb&yi3nbh`5)3Y zUKuKz>Ewsh?V*eaJ){Hzl=f>L!$rVbjpW@B zcbSMQ;*2{M9ef+Mu{6E`+$Fce!r3AucxcV#&f`4?pl21Vxc4EqZceIo>bFF5zVzI* zMuF(Z7P#LHTph-Xx%k$p18gA@wq8T>!|Z_|fk`(f!82KIvR*&2iw`2Lp3{e6v!BDV zZeH$3rnO~H5@Ii=^bYPAo{0{pMym@R6r#m zK7?AXW{9ohV&Hu(fs=Toi5VyS*^x$OJtkzvp^*q2Q9Bt{GglzacYX5If-G`mlG}cR ztC_r{;ZHTyH%p0{>Cd+toYoSzvx}FxinU#v&s4L|-zb?pv^PZ6WCc#PGS<+#6y!x& zddhWhEt?dcbWf+?Mu-}72M$JVV6v%{2=0;+LiBGWeBb*Hd6$6*@iS8-8F<*DbiCb= z+xD0H5eK(8|4=-TZQ~^eu>0XS_>!M0_3klK4S$-V2JCtnwF8tFiCyvaQooV{&YM*x z5XxfHyQGFq_5W8x#s4AOgbyN;GHz~uUhUq#DD}C&f9N9*Gy5>3B`Gh|e{d+Z`2HdL zy}Sen2edO}t29ABmckVB%RV#aNz*t0GxTA&gak0H57-omCU3?r_7a)kqn!JRypg?VOVyDmJ3D)Cq4^iEJxAd)rkTHB+;YiyiONp1FR zuJr373vPY7%BgJf!F?XBX#aEClhn1|5VJW_hTjS(9qZnd?M?g`kU|M}ns_8?$LEOt_z|AgR6bPyGRX&RJdYP^iiOr_Lb1yo((EjC7{tew~ZMm`o;Eq`Pj z22cE^iFbN`lrPUxyYn(z$$VMwMaL5+4`b_SSdoyFg(_&5+$mrx!2Qy0hJrPiF<>() z((=WS!R+V-VxU26{h|k}HOqG~6B(f6SpPv4q^&oUt-G%yLgz7qJQKaUQk7+HHdbrN z3r^lY!ZOwjB1J8SIZ8Ahen=!Zzj}v zWnAqkO{{XN(rAu<#|wL78UiC8)X*_@GA@*7OS~s7l03*CgIcsAWAmf%rMaOX-5>Ja zUgvT~C`t7A_lt4T!iev_V<$0u{gVei82(`YZsv@0i~)YqN9SI|a;}E3`QCZuoG?qm z)0_TU?6{tA2;}>;ci)o_up7H_&oY{XM6V9E2*!PntY`bSPW5JiE2d9E@jlgd4KTe( z;AkD^_URuyJ^C_97{6yod}mM2v)p+MPYOOd_k12ymvWjW>UnChW-%2eYw%d+MB*#m z&-qk}rSkc?iDnKiVLtL zU)5msENzQfdp1SbV6nW|6;HdfO1T2M#3(hmq|E`K2`-gp+s}|kRBb!U=U#3n&U81L z54*Sn3#%t7?!OQQZufVoZ!^-YZ&hd3RMJiX3R!v2Rk=LWoA8biG*ktbQ?KgR%Lz!4 zgn-NokQ3n!EzW{H9Bg<@xK$ou6^m;&XSexI3L645On9$h)cLJ$^s(C!Hp4E%-6Dz7 z@oFWl&paET`0@II3;j)_K;XB&YAzTsKm?UMn;qIugZtBa}V7qo75MI}6*Jf9{p1vJO zXp1*}_WP-{{)qVKa!Ag~tx=$M@Q5_a!dyi@HJd%GvU5B;n}HRrNbARHz40N`d(7IL z7ms5PPH8}0pu)Ym97YVeKC}<`2b;#|WwAFMG!vvo)q*tw&`*VkG)#xP^RUG*v-Nu169`T7$F%R&IkRI(W zN2*CGy<|6~^6t(?Z=8-Y4GAzlIB}KKoHUmat}mQ{A%IhcI%zAvV?GLPl=;j06@3NP zk70enq48A}F{pX@iy_Wo1qK_APs(s?%LQrS?>+Nqym!_}ia>eyeU+3(1g&)@N5f4H z49dRj{Vw-&$Om19;ZwGO75-D!JvsfWIBvpauBQIF^}gA0-*S%g%R5)zBaLSaID~(= z;)%-DpWEeJNx`bz4T1os+Avsd20`m{!cV zpWC8Cv&Z1rn*=JBO4LL9?&#lEM+}64Ic^^*N$a2#_ilvXZ^@M+9tL4^cx>q(v8RE; zHY98VkM25PM>ax-<=%s+X|v>r1N-_1er)e*BY9U3*SQ7N9uI7^*-t5JE;OP;S_lQW zo`lLWuvRZw9rO&V`E;$daZjEGZudXh!qnPrxvE{$UvU z^{-OqW#tI+wJTCfqta3H?LDyZUuGGjU(7K7#Oq#5ZW>C#RuXvIZw`UTYlPrF&H?+2dff!Dt;pjy(MafkiAK!{lngLsILoQQK&$*7{asEN&y87e*uyka>X?YxUhh; zg2={IfQK%FI|46y^)nlY4GZiDmW>;4+gweS2AVcqB3e(l8zt_djh*a_C;s|%HOXxX zy_`F`QWdN{^Z#^GaR5L_@)ONGvn+AH#R+p+hBzt8&U?HiD&w5rz2U3<=Cm{@5W!eO zR!272b6N#Ux6sUaoWw#zSb&CFhMJvN&wMJ=pI4^%Kg1rA?AEAOz!A7}Q}zpJWNEDc zkmW71F+9A3&fn!V^j z#9tZ!YBCs-QPx2YH%|{+fV0>s>m*h$@R!w7gS98J!Wo-iMAZ`zpU&%~pq7fM2cI*l zx6D;K-Kd^I{78NWej}j=IU^LjGKe+nZx>MsO|3@T@s7VZWc)s0Uy$Ba17tWSjJNcN zfZ-|Y$N?>VXC^RVTw{$>Uok?foC$iZqO7XInm8 z4Ht+jZ^5fPau9bQ(`m|U+jh;zLbG2)YzeSj#mk;IyF#VR&{<50y%PJo!My=7HkIJ_ ztm_&05RGon*4D-ce_j=T*sGvk9@l<9)V7`_&@uEg4Pob>J%#C9pw=s!Ty$VD^9Wxv z#J^1HhgKC(bnoKI-VNO0n>G<-!tg6FTnR5}Py?bd=8;iN1joirBLW0qn6NP&6`!z! zwfVIbrfSPqEx>*9Z@2{fDmm@Rd8gD-{WSH4V2173r$3aqQB$+pJ2#`o>ZP?LcmPe?G&#~X@Z%dL5r*IYzv z2&KP2LxAa6i7K!Ze+HP+#BkD1DcQ}k?3fUA*U(}!Mkzs1*p-OPLu@2ic?;7Nm)~*v4 z$F%?Xu;hvJFffh%`d*E$J!!2+wC8QxGf86P$jBR=&(Ft4ym$K_8dVt3sK<{cGk@`5 z#yv?0JUstmM8cd!b$GObIipzKyBM{4Q&!XHO}5eA3IE;&Xy zwJ*4WN_!jq{_S)Xv8)9-h)3+K;kW6)-RYLuhV2PodgNj#kV*3E%Zz3Bp`s|3Q27`q zDtrY+ZN+7uANF*)x<;M+tNWpm&<>R!e9J(nC}LTmht?^MibV}2{N_R-o-|7lWtVqM zY5N}mD#%$N=;}m13&-@TyQFL_v;M{k#J1VFb8tX4P3;EvxTCw^;vHXMp!Ii?*=oL9 z(HVLT;k-&1pxQh2f7?*9AF9Dx6U49*`2Oq|N&|oV6hlcwiA9yf$sK$ynr$`3=7#5) zhB3&Bk8NN~N3z$^L7@OV2mg3h9RSt>K{I48^E{xUi~qU;s*VA8z6?Y5!O?fh$jz|mNGD65y$R`H~t z$0CB0Opkv2?QVa(A-GQb150}6yt&lZ;CLO>##|lbP2+$F%HT&choW{9rdtw5Xq(!4ro|*wJPy@)_G&RpJSbp}E%U}Al zjc^yM%k0avdq^DtNj#f=*^mXA5&<6Ji~L4rA#oxR4zF501|?RGO{u zhTx9x;8KPOcGDw**FXw1?{BCTX!l|I_JX3H{xC@Y3(&n@xiZM}9S^OKhRIXke3F%y zWTEBf#?RCGaR&g6cl6YR?hus8&JHv?s*eDthrjzbuRmOR61bgC-oRg}CbIS(@pGOP z*O*7`@SZqs2$VvGSv3`FP7wMagWR%Ou=Vin<<)3CxxI4tY5&oc;nCVuz3Y&IxoaGz zp^XHwO`83SmTz3o_+;J)d?lJi=f27E)Jv|@ynojC5Zt$*Ai2pD&wcgQ9M^5vS2l0v-=XRt1O%O9wSobOw=Ly;;2>) zi9cJuWH@Y&g9>x-_*o(ep1-;ma@@h^Crm*5M*Uj0(r>m|9#fXZ0E+H^>#$kUfyU1v zr}aAx3Fz{DW2Fh{B=I9@Le3vo{3NThp)fC+rQuT zD*7W3(P(OM3Y}XPDxWlFl94P11sXGBi{qZRx}NflR}g~R;W8M84sFsMvSa2jq)v};v0o6*{H8;Q!|^ci#y zSk%4FOisr1n!aK^##Z#f;`O?U5a`(%zY9&7kbzlEFJpyzQo|~r*Zs6d$^!kK*Yu*7 zW)KC2EzmcJKDIo578LfpxBt_64h$-e%^3?J;M!lm&$b{vBLZzl9@VG5v;xp0<*DhR zWGna*obXpn3>Spa6}n=$nihzK(3*YO6p=q@*;U?@$MP#Oi!p|~WgohW-45HbeoNj+ z&jw&59{-}Vc^5YS83!C&7KbVq`3LmGa>V43e2iO&F5C@gUhh*&$Eje~uC4R-n#J2$ z$26l2CvIXC(x>167sMxPwQa8=IDV^(ACr@~9Fiy*cAiO8(6R^7S>IqISGIihO|S>y zlncQZ5+FpAfQHEJ15&AMFp~*;hQ3un=dGxk z%c9JT0hgI5IymV_<~--E)0Sb!MJzG4s$cy6$Tx+QNr6T0N_E|`3YUxBxYubrx+hTT zDI)vlrvQ0B_b(xmIt=hP{K;1WGMeJ%6j~M-1v@t}KC0oi5NV5%aa<=5E%Y5W9Ljfc z))o+ReeS<`+;>0O5rFP@FV)2_DjhmsCPNV23x_B#1N!lVzYX?|1w#=byvm;>AB%GSbiMR2m zZ_2K4I9S|^?o_|mPF~G)&Gt{F)tJbi=}-tSO8Li`0bp0g;gZR)5fbwHvhiJ%kZz<$ z-=_fd@b8+PHqokgnl$g*jH>-f02GmcLe;GjaW9yDb~*PV>v5Z;fFbn5%wMW3_igM zC_Onk4qq$SN_${!U?(6ZN^Ds~(LM86o3Z_aRE8=_1Nx;Ri`1maJ3ZGu)pDs8ohd?c zi@J84YfRXFz_A)$xttlX4p0s_H#)xi(gg#6&;By-(LxoKiOBKE!cg@M6RKjI(U)@{ zxG(uiMJ^t{LaGCJO#J_~#)+mxvZ8tfoSM6$SP%une15QS;ohSf<<*sWoG18!nljk>WW&!JZ649Q`UXSnr5o1q zOOik!3rPh03>FF>bQl8gS+SXiK&X;RPARJL`p3XP2;{a%vTI+c&MzYLZQSgwN(F|e z^Vy(i{GB9lO4J?xj-Rtcc9^XA$9GQ!G9DbSrB&O+8HRaAgVzR+pV@!x*=}fSG!eui zvf#Bzm5v257aXTmAvX9$4^zwoJT~UsS^~kZ4%*OLxv)%|yk)9I5<-2nFxn9ckdA4>mEBMwwDepgnq+RXHm6B(I$5P=AF@?lbn&_c5# zU}*TS_l}V}5E&2xlZynJ5bk(-Q1&1XH|R?sHN3fLZ9vvc;Y_JNz%b!jAF|bMLHru( zA1_ln_I@f&m{${2j1<{{8hG|Pl$-UqfQInbk6ieF1RzSQDUsc}5ArRMK2+bFRG(4Z zio+*`G2|R{D;MN1_EO61aGok~X0oK6#Uc|gapy$N`SwdP`|(H&RVF&yyh#F!)4f(O z!MvtBr0cMH?d$oD`EHy1R#N@uvC}Kc*4u>Q{39gfrcK&v!h0_UCtiM(S-dq1p=`P3 zJ4%irwl;<;UFP+Gyt$0*E(Gqi&en#2D`x(b_O27ZC(eEK>j`TN{>UqbcnE-`Y zs7mH4;I<5|NK_~&2DuBbJXCHE(Ytg8V;pYxapeg2)y}gGnus2lf3b%DKy5#v2mh)e ze67y5cp{ZP#A|RYN`XP7RRU*OIr05q{NXQ}-6c1Xi;q!C%koiOw~wZn2`7B%M)7Bx zJU3}=LXIZwD~d#BBeX{CdA}5qh=;E$eR&p*9`ukif%$tVeL4I0bZN{W4I+Od=cZ%<3{GIskRLv<3b#pXmvSq|&{3$5)sF9*zDd{8b(Oj$8jTD2R*pWleCqs|EM-c5Kbn%PQX+(`R&7WwuYAm?o_IwU3|0(W##IG@ttg ze?Wn71pO-jK?UA5tgSC3HE2kGBij>fuU2X-`ip>S=}kdh7vlqW^uaTvrz6Lfuf*v?R>TIYXskbu)NxoOB1#8pbMKy@ttJS+}ACIP^F1AKg*F> zXzbEwUP%jW=<}&Z@MP&C)?9kl*Q_XVneXXe2JU{g>Dyw&QDC?TC3)y}8;HqZR9GFw z2N?EOmr0X%y5>I~E|^R^EWd*pNt2vF1N~=@KR+ssX91%YqA~Q=MWv_gJ04lAS&4H~ zse8q#luk>rf^`%wWVuZ3`j#G+&Z_Q)m|iY5nodf%w9FarUtO9$y#hNo1Hc8OhzYom zzh)v)s7XqZX+aVtR_P6r{kH~^anbrvC0ewa#hbKm2d)Dr@H-*v!Eex`qzvY-8vv`` z6KkLQ&_eQT@ftq(CDEL*m(mY1zDeh0dhFeRAA;IGx7$-xdnhQhLk^TCcJFsRov%)l z{o39CsYjw0Mk#_jTqFr~D))AI81ZpXdiZ=<6KOPQmsj}M4aUh@2H6&!{Ds1{3JE5Z z0!iQt(hRHLq?QP-X7^fFa0C&Wir_%u~I>uoiH~CFJMq5?jJtNeh+)u9f%rMj)u3e`j)&|B^n?Wh)Fj#T4bSP z5xr)DN9_6=slHRE+drp1ORI&{sBfJ|_deL+a-SPN>P9r}GJ}oqKALziLZWBt`HtFY zjw;Wg_5LeL;=FT-k49>pyuEbFmZ?M)VkY(%82aV0GWW75c-_`}AH4fUh;RZ`>mBNv ztwAiHRNC+7JD^@kq84V4@`s*R)wx6J01%*KEtMrX$u}y@AJaD4M~CEgkctdM^9|H1 z^a~z2j+R-9_+Kv^0-*%WP5(A85Z%~P?_Wuj=3}l(j4xh6$k@VV0wr6VtVU_+IJ%CJ zGE8X6-b_!EQ>69L@Zlg$I-yUiYN45mfv?+Pln`mwi?YFc&guO@Z5 z@33y-TjYk(}npn;eS z;X)e;GS3$voG-!MGcrCPPA!GYAz&K}p@R+?_c953pMMx(2}#g2@=UjBSo!?LDsymfxpAouC|F!+OCdcKAl%-8U;J# zC6LFoy5V^jaPcY z4tCHo8N(AyHVbv0O#fI^M?OT{`!7b^PV%qg5qas0Yjwwg7&a&n3Z6T>qJN18347_1 zTc$y&?s%@hs6!tC!^~nsrVf`W|-Df?J5;vQt=Hk#nLX-W6CjNp1RAYf<@hu@#+ zar(I$70+qP6g1!Julr5}S1agzAtDP$A>*q)xnFEX`Q+-D2l(JTY@I-&j&rWTZulk^ z=M()s{Uan|#Uhp6uUU>M-uF6hof9<>IUH(INEk9K{CMqx9ZecC_Ab@C_oh8Hn)ZrI zd(e)ilxB;ib`iCm@`MY0f>SGEA!50VpZ&t2DPyITKSV^_4D-+IOLX zt5HVVuUoWA+HZ!sQ7-PUnV9F8a*=}m?+|^(Gy(OVdNKPdqjTkE79_qxev zDDuK;gZ^wq9|21Alcss(USi7O)CaS}W#lx=$mo^Tx#aoFOMdQtfQ>3G*oKe5l0->|6y&9*Q-TZTH z1>)D1^PjEZky52ZD^uv=qoS}=I+1K_oi}Qc0)Va4oQh-g2@#0L?JIZja$%RK(`)~ zgE7;-aXIcRiY(^xO|$f=7AWbI5cg+yyrEyEo;MT@dRO&?AjYAqQIj1%!!f(10aYJ; zz_pGnPE+#j4K0bg9XzBXJ3UN_7B;p8q~`j+r=_FzjsQ&f>4Sjf97m!1$IRm1&^4l1 zajX$RWTmGseUY?CUHm*L;hsLyD%qYD;W%CWxmYd^jLC*G-M7n3boHKjUU!`2qneMf zV?c6k$OrE~SXQ14(?1~Q{VN8`K}clpj`JNPSl@XPz*&yR8MHRWc{f=SSlPCnm+%hm z7qJw+{!goN`{rM_5VHl#23_xu=37C{IO%rQ_kmxdg(lFV2{wvF7UJFN7Y7Ly{)=S4 z{EcJ_OB*%sr|<4vBiRPWtkT9D>_s06wel#OHw=4Td6SM+t?rg^;_#NIchZK1bSNCt z1C2DgpQa{BO1@p`RJcg{cH)UlK_7FInBuGDn7@qeI{EnX_N_C41??3>t^z{=ssmxd zZ}f35DcFY7QY_Nj%*5|poG2O>iYz{6xJNEAbecljD{?G_`Yi+rd$%r!3417)jhX-A zHx{HTPn%z{GK#=gP2axsac69jhD1B~`hKxH7Y9`pzm##;X`fE@Q`16V9uvZ-kktk2 z7YGh!-BTTQNK%H&lg@l7~!hsHKDqc7A6A!af zGd&Sa&<776BK;fLTR$n0!Jz%OlbqeqBJ$Wa^XH3>>Cu`cTSsYC-M7HTw}&{FABOiV z?EZnlQ@%bDO)kq>U4LNk@!&>Hhi}6}q=jm>U-Yz`R2UP zL?2K==$Y$H4(m^};}gd9hBzZ0&bvGv%PvZ@8@5iLky;v=9EDM>U7E$m4k-9uo(!hG ziv*)hTfR?uZ(ul%avR?%$Z)-9b}e~;VM7eZtsaL?%24cMp_$patNdWhB5dwa^)?ZEb$#* zb;CfU!I=o`qz5O$Ejm^N@F5xM*CEo{a;opLzZa$uG$`9ikmu~s0q#PJLP##PDW6>-lbj#9HxxP3=^IMlZ;(t^-E(^i^(^qStD*%FY@A*%pVZgsH0+8Z@ttAo;aL`CN~zO=!)6V153>s?%JH|rwMv3 z7WQY3k4LW_Kt~vEijt0Wr-L55VL3JxRteUVPZ~R9X&^1HG!3sQLcrbS{fBA!BKsQ5 ziI69e$&o7VW{M$DVl(FY6p3m7)!lFFry>It2rQG277fmQNaJLWINDJ=Yg#0qA?E6V zxcS`7LfzIK_!sokyoh-oax=P%eIatH(iZ(DNYTjBa`<7o^TP>b4?SOWU4- zG{M89^mBFG^`Bog_liAU+z6pBj>UR|X&K%^;x_3Wx48RBEl+1*_Bo`*?BA`q_n)mP z43wm2$Ifv4)N+x~VkVfG#n}r}C1Ilk)!eO&^(`?N&=d<)pi8^Eq648oR2hvY^z%mH z&6o|2O-YYyll2+&M)tWN7UQB;QM5yMRgOpC=I5f1bj_;OOylDvaZ^!radcuH z%@fX@SvUU&jut-(s>u7asuSbL<$2~cJuAbW$hlp_&bIKZe`Q>?q!EHgK{ao_dYqhU zzDoT^!GG<^u>@weHS!wJHhT?}>Wx0kb7;OPOMC{Fr>nsv2YX+JCI=>`gp<~Y3=#a4 zX@0=db%RMEVj;lG?$98ll06zTDD_x2X2i)ejkj^CBr(j07z2Wz?mJ87epKqC-`}+U zIskd@;DHbSC;aLOY|@VLh@kgtd*c;6Of$q^g5eM7lJ0iY_VkwQj(ar&6_#xB4m7ZG zce=34T!+hohcPE~_R(8G<4>O=`6dh}(P^7u_93PiZ~t9`XwkLK*RP$7jHY@Uo@=wH zO)-qmZG@Yiz8Ae3AnbN+I&eN&x;TpIBf9+EV+vKQ9yznEHHZ|urn?-U`1p3+vVoSu z759P_bY={T#*=Q3IkAJRQ_Aw0?m4e4$>_3YW=Y}*DPtPrhHA8w3*}g0n0@`T-%Avk z1%UbUOGrpZW5x(40i3r;_hyxF_ulxBJe92U`v;vPTkns^5jzI$B%6Ne5?BPKLuYD-ci+;sxmAv@iSl@R}IKu5Nmew8!_PvZEdn-P- z1IoL0S|U!~tf7^BuvMWeD~`RP^hu&ZN)3=-3&~DX$n4~}?Qw|c0ikJ<-Gq06=)upp z0KNbav)*%iuvg@?u<&BJ=ZD=0gWTkoFx3D0l- z={ExQtmD_)md(_)Ec%ciV2b6`VOwdY5+LS5bbA;7Rc`JVCY+fWqk;LlFzBFd)*Q(U z5p}1F0z)G(<8qx9XDDpBdNZjvb0G~2`oEmHK<*gQk`q}dTBwRUD!|GnV-ksHto5y6 zP_wfukwc70VDiv)m+o>VZ16k{XZdBz*1Eiky| zNti2XSn3_Q9MnQ-2V(-+rnXyeTVgsC5IKFE+*?&!x{4?U3nyZT1iriOx=blUaWdVJ zlMjL~Ksd_rz>Z``k-@h+2&(t{%6hnaEr)fE0f%~(kFkHEf~x}YNyzVO?T!xo;7KN1 zpdqOO+U>LSgC{I=JkdAvAknvxtYOoBM05O_xKH6v!y$B}g9Z=0=syaG7rz_?B;07_ z&}v38yX9Kk=g!Pr*^U(1fRQ2|I1{ywg=(E&V)&1gAQ*6FFvd2^v5_->$(V6br7^Ol zNk-)q%_5tIn)*C%qzJkPr+f5uF7TONWqY0T`Q8^yike0G_ubB{)8zBbQX_ixsWYJ+ z-_whq7qn8vN<|_e?JKTNE-WUsV6N!fp*uegmMQ3*UWO+W&2FsSRiw9$H>b>v_6BAh zT$JHNWPuh65M47{YD!u*cs#3d>oH+K^{9eUs|{kFiK64xhG71Kni@8<48JiRQ!VLv#&OWjf{GsOQa3Pjr*~vEMKc^k8;##~|rIvYv<-DHnHPSX``B z?6=?+r*0pjQ6_)?=i2!LwJQB*-|n7dG#^)c?N47t+Dv(g*5R*~jN2tlUmYLpPK!B2 zh#q~L1PRvsCB$a!-F6K9XbaVEEfqpXnc7`de5P1riV!UFx(i{pg)m396DiD2-bIyI zsY8q=X?3~ODei%}QRKGxMiiqsM!RO~GK*syfGNuu zWH!ntBOR!cErrJy1bBG)$jEkut&=lO3UkS~o1>6E_ZbRxk0DFgd!)1}UNf`njvGyY zpWQJ|o0o1-S_MPa=4BCGsx=oG=S#(|JvRh=V>N;*pAOiboYPG)W}SR%jPl-RucSF?XN)d;(`umk*^D%}8#Zkx4D`tRo~fmnGzUt6H6fqeTcEkfpYhIq z4SPn2+ZZ#8m6PUQs-b%{g{hoS8Il$}YE#!ZExK3*a-c~+s5m)S_T5W(IL_*Q1eh=u ze2koW6|YT=7RZF1(^o1ozS}B&sv0BJ^sF;iA0_yqxKEl*-JJApO6irxWgDHB=G~Ka z4mQ?XgCIM_E$WUV?^ef=xJUefl#iJj32*N z_2_psQ>8w|iXS$J(4cKNquibWo>b>%A2WG*9W3w@5qs(5O;1DiVz&AznQ#NS!d+d7?K%jLNR8vfi92s`gvo4ORVLT==@w3by>g}5fn z8NUUSBMo=wScMvk?6&})KQ5B!B*WP zrf7vwK9$al7YJ)>MYLl|OXsoNX!VlexZh0miWX?hpfh#zGjkQ*UC>{%Uc=nTtw#k&;>cnQLrl`sgz+3Q#}$E z9G@TyCx-ePWq#R=ihc9A$5!7XMpyb+$QH4-nZ}6I07lWXz9`oS?ekD+%t2} zJToS9q(DpmtI&DQHrS(0Oq)W7x90+JEZM?t~Q4#Xwb2G1L&7fo9Fw?^7 zH~LO(3-Z71f#4d^XTGOp*ZWH>duAGwZ6VR31;8I&zGF*n%QE{C^RBKDMzgCZ$H+@N zx7K25#J;oMxiHFjTs`4>SoXK@J2?hFs|scwxK9D}&Ej}2!EE2|hAA^%3XDzIsK{r! zQ9<9i-6-J0u(@pd_d=r9P3Or=BdB_DEzmcZS(I)MM550ts!BW8o6995Hzf%7LM(ld zIWIWzb>ObAk{Eb8+-L*=*nbM8-#1@g$kDv_msyx|S(-q-yR+Z4fckV*qdcuhk@1tP zjC*f-4biIv>#Is!9zy@=p3qM6i1M4PagB9X?AknwBIrWER;4Gd#%D*>Us3vC+#R3+ z2pX<9Z3l#z|_PzvlQ3!yO(Ie>OHS5ZQ#%$j=|S7z4*Spk^?-3o9C`-c>ms)pEGbyrbdnPA3re1&AvKrifTPy?d(`tn5DNJT)`RXtsXI`V|egyjNBqE^mJm zu%sRYy(OR{&;Tjwt#KSv6}#t+@3tzxOY&Yv2!6N{4eNcp&&3D8V}Q9t{=gbL(u-sC zrnpr3@#3+By*q0VSg%r=?gq>I=g6$sOGb+PG#dPscuC;MyEVJR2vNL+FNhPx(P~Q( zlN+c#u z1McWsM7Lnmk6vE*1V+w}>9>F^PQx@oPkw#PGL62lE$YXNy{0!ID-a!L>Ctv?h7isw zfy+b_Tut%?*Kd+*ViaK_2u@zgQJ`EWB^9M}vy1C7{Bt!203v`jJj-ncD%AQSg3XV+ zje1>MuCO(tUHZ@YU8F6qNw@?;P>Y&HF{7j$77T7pKm0#oVtZ8Wz5{1ie?L5oTb zc!BOm%B(bS*Qdicla2x)H(mntkG^N+H=Yx?8b>J7W{^v31q4eF-Rr8Df5MI0#Xs5Fm0qNk(;BV-5a=)O+M3Wq+SLs`K)N zT0gcDbzlkXjZb)rPUv=tEI+vQCfU>x*rIIjZzvDScje3OBUuGRfKuY{+29%^4GKUC zRr~prG*_*8waAuV5_xM7g3Z2XECmq4;MDNvat~tfzy5GpHgH>f9$ct(|7V80 zx$9S<>+G5~-E8QC1% zprdd%s1vvv7JoOXd&Ws$nGYRGWshsy19;C@o`+Os7Wd1cn~jGo#Y3cAz0tkI57ZlF zIs*xz&m;q9!^!n@aMPqkSwg~GBb6aOqfV)Q(#9qFZ{8|#fnf8~m?T>QHi$`0O}$xA z-agu8NZ63s;r0Z=QCEGg0>W&2)Tw9wPukqbpxa9mo8zkE-3&jJt*R2g^!#II=^x8| zhhs|ua-ZWC?>HbhDb`z_+yL|eX=3L{STdyPFb(h8dHZir-bMp%OFARNGa7kVU4ht-&TMR^Cpx$ zf$Q^VDZXIXq1MQ}p=87^12Sa)odImo_9h2wf8eD^->u#J2i@szrBofQPmAcN7i^~4 zhMLV*bG|$L2F&r=VZRyg;P3V6f!pzqN?-6lJ~%q)oO-yi|7}Czzf20JoBweiw;!na zb)6jmcqi@t{)Ak%rhn$)ynvF#afpqw_`+)-)$N=3prDQ*=Ouu800X--JGwzf&DHDR zrU_8=!O5}m(dGvxH#heI7wq#(t0oDGnlbXX1vk+xPTx0bhU`nc;%&|ERv5sjI2?0H zhG?VMJ^NB6u8fOGAb3%ydszzrMBh3gL>*dW+6|l+b+F&kc^g4voh>FG@O%lAwnY}{ zTlXh0Z&0A^y2uVH}@^W9_@qAks$dw|y<=n-&1^zX8xw`~4SZEdPI z66S+J1yA8No&HXoi8gRGuDc0iWzgIi_V0l^J}8l=T0%9`bj_*{ny-B3zgEjXcY*Ij z1wVeJTapC%nxDuEsW3TImvLkY71aGp`%(+rqG!1m^6u~m;=;>H)X9=#7q9*??LXK~ zBuA)=etrqz9&huMU5?++M}G%Syd>t%W_!Ig6j?1UfGn!zY6!4Xq@>pbhhlGc_#%K> z$Q2w1NiX1*H`vGRL~AV&hV1n(FY3%Keg1t&pLqeWZ$5ux3Z9WSaV{BJJdp2pnj{H5 zQrTT3UJ#PICEHI*{HpN~TvPF}YSwJ@rXwRzM8DEqhUav}dpZemuubJD@J}|a#MC~+ zK3oLK9i?0lo?xqZumQJ_>(&_jJ6+vkT95*JyHek!Z{04htwrP;dMlCf(uGcKQMSpf ztW8_jCJG-QxaX@7?$X^ALQGp1dkwNvk@U)Fyj?LArCSrz z8pk&Ruf~~)S-4uX<@P#hCD;y#nxsSN9QAnp5WS};xrHWw|BVP{yH{yXZW%Y*|4CG$ zJ5RvyQ$HnL&;@w*U&EZt9id!(3vY}^Gkk><6e^%`Rq?Inu6lhem`kFqPuH1oHcbK= zxj*k%&!pmnK%Xx-xEqzUuD^Qw>P67o3AQ|WcwI+RP@w_r^$gEIcQ`{|b>qAmwMxs9>yjaZrgU2+;_QvBUc zJJ|OjzX;Yv{E()k?w$bH;O^f88@rhU~Ij#dx}Qr>Pj zS#I^XN&5OVnj;?q26m12C+AF8n0~;&?FgMxDj|SFYOGkGy_=NzZVHt#lcv8PXlOY> z{~=kY_Jl;>L*hj3yq|Y4JnWcAnG$`Yj)=HJCFQ}@x^erC@}WJIgGO4$nphyNW-1%e z0K^(UHQ#s@7BtCrdyOpor4d(ych|ks>}OFsc?$TvQ*QdOTcmzI`-s-8ThDnndGv)tmU!98NJzyLp&Cv4@ex?a5rBcmAZ1M*OlV-Gxp?o zlfu7$@6rt6ijv4F&}w)%yPjYl5uT**|9G{-%)8clEuKP;;2|$oKInA4Huwbg>2MLQ z!%I|4BbmRY`Ayfet~AB$mfJYKSGKG>``EN!Sb~H2uX6vH3d07l@ExUc zv2c_^zXwM}qL@e$mYi5)#k@V*y~`WJ4bR+OjXBX-Z#)K1)!df^Nb?}&`J^wdALILd z(glSx#2YBzeDiGuzvw0zKsis8Pp79wc6xVsM!u0YakWqYHfIoHZONh(?)&mDlG${Z zc)wZ;Erl2BlWiV;vWG6DpwFD_B?3!Bw8u6@-+bS4vax@|dkH{o0fXWC(l@6U58i%$ z3G`LZHIdugj%!HvbL1r1-wmA%ZvH(@<|zSqTm8ob1&{WJ(q8?;4I7IQY^^KAt2;nA z3-F;L2UHNVKlKul@5R#@;S(n@)fvwMEk*3>hk%}BBf<4RtYZMA?;ap= zs$bH)UR$im_v+{EB1>JcDxC7r=Q>k_i+5t07I(GPJ&+gIov^CKEK`#wgq0N~9G@bm zRx2oA6lv9UdA{aa-5YSRNm~1z7A21DbAB2cTZP@ppMyTdyt8-qX+CbkmEXp(PR9d{ z#5NYDyw?|%>7K?-2VS3cZ|`&dea$hUJ0za$00lDqU>FT+Y84wNPC)q(aX!#A99>O6 zb}Q-g2<%f#GcufAqR#9MTd z)y}mt10be$52%*LM+2lt00aO0*D-ebuzow*XkYbTm3(%84v5_37ZgaH(*auYp7IO7 zNVy6Fl(vGtt4NPC#Tps9Pd|tIlmhPKa&Dlef0C~`GRu+@NK3WmELVK4&a^n;!e6;_ zcQN3l5I}ZxLkXOcojwrP=Ym8=)I{56r1BB}6~qJ#qGBKp_u_cp_s7q%oNK1n0WMxl zH4?eqHyY+_-U3)RI$RQ%w=XsQ*Wpk3lM2EB^av}%b}enWjV&;K@I9RdV$HB45rV7h zxP0?0+l+7rWSd00ReLz2#sH9HqaBoJhA;j$`aKAUd|=Y(pTQ|zE|eZ&Vbj*5c?vM~ z643jIUcfrTrn~s$S6X!mHBYTpPuK=kVp6LUAafspfQJQa+)-7@S@pQPS3t=;-G>#h zp)~w7o#KckjLC_g1M>h1Ozg0_uVw@Nq|YB&Gc{xPKD_FOufKZx`n2Q;EB+YFOp?MJ zkrV%S)dL+UD$~C;t`51+_qLMzgpMie%D`h?PmYSUee5eux5&K8hIJ$aR8lpWfmyQ6 z^@{xMEkKT*{fK+)vNQS@?s0C^sEG2Kn0_+B=q$dLs4c&k$MncB4x?944eN5{mTB7e@30oa&M=` z9C7aVQ#r;?k)5bKXu`Eg%bYa-_Qo-=N7d)nl#gd@q#tIMbE1o5uYx1clOnTAA60LE z`-;`M1l~?%xyH3Gs#wCmt7i&L$sdh+8xZ|B-N{JXdM#Jy+J~?2vD8~ou}n+AKPUPu zii&tJ+bk*@a#4V=UZRn}-MIx4qy1*6@933l1RjO($i6?%>ioZ8S4n-V3)4G5relmX3^Z(OJ2nc>7Y|k91!kird4}B*GfI z!>My1r6mmI>NIk0@j1egeM6k|or*Us2L2~H=5x@YxX|S-Bht`8A$pu-E}{RB=9ze8 z!jMSDNv{BY-uJ<+(gU9d;a@W+$ALa#xq*VXH^yTw-t3nr{q*txQ9 zs!jmCNK*F`IM`(E07z=dNu`&2Um;idAe5? z{_zWGf+`~{1)byR<<0V$r&B@O$DOUrF_K3&83XPUc-0_u6s<^Cv?45Rqzc1P@7H^6 z)wbg?NcwduJw>Y%N-_009~c+L7I!k?g4`K1)%-Do3;Rt?j_zBxcZs6zshf5yOB=ma z|47WhO#iD*Sj;t&NZVJvKK*HvQ`QnGa2fn${DUM4q6n2(0tM$&m zVhYrZG%rWzH8}KkCiG8La+eeGp{TR~H8P%I&9Cy{g((x#^%dXRZ`#RqpDZRm;GTkt zt(#*80s8nuyJK6d&0Oz+pie3u)4jfS>zeS*grg9Cxw0)AP- zdEMYGzt}6Lz^xUYK(;VbJ$ zzhN;8Fm9bfSHSdmr1D?|C)M$iOLykCoIMT>ISuPxsY7V70Ky7di2K0?==7~J2LVk6Yr zNZ=3tm~su%yXwkip1$hdITAS62pG;WlQ8>{xyIz^_-@D4_;}k9*lW7Zm(t0v_=#8f z9Cmn<&U+VkjGeqD2C~90#TY$Q2V1fXWIlu6m3_covC^Hi{pN*R0MnFbgSM7Xf@~e-Y&!mP4CZh+c8~)krz>co2;6hUjxbb z(SG5&LoeH1c>tbC(=fTI6nhoq1vMV2_8tckjEa*YCj5gc%|}&GD}8F+L5X*%NV*#C zDwVGY*=R|-+%1})hy^IqnTDI~{a7fx`aZ?GXrWUd=KkiFG+3Jp-F} zxRVt>wM085eRe+H|F$CH)2Yy}s-YYDQ?cJsuNoy7)RogK+tLsDt0Q`JutR%34mWp|P~9QaoguK-@PYus~6hf~i9n_Mjd48Ejd z#3PB228yjT*R+qxgKZVUvd-hy6 z^wovlRHnIy;q8)kV&}JhyJIv0o7mSLX^oh1he>kdy?D*V?VKbD(HXFA;u6ydp z_bVElRlfz4+Y~T|e$6`}QRRI%>3tBTi(FZ@3_ypAjRTcoT{92eQg98KUR|OQO`Tb^ zF&K3{8kmZwCu)A8i+=xoD}G_KjMrECsNZ*&*y7^JCK*F&BHnPiZE*DXdyuMgdnnLBb@ z9WfX#cU%hJJE#TcEc&ADiXC9+uu!RuRExn)Fh(Nt&uT8^pRZ=^$+NBqOz`C7&QUX?f(1ve&U>`so zKXO#JbL3tHH;@^&*W_Hcgtp+P#}s(8W+t#eudF`PA}*2^s#bwyo|bX}w2fz(l|T$d zGq@MH@tYGoX-k5`DNy9A`HL<`g0rgcA6)*4LNGNyVnlegubHeBb+&7t{&txaKpdW4 z1J)K(z?c%*Hhml%6B4n5V6B;IFydRuelrmh62t}+o$r*N=ytS`4_@P;euI_RVzcFL zX+;-mk%v^ec7j_@wsO7gl56ki`IRQ-=Y83-q#T3?Ke07|7f;0ZeW$&yo!wt)F7L$h zbuw|M+v+BY7r|4c)g5hOXk9kzs!udRIZ!IdmdwB4Y9~%OHlL&O&vD3D`0U<|@k8ME zJGz2*`*;!Mb`LMr4H%QdNVQv=tm3JKgI=@L&5H@idmkra(=be6ef|YEXUJp(&g{fT zLUgD1>44!nR}EEfJaoU-klY=Ri`r^I*WNFw8PfwbKmBKy+^Y5(hxWlP@(-Z$=Yj}a zr865eBqFkya>DNizY&yy>Wvvd`khQ=<;SQ?CDGfukMy|L>Gbrece3FNXlA^Er^*A3 zO)2@#ps8-$0z`7V@yMb`sC`ba{F?SWW*f1!+vZ}lkJ(({^%0hI`~BWdct&Qzo9&&C zz6a26=TK(zQw7!@9lE?SRe^D4BVGxCzp1GEzzlg5lcqQd*%q=d+HG@R#Oyf3gb-@( zrJpIwGTh{YigX|TmMHW1PFlNDJ_HD!%K)@a9lDcKi={wAEYL1ng~Prl5<)J+J(8E> zYsQT{%VRz1sfg-=1xea<*;XkTj7tDYo`4W3+-Kpek@seTR;5y> z8Kv;wUd*a?VJh{5VNIM7amE4}TowxBJuPnDPg4K3R7wkOm|lt8_Uye(DexFFx!bc* zPr})5IH2oyT%lgpKvumJ9%UexkqDAp73-fVEx#yNg5r+C1fNW_IrqsHL$3kwawEpS zzAS*AC}53A#?P@F`3!qq#P}GRyqZFT@zC4=MsZNsa=6!a1RaRsp3@%~RX3cv` zFCK#LGrEED!=u`cL&*qoyv>WC1VW#uo$)Ih`?gow1G5hFO!nuFKQ(V2*dI>oCr~}l znH8mfGiDm>x|v&g_XSq&23VmfKmP?-aTD6BHlcLbYEHhc0)3RC`CD|=_J{I_xOI#$>7G(u=zm6 z2~mJ{kGC9=hk9C4$cwJQiKiQ17f5N-UlYJ zR{u*1($8nzzl%+FqrzUNc#9xznRQ}bZmvkkD{?VZ%HkrC#|9hNwyWssi55s`!#wHt zxR%KdGSsmnPlXvIlHX7Y^&^;8`#PmI8kyf9w#@drv5eOM|K)?R@C@1MOl%k1(WKFy zRl`ixMU$nt6$}5Rc=Ij3@W!nQ?Q1_iif$avc@s-o%rYy63zFs}T2f(jrOJ6%8G46S z6jn#xOnxzDUSiPWnF=-Ku@I)bW6iGX>marcuG011wP_jxz3z+=RERs7*%NR{zrUycf3V_fQxa`4OA5fVYWOa-#_N!sx=HC zl*(_E9|jH7q9Yuc-ol6I)9&^S6fXtg#*I_soS$W@z;fup+{*AG4JmD}Q^%V|+l+>$ zs(aV^L%6~?Td;`1=<%N8;iIQoPgrS(V&;YlaZhdOT zWqD}#bbKS$N=47{yHSLAXZV0Ps$K~xUU7I-kF`BhRqC;iX!#?v`;GB%x1{_<5h9|x z7PFCby@<=7#1YMPeA7EXWc8Qa58Vkd;pC3kzNJ*J{o|TAO4|t5(!hp)e$0NJt zox>9OjlBU;<(8?|M4P_vtycaG{EXU1y`k+}2oFi0EtjloG4xUo(ngrU4_&2TVWy1%wu%F9M@KECrNo(kA?b8dd3qGO}#Y} zQ@=;nnk8%Wn`p8|7?g;}4eIZE`pIcusQ%hnrmu0xd7t2% z4r`i_PDGQ(>!4H@FBg0o+}D5XXCxQbrYS z{Ul9-6!JI3nwtisrC0N!kZ4z&DUfyDT!(otxVDRq4&Jhw5v3#wpwAn5EbrSN}(DK7?G$l^#r>&YszGOWo z)MfvR(=+LE_*%(qs*Jy+gS*?{ z8u$h}4@s;*)$A0Q-K%(5z&ac-|_SjZnK777B9C6a_%vwsU2#~%v|RC>brLg#S*F84VH=IW04S8>yfi+NuJIs7b`0N``4%;XeW99~>Z=D^#STWr9PC@ui(b!kW! zw`)VtO+?0_@2dtL1Inr!a0&zHG0DmXxViUrNq~`(vwO{%8*(weIvHTx`S*@kD@87HGz15?=cak5U<)yCZBZlV86l5n{JyrU9Y3{| z2Z$k%Yx21<`>Vr*SY6Gq-nB%p60{v}sLs^ay`kkO+0KC{_14vL5>m@M#<;V9!JsE-#EtyDByQ#RT4^_Y|Riru)2pYR>W=?9L_t;bXcAapNs3KL|@xET6l;&T)Ht&%s0?4o?i z=mt*4oC^??-9yU_1G@V5f_hP2d2>Dw?yC%baT2}D64d`X>8pKMMZA)s>QWh(s~0CL zwo|3$2bW0k(50o-NYl=fZWovR32d`~KxJmnN&mdnFL1-2o*3>z0|>*19(g(ATr z7zG7vmZja0JK{3Qe)9^@LTn_^3*&6`@3zf8V?0Tp#roq73GOt|qvYAS5vPQ)(qv@t zZe-9Z!7NWW7Yy0-DIbzOsCE?(nkBLJH;2&4`4K^vGRNl%g(Y{C>@~~sYWEjv0TdKy zqAwr$(>{>nK-txRh9_q=J=G;aR^MMhLc{pay-RG@0P@$ z{zw25PFf!~)$MFKat$y`Yxjqthk|!np7?XGGZ@vRQWFs!y*DieULmmxRGo`Uq{VUe z!QIN#%N)}GdW-LiUcsm%GER5bcML4$B@hgk7Zcaw zv-5onDu=E5wCV>RU4+@J{S1?B7o>hOrgOV~J6#v_Dq!z^me4v@uo;W zewxVYLd1s-^&hOS87>86w4U@Ubgzg$Jaak6rw$$cyc-U+PZ|GgvFZ61+aVXP{TRb3 zLh9)_@L4J1~&E^ta7@s2GW1)>?DZv!<6J7_ojfo;4pS`iN} z7=x;&;dPrp9H`zE*_AxvE>W7^f}AH(BdaO&Jk*OZL9@p0H8fA*;26$6xB4k7%3uMB z;tFoyAhCsC2BacYHVAGf32vxSWXh3Na(R3>fuF{MC&{WUWe zTPl0!2ZzGAX@Z}8hqr}fTLe{f_m6bwIKBMIh&FvQ898B?ULa@- z9B5lA!v=|?ZrE|tcRTNCfNKIU(XHT&eGs@$8}p2RwU6QTz#!emFsI43A-$DqBrEOD{yk?OTPHKq^WrY4s3zpLn7HR@HkZeq4_bGx=mt-Eii2A;TAEqU!fPc^95w2v&V z^)lBLHq0U)Ldpw9hbG=68@HyTIP7EB3efhl0}Mtw#&HVwwq1&T&0>7Enu%Vb0zSus zxvwB}%j$b?+z)+eSnYPY-ufj8Jw%0)-|o)@aFZ!GGXIEx4zVAHBa-=lj{$de7K3;aP}Qv-B;wrtm71NlL*mFC20s9zU*H*O9PYYnZ1?s>2r5Ihu>(@q{A^$g8|gs1ghP(CcBvtm(HAwif3nB$cz$)-%C;2H&k*# z4)0a$UWpV7jvvdmOqFVJ2s4dZWDBmzsS7HEPVT=EEX0be#SxFI`<<3AnC@<=h-uQ6 zJ%K-x0rd-FrUy4D9O^o@3IY2u6;THiUDp%V7LHIay}(HT5ok{Vh>?B&F3nnAsd|~0l3fXYMs$7ma1tOc1XbcZ!vOJ2 ztv0ksX4G&UN0xs@cC5VkWN@OWStODJDFP*oB`W4Qv-c#g;P7K&>028+*?YmDtBG8+ zmJqsv1qetLqYfN~w0M}jIz6;5nX+Gr0X<{`E*5Ii$&)Tc)8cLN^wW1h!G7e7s19rP zs2ncEY_FuqMKtyb_JXH*t%a3Qjf{S345!~>`|K#IG;QlqFe;=onjyCDGGLX>9--S! zHl|40Tt%j6{Eh(oczc`S%jX-qdS;kxHW6I~FB8yP1Gezhr+LFDIY_TscMNr#eoLL+ zYrQH5@g)C(V)gPk<|v4uUDRN1n*T=l?nN&7tNqX;kG!}Td5Fd%8A@ig{bte9pL+XN zW_X*S!|H+s??iKT*!WUjP_4lV?qNmiuwr&$Lz=4br%GwRP2BTKM0RhVfN2(1!XZmv z$1Vy-0ax&ejK>eqyNtwGqoeq@gfmYxVscix$w|1>@fDg)b_>&iWJy@itFkkN|2-m=+p;UBcQh;z|qnn_T5BrMw@Y?_zp5ZPqR{v+_ei9<^yFn!m^s*6Y``auW{e|I7%glygbb-*{#K*fgZ#dXE8JUoTR$6W6gk-rtYaG zjI`qZ0^DG>`J#ww$B>9WyX0XlYg-PPjA$aZ$l^upjy@Y#^|u9PI?#t< zgF`;bnx(PfwQ7E;iLyC`$wrj6xe9(?wfZ{bJ)vKRUauuY4R(7~I-2Y%#*_t=sW=cT`wcHg>59n^^HXKEh`F`YIEbB|{A324SG^WlvLGAwUd6Y4xo2)ulHZbP zeW?57-u-jkzp8eo`$fmYqm(+V9eJ*MyR@iWZBet+)K+~~Hp-1olg|UO_YK)LF$>X$ z_mRs&1|qW6K`OFk5J@Ns5!#(O^Ru%{kyxCdnDw(FXz;ovhDB_rqfa4eH$v1WP;(~s zbolWVbJtAMx;JFp`42IgzzZFdkHi2 zFdFvYl;RRP&UMG9F}oKFvQ20k;qgR}eC%Wmj3hK@R+Od&hke*t0|Xy~;@HGJYuR4y zwVLwfUE@0*j$o$Mk+gyO^qy3-bw7nnmEDDz_<0mDvVB!FTAU8)`zd-lP$9zTZs@A` z%Ma7FiDy00^Z2EaMc#WE;8nkwkvlZ4tUFD$_B=a$+p|6NSVQ#jE8d(8#kn73lG9WN z1^T>+J)b~jA=xxs=-bmHtI5Vr;m0vaR@Kiy)y`K6Fm#f+0_b0bKH+k8mOQQ z=Uxe!{VID+2QFUtQ%@aS{=8PV1zeV}68=$m`ko57nu`{DN+wSiRV`Sa7-!`NWl6M? z{xO?$CQ5IgT)5b5 ztAfp}c){fr=c$^axWunVg$)iY zqdB1NcwbQi#|TWhH)XDQe13wqH(OVr25{hb`a1P)Oi@IiA~CZOS%z=Dt5w{kRzL1#`AOLY!IIqw7B{T6*g# zJrX;$?<=nWj*^UPD|NXM<%SDaBBwmK{6^1^S6m246Na{Z@x?$I6^UJ`b;;e6LLNGY zw0~ivFXfJo&*cUh&!TL~@a-6u z^q#E7M~X%IHx?9xP9s5xVJmZMHn~KFT21l{a{n4#_Km`-07G(wns_CzvieIz@3UPc&VqLYYzV&uoPaGGN9eCVN8$2i}STI3hRP^)} zSkQky8EG_a^%INOEl@QmNojFYMa~p@R*fqBSSV`!m zKty5K40zLeWD>L#^FTrfXhL5GNYuU9#c+v)2GL8E(n#_pNtd_AHsr@g&#K%awpt0D z-c(iHpzK0+gyB(Z3e~`x?yzP;B-4_I$LqA-?i}@>yvbF%fLioO=)7447FOY0ahcww z_z*dnD2j&wi8gu)IqK3Pkz+_alaFI77x_Zg{#dz@ea%4jw+6P$W#Hl=pO*Ok8!Q9-9*3<7>#}=E)Aw*EA%439BUN9L(74g@h*b-s6`TDwhyjieO z>%DTjB}P|Kl6d6iXW!6E)fWK5nV}toR42*hY2)Eku^Mw6=$NZ z)Z8j7HAL1s)D`ne;4guye#JS3w6BUwUa6C2%G%_V+O+L9IXXpPj-j#Qv+a3=s*=(wF1hkv{{6Fd-{);K+mA=IH}N+D(2mPj>$ zWUfz$vGZ*V3VAboPK~SyX(XZubBj2vclC`79mM0IHYzj(J`n z`H0;a7ivFy(cOU2;Q;Q>amIxb8OEL`6Q!uc_vsDPjL_w!E|~f#+`<;+Ir7$q$w2lS z8MiBuUFZgBmF~9>RQhL3pF-$mo~mDOG`uY`x>sz~tT;Dod*VGzvX$gNkJyb9<4Yk6 z)Ycy))in{cVlGH1&|Z#$6#hKOQ{XNpf03T&EUXP%n<^K}J>#kL5&~q^1&iN79#WHX zAVUHG)4mKf*|YwLuz+^9wHB|udW2@Xee|~mWvDWbyBR~LPk%eAF6_f}oKIUqS(3eX z4R20)_t4Kyh@6_S@owA#3dmhoz%(>iF>e*(=j;o7e14CeDlEJKvWfdhtDIGd?SQmC zK)`#OHrpm=b56(o|1<}Yi925kqWn}K6QV9%kS6ij-P(wit^<4472y)R*URdG3SGyq zIz_j!=p5M`X{x8}ecJ`deXliW*~vi;kXJDHMveHBKKTF=!rxm3DS}3oU?8BbxCSs! z@SANJc!MnwJ73RK|D67u{W+tXlk%1N!~nQ&nFCcwHT7-Isdq|8!iQT0oSLK!(_iN zC$CcQ(_lw%buWg~+UNkvAlm4lb8)y+J|Z4An?MViRv>)MLyHD$M61gbe(@b$m`@+UaQN_xf zyHeHp*Mwa=7yKxnf{8ydkqQGfOMn4b`0i!;GoNpn@IO=5JG-Jz_%KvWVmJH0{eoT% zqw8c7?yvZ0H%EQ|v6qG=OGh$CkCmpU1izpnz3ogiQto4JRtb_E6I`vJKA>VAFgba| ziQ|c<=;>S*`T6H)&r*DV$(8*xIU+;ZGU_p^HL}C)tu0#z(hQgk^~pTK?*MsQSOxVg z>%i>l{>VRusLS-;@ORNu&=wX?86tJtgQb>UqNo?2E**mi{ zQ6j-22%NE%k(18V+I*+8QRgcqBud=ReQP{;7K*j#=Jh+u`44sVnflWo0TK9j%k1?3 zL)-mNfPZ!rb_@^t<@?V*p%lu-iT`&lkz^CDzW)hR5%sg3XDbpxuMv_P36F97P@2gS zH~JkX(Ci%LBPx0L)v`Squ{lbRh^o;5U|!HuFVWRW?n|xsRW6?R3uQIH$rJg*^8g zW`H_Xz_tPCYw>SBtEDz!(WU^dbBOzl>qKV(-R3{3`hoyK2O5_s%bpRP*tI4}z)#{m ztNRg9J^u>4tnklgywI)KIj2F?vBo)-;52*|CI{B*;lBb$SuDhQ$u@Zr!+m9gxbt*w zYZHm`W%-l16nJ<;m1lRo<(|Gfrfjx3%R{a(!#mdaY)1Vbu^kJUmtre!h=bP=&0(OVSuN&r+!A1h!{ZB zZl3*(9s3`-Xr}yEF1*fUJQa}fb#27WOwZ*ApiR>a5{ruf5SsB5iyW`6&5}C$YX4sn zF8qW>!J4M6;`UoA!%=cA!0RI#Ty7(A4;}a4I{l**HJ+S#dVo>^D)yYuE`@$AVkgvh ze{WByKBOO=bzSv%SBCgct_!el{O?}ByMtvz`C{~*0b6_NECZ|J2?V?hRsg!_2nU~` zpUv@HrwmQn+TYSsI68AqR z_&moNn3kPt6pokF8wWvY)xTR8$-Hi~fAo-0FXDFZW%B)u-pzkWeao{&@M};%6ZCT+ z7f1ZA9B)rA7iByDKz`bvc@Y0A30De*o*iZ%pP5Voj5koyTciJ-q6bI?7Qt|XU^V^! zI&sGQceS$|u^r`^fusp17)VKEeoE(Z*ZcRM*+``SyJ()>E=`0*%Z#*jIJEItL@|=Z zNFU8;W{N;5UbyW}d$S?j*ytLTmz@?!>)!>7=nHqz5atzd=iGqdI}9|C`P>5s;>0a6p!oi^)YfMW54L8SgUy2h6O%A8Nu|3%0A6HovBztA!9ZI931 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