From 046439a1ddec206706e368527f307492002dc18b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 25 May 2012 10:38:15 +0200 Subject: [PATCH 001/548] +preos ideas Signed-off-by: Nico Schottelius --- doc/dev/logs/2012-05-24.preos | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 doc/dev/logs/2012-05-24.preos diff --git a/doc/dev/logs/2012-05-24.preos b/doc/dev/logs/2012-05-24.preos new file mode 100644 index 00000000..e4f988a7 --- /dev/null +++ b/doc/dev/logs/2012-05-24.preos @@ -0,0 +1,72 @@ +Todo for preos: + +get debian installer (?) + x86, amd64 +configure sshd + add authorized_keys +output files + tftp: cuni: curl -s "http://http.us.debian.org/debian/dists/$version/main/installer-$arch/current/images/netboot/netboot.tar.gz" | tar xz + iso + + +http://wiki.debian.org/DebianInstaller/ +-------------------------------------------------------------------------------- +debootstrap: + [19:33] brief:hack% sudo debootstrap squeeze ./debian-squeeze + [19:30] brief:hack# du -sh . + 213M . + +install kernel + [19:35] brief:hack# chroot debian-squeeze/ apt-get -y install linux-image-amd64 + [19:37] brief:debian-squeeze# ls boot/initrd* + boot/initrd.img-2.6.32-5-amd64 + [19:37] brief:debian-squeeze# ls boot/vmlinuz* + boot/vmlinuz-2.6.32-5-amd64 + +install sshd + [19:37] brief:hack# chroot debian-squeeze/ apt-get -y --force-yes install openssh-server + + - connect back? + - generate sshd keys? + +-------------------------------------------------------------------------------- +initramfs: + find . -print0 | bsdcpio $( (( QUIET )) && echo '--quiet' ) -R 0:0 -0oH newc | $COMPRESSION $COMPRESSION_OPTIONS > "$IMGPATH" + + /init for booting + find . -print0 | cpio --null -ov --format=newc | gzip -9 > /boot/my-initramfs.cpio.gz + cpio -H newc -o + find . | cpio -H newc -o > ../initramfs.cpio # <-- this is the actual initramfs + + +[19:39] brief:debian-squeeze# find . | bsdcpio -H newc -o > ../initramfs.cpio +[19:43] brief:debian-squeeze# xz ../initramfs.cpio + + +-------------------------------------------------------------------------------- +cdrom: + http://tldp.org/HOWTO/Bootdisk-HOWTO/cd-roms.html + +-------------------------------------------------------------------------------- + +[19:34] brief:hack# chroot debian-squeeze/ apt-cache search kernel | grep linux-image +linux-image-2.6.32-5-amd64-dbg - Debugging infos for Linux 2.6.32-5-amd64 +linux-image-2.6.32-5-amd64 - Linux 2.6.32 for 64-bit PCs +linux-image-2.6.32-5-openvz-amd64-dbg - Debugging infos for Linux 2.6.32-5-openvz-amd64 +linux-image-2.6.32-5-openvz-amd64 - Linux 2.6.32 for 64-bit PCs, OpenVZ support +linux-image-2.6.32-5-vserver-amd64-dbg - Debugging infos for Linux 2.6.32-5-vserver-amd64 +linux-image-2.6.32-5-vserver-amd64 - Linux 2.6.32 for 64-bit PCs, Linux-VServer support +linux-image-2.6.32-5-xen-amd64-dbg - Debugging infos for Linux 2.6.32-5-xen-amd64 +linux-image-2.6.32-5-xen-amd64 - Linux 2.6.32 for 64-bit PCs, Xen dom0 support +linux-image-2.6-amd64 - Linux 2.6 for 64-bit PCs (meta-package) +linux-image-2.6-openvz-amd64 - Linux 2.6 for 64-bit PCs (meta-package), OpenVZ support +linux-image-2.6-vserver-amd64 - Linux 2.6 for 64-bit PCs (meta-package), Linux-VServer support +linux-image-2.6-xen-amd64 - Linux 2.6 for 64-bit PCs (meta-package), Xen dom0 support +linux-image-amd64 - Linux for 64-bit PCs (meta-package) +linux-image-openvz-amd64 - Linux for 64-bit PCs (meta-package), OpenVZ support +linux-image-vserver-amd64 - Linux for 64-bit PCs (meta-package), Linux-VServer support +linux-image-xen-amd64 - Linux for 64-bit PCs (meta-package), Xen dom0 support +[19:34] brief:hack# + +-------------------------------------------------------------------------------- + From f41b029adedf98a01343ce19539111f71013911e Mon Sep 17 00:00:00 2001 From: contradict Date: Sat, 12 Jan 2013 19:22:23 -0800 Subject: [PATCH 002/548] Eliminiate excess output from machine explorer command -v emits a string to stdout, silence this since we are only interested in the return code. --- 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 bb6e0beb..d4a0e106 100755 --- a/cdist/conf/explorer/machine +++ b/cdist/conf/explorer/machine @@ -22,6 +22,6 @@ # # -if command -v uname; then +if command -v uname 2>&1 >/dev/null; then uname -m fi From 77e92ceba9d1964f5f4ccf035d3e04052c1040b0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 16 Jan 2013 13:13:45 +0100 Subject: [PATCH 003/548] update changes in log file for dependencies based on discussion --- docs/dev/logs/2012-12-11.dependencies | 90 ++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 15 deletions(-) diff --git a/docs/dev/logs/2012-12-11.dependencies b/docs/dev/logs/2012-12-11.dependencies index e5506564..5e673b23 100644 --- a/docs/dev/logs/2012-12-11.dependencies +++ b/docs/dev/logs/2012-12-11.dependencies @@ -8,28 +8,88 @@ __git bar __package git --state present -require="__git/foo" git bar: +require="__git/foo" __git bar: __git bar __git foo __package git --state present __package git --state present - __git foo - __package git --state present + __git foo <---| + __package git --state present ---| -> detects circular dependency +-------------------------------------------------------------------------------- + +require="__apt_repository/somewhere-where-you-can-find-package-git __git/foo" __git bar + + __git bar + __apt_repository somewhere-where-you-can-find-package-git + + __git foo + __package git --state present + __package_apt git depends nachher auf __apt_repository + __package git --state present + __git foo <---| + __package git --state present ---| + __apt_repository somewhere-where-you-can-find-package-git + +possible solutions: + - __package git does not depend on __git foo (clear dependency) + - because it DOES NOT depend on it! + - but we don't know whether this is always true :-/ + - multiple instances of __package git exist, with + - different required BY + - different requirements + - define non inheritent dependencies (?) + - because __git bar really depends only on __git foo + - proposal: introduce require_non_recursive and require_recursive (previously: require) + +-------------------------------------------------------------------------------- + +__package foo + __package_apt foo + +__package bar + __package_apt bar + +require="__package/foo" __package bar + + __package bar + __package foo + __package_apt foo + __package_apt bar + __package foo + -------------------------------------------------------------------------------- -__package abc - __package_apt abc +__type1 var1 + __type2 FIX -__sometype def - __package abc - __package_apt abc +__type1 var2 + __type2 FIX +-------------------------------------------------------------------------------- +facts: + - use is different from require="", as use makes USED depend on parent deps + - use = called/defined in the manifest of a type + - it is currently not recorded, where an object gained its requirements and autorequirements +-------------------------------------------------------------------------------- +requirements: + - a type should be a black box: + I can require an object and it is ensured, + everything it needs is executed before me. + +-------------------------------------------------------------------------------- +possible implementations +- requiring it should include everything it USES +-------------------------------------------------------------------------------- +solutions: + __type1 DEPENDS but does not use __type2 FIX + + -------------------------------------------------------------------------------- Change proposal: @@ -59,14 +119,14 @@ Order: For __package: -__sometype def - __package abc +__sometype bar + __package foo -__package abc - __package_apt abc +__package foo + __package_apt foo -1) __package_apt/abc (leaf node) +1) __package_apt/foo (leaf node) -2) __package/abc (new leaf node) +2) __package/foo (new leaf node) -3) __sometype/def (new leaf node) +3) __sometype/bar (new leaf node) From f16ac1911ddf86eee5ce8b620647cb93b0b7c386 Mon Sep 17 00:00:00 2001 From: Jason Staten Date: Wed, 16 Jan 2013 20:46:23 -0700 Subject: [PATCH 004/548] Set permissions on existing directory Previously, an existing directory would not have its permissions modified by the __directory type. This change removes exiting early when $state_is matches $state_should --- cdist/conf/type/__directory/gencode-remote | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index 21f4c5b6..e9023b60 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -21,8 +21,6 @@ state_should="present" [ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" -[ "$state_should" = "$state_is" ] && exit 0 - destination="/$__object_id" mkdiropt="" @@ -32,7 +30,9 @@ recursive="" case "$state_should" in present) - echo mkdir $mkdiropt \"$destination\" + if [ "$state_is" != "present" ]; then + echo mkdir $mkdiropt \"$destination\" + fi # Mode settings if [ -f "$__object/parameter/mode" ]; then @@ -50,7 +50,9 @@ case "$state_should" in fi ;; absent) - echo rm -rf \"$destination\" + if [ "$state_is" != "absent" ]; then + echo rm -rf \"$destination\" + fi ;; *) echo "Unknown state: $state_should" >&2 From 61747c4cb74087d028ded0dcbc60cc9a9140c4c2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 19 Jan 2013 18:24:17 +0100 Subject: [PATCH 005/548] ++comments Signed-off-by: Nico Schottelius --- docs/dev/logs/2012-12-11.dependencies | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/dev/logs/2012-12-11.dependencies b/docs/dev/logs/2012-12-11.dependencies index 5e673b23..1c0adad8 100644 --- a/docs/dev/logs/2012-12-11.dependencies +++ b/docs/dev/logs/2012-12-11.dependencies @@ -44,6 +44,13 @@ possible solutions: - define non inheritent dependencies (?) - because __git bar really depends only on __git foo - proposal: introduce require_non_recursive and require_recursive (previously: require) + - recording the source of the dependency and use it to assist resolving (?) + __package git: + inherited require: __git foo von __git bar + __git foo: + inherited autorequire: __package git durch Nutzung + - break out circular references (?) + - if either of both parties is only locked by the other, allow execution of this one? -------------------------------------------------------------------------------- From 7a41d6d8fa283fcd9faf3877f23dd3d18dcc1ea3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 20 Jan 2013 18:11:47 +0100 Subject: [PATCH 006/548] __file: notify when doing changes Signed-off-by: Nico Schottelius --- cdist/conf/type/__file/gencode-local | 1 + cdist/conf/type/__file/gencode-remote | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 087011c4..99456c5b 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -41,6 +41,7 @@ if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then if [ "$local_cksum" != "$remote_cksum" ]; then echo "$__remote_copy" "$source" "${__target_host}:${destination}" + echo "copy" >> "$__object/notifications" fi else echo "Source \"$source\" does not exist." >&2 diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 8b03e919..fa2adc6f 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -38,17 +38,20 @@ case "$state_should" in # Group if [ -f "$__object/parameter/group" ]; then echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\" + echo "chgrp" >> "$__object/notifications" fi # Owner if [ -f "$__object/parameter/owner" ]; then echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\" + echo "chown" >> "$__object/notifications" fi # Mode - needs to happen last as a chown/chgrp can alter mode by # clearing S_ISUID and S_ISGID bits (see chown(2)) if [ -f "$__object/parameter/mode" ]; then echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" + echo "chmod" >> "$__object/notifications" fi ;; @@ -56,6 +59,7 @@ case "$state_should" in if [ "$exists" = "yes" ]; then echo rm -f \"$destination\" + echo "removal" >> "$__object/notifications" fi ;; From b06122f3a1314da4a82a2554898c70da6b4e3c59 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 20 Jan 2013 18:21:40 +0100 Subject: [PATCH 007/548] document notifications Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-01-20.notifications | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docs/dev/logs/2013-01-20.notifications diff --git a/docs/dev/logs/2013-01-20.notifications b/docs/dev/logs/2013-01-20.notifications new file mode 100644 index 00000000..be326196 --- /dev/null +++ b/docs/dev/logs/2013-01-20.notifications @@ -0,0 +1,20 @@ +Allow cross-type communication + +Sending notifications is possible from + + - manifest + - gencode-local + - gencode-remote + +Sending a notification from an object means writing to the file "notifications" into +its object: + + echo mytest >> "$__object/notifications" # a type reports something + +Reading / Reacting on notifications works by accessing the file +referred to be "$__notifications". All notifications are prefixed with +the object name ($__object_name) and are appended into this file. + +To find out, whether a file was copied, run: + + grep __file/etc/passwd:copy "$__notifications" From fb630437dbd73900e209d8c970c1d58df7aa8292 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 20 Jan 2013 21:31:08 +0100 Subject: [PATCH 008/548] ++triggers Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-01-20.triggers | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 docs/dev/logs/2013-01-20.triggers diff --git a/docs/dev/logs/2013-01-20.triggers b/docs/dev/logs/2013-01-20.triggers new file mode 100644 index 00000000..dc13c746 --- /dev/null +++ b/docs/dev/logs/2013-01-20.triggers @@ -0,0 +1,49 @@ +An alternative / complementary approach to notifications: triggers (or actions?) + +A type may support various actions by creating files in its subdirectory +"actions". Other types can trigger an action of a different type or object +by calling them (indirectly?): + + +if grep "__file/etc/nginx/conf.d/.*:copy" "$__notifications"; then + + # Call action from a type + cdist trigger __nginx/reload +fi + + +Not sure whether this approach (calling "actions" of other types) is sane, +as nginx should probably better know if it should be restarted "itself". + + +-------------------------------------------------------------------------------- + +Alternate approach: + +__nginx_vhost www.some-domain.ch --custom << eof +some custom code for __nginx_vhost inclusion +eof + +__nginx_vhost: + + manifest: + # __nginx_vhost requires __nginx: creates directories + + require"$__object_name" __nginx --require-only + + # Do WE or __file ... depend on nginx? + cdist require __nginx + + # Create file that contains the giving code + __file /etc/nginx/conf.d/www.some-domain.ch + + require="__nginx" __file /etc/nginx/conf.d/www.some-domain.ch + +__nginx: + manifest: + __package nginx --state present + + __file some-custom-files + + gencode-remote: + if first_install or file changed: From 1d933dd5d37da2ace58c8daf68ca800b755bcefe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 20 Jan 2013 22:02:10 +0100 Subject: [PATCH 009/548] do not need to create directories - git will do this - thanks to Steven Signed-off-by: Nico Schottelius --- cdist/conf/type/__git/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__git/manifest b/cdist/conf/type/__git/manifest index e8c9b233..3b52ad2d 100644 --- a/cdist/conf/type/__git/manifest +++ b/cdist/conf/type/__git/manifest @@ -33,7 +33,7 @@ state_should=present case "$state_should" in present) - __directory "$__object_id" --state present $dirparams --recursive + : ;; absent) From fc1a9ed27bc805bf0c4d75b39f715cf11e1c1f65 Mon Sep 17 00:00:00 2001 From: Jason Staten Date: Thu, 24 Jan 2013 22:37:52 -0700 Subject: [PATCH 010/548] directory permission explorers The group, mode, and owner are now pulled from a explorers. If the desired value matches the existing value, then no code is executed. If the recursive flag is set, the permissions are applied every run. --- cdist/conf/type/__directory/explorer/group | 28 +++++++++++++++++++ cdist/conf/type/__directory/explorer/mode | 28 +++++++++++++++++++ cdist/conf/type/__directory/explorer/owner | 28 +++++++++++++++++++ cdist/conf/type/__directory/gencode-remote | 31 +++++++++++++--------- 4 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 cdist/conf/type/__directory/explorer/group create mode 100644 cdist/conf/type/__directory/explorer/mode create mode 100644 cdist/conf/type/__directory/explorer/owner diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group new file mode 100644 index 00000000..b14794e3 --- /dev/null +++ b/cdist/conf/type/__directory/explorer/group @@ -0,0 +1,28 @@ +#!/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 . +# +# +# Check whether file exists or not +# + +destination="/$__object_id" + +if [ -e "$destination" ]; then + stat -c "%G" "$destination" +fi diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode new file mode 100644 index 00000000..3ffa497e --- /dev/null +++ b/cdist/conf/type/__directory/explorer/mode @@ -0,0 +1,28 @@ +#!/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 . +# +# +# Check whether file exists or not +# + +destination="/$__object_id" + +if [ -e "$destination" ]; then + stat -c "%a" "$destination" +fi diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner new file mode 100644 index 00000000..a691ac1b --- /dev/null +++ b/cdist/conf/type/__directory/explorer/owner @@ -0,0 +1,28 @@ +#!/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 . +# +# +# Check whether file exists or not +# + +destination="/$__object_id" + +if [ -e "$destination" ]; then + stat -c "%U" "$destination" +fi diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index e9023b60..154a46b5 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -18,35 +18,40 @@ # along with cdist. If not, see . # -state_should="present" -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -state_is="$(cat "$__object/explorer/state")" destination="/$__object_id" -mkdiropt="" -[ -f "$__object/parameter/parents" ] && mkdiropt="-p" -recursive="" +state_is="$(cat "$__object/explorer/state")" +owner_is="$(cat "$__object/explorer/owner")" +group_is="$(cat "$__object/explorer/group")" +mode_is="$(cat "$__object/explorer/mode")" + +state_should="present" +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +[ -f "$__object/parameter/mode" ] && mode="$(cat "$__object/parameter/mode")" +[ -f "$__object/parameter/owner" ] && owner="$(cat "$__object/parameter/owner")" +[ -f "$__object/parameter/group" ] && group="$(cat "$__object/parameter/group")" +[ -f "$__object/parameter/parents" ] && mkdiropt="-p" [ -f "$__object/parameter/recursive" ] && recursive="-R" case "$state_should" in present) if [ "$state_is" != "present" ]; then - echo mkdir $mkdiropt \"$destination\" + echo mkdir $mkdiropt \"$destination\" fi # Mode settings - if [ -f "$__object/parameter/mode" ]; then - echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" + if [ "$mode" ] && [ "$mode_is" != "$mode" -o -n "$recursive" ]; then + echo chmod $recursive \"$mode\" \"$destination\" fi # Group - if [ -f "$__object/parameter/group" ]; then - echo chgrp $recursive \"$(cat "$__object/parameter/group")\" \"$destination\" + if [ "$group" ] && [ "$group_is" != "$group" -o -n "$recursive" ]; then + echo chgrp $recursive \"$group\" \"$destination\" fi # Owner - if [ -f "$__object/parameter/owner" ]; then - echo chown $recursive \"$(cat "$__object/parameter/owner")\" \"$destination\" + if [ "$owner" ] && [ "$owner_is" != "$owner" -o -n "$recursive" ]; then + echo chown $recursive \"$owner\" \"$destination\" fi ;; absent) From 3ff7621984727c89da84f9155e0eb598717a3551 Mon Sep 17 00:00:00 2001 From: contradict Date: Sun, 27 Jan 2013 19:53:22 -0800 Subject: [PATCH 011/548] __git respects --owner and --group, add --mode After checkout, chown and chmod as specified. If already present, but not possessing correct permissions, run chown and chmod as needed. --- cdist/conf/type/__git/explorer/group | 5 +++++ cdist/conf/type/__git/explorer/owner | 5 +++++ cdist/conf/type/__git/gencode-remote | 27 ++++++++++++++++++++++-- cdist/conf/type/__git/manifest | 3 --- cdist/conf/type/__git/parameter/optional | 1 + 5 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 cdist/conf/type/__git/explorer/group create mode 100644 cdist/conf/type/__git/explorer/owner diff --git a/cdist/conf/type/__git/explorer/group b/cdist/conf/type/__git/explorer/group new file mode 100644 index 00000000..4be8c1a6 --- /dev/null +++ b/cdist/conf/type/__git/explorer/group @@ -0,0 +1,5 @@ +#!/bin/sh + +destination="/$__object_id/.git" + +stat --print "%G" ${destination} 2>/dev/null diff --git a/cdist/conf/type/__git/explorer/owner b/cdist/conf/type/__git/explorer/owner new file mode 100644 index 00000000..1f3c80e6 --- /dev/null +++ b/cdist/conf/type/__git/explorer/owner @@ -0,0 +1,5 @@ +#!/bin/sh + +destination="/$__object_id/.git" + +stat --print "%U" ${destination} 2>/dev/null diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote index 0f665d59..bc0c66cc 100644 --- a/cdist/conf/type/__git/gencode-remote +++ b/cdist/conf/type/__git/gencode-remote @@ -20,6 +20,9 @@ # state_is="$(cat "$__object/explorer/state")" +owner_is="$(cat "$__object/explorer/owner")" +group_is="$(cat "$__object/explorer/group")" + state_should=present [ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" @@ -30,11 +33,31 @@ source="$(cat "$__object/parameter/source")" destination="/$__object_id" -[ "$state_should" = "$state_is" ] && exit 0 +owner="" +[ -f "$__object/parameter/owner" ] && owner="$(cat "$__object/parameter/owner")" +group="" +[ -f "$__object/parameter/group" ] && group="$(cat "$__object/parameter/group")" +mode="" +[ -f "$__object/parameter/mode" ] && mode="$(cat "$__object/parameter/mode")" + +[ "$state_should" = "$state_is" -a \ + "$owner" = "$owner_is" -a \ + "$group" = "$group_is" -a \ + -n "$mode" ] && exit 0 case $state_should in present) - echo git clone --quiet --branch "$branch" "$source" "$destination" + + 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 + echo chown -R ${owner}:${group} ${destination} + fi + if [ -n ${mode} ]; then + echo chmod -R ${mode} ${destination} + fi ;; # Handled in manifest absent) diff --git a/cdist/conf/type/__git/manifest b/cdist/conf/type/__git/manifest index 3b52ad2d..8d6a29e4 100644 --- a/cdist/conf/type/__git/manifest +++ b/cdist/conf/type/__git/manifest @@ -26,9 +26,6 @@ __package git --state present state_should=present [ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -[ -f "$__object/parameter/owner" ] && dirparams="$dirparams --owner $(cat "$__object/parameter/owner")" -[ -f "$__object/parameter/group" ] && dirparams="$dirparams --group $(cat "$__object/parameter/group")" - # Let __directory handle removal of git repos case "$state_should" in diff --git a/cdist/conf/type/__git/parameter/optional b/cdist/conf/type/__git/parameter/optional index d9684aaa..3c409162 100644 --- a/cdist/conf/type/__git/parameter/optional +++ b/cdist/conf/type/__git/parameter/optional @@ -2,3 +2,4 @@ state branch group owner +mode From 1b25ef33b9bcd4cb1b5ef34dbeceae492711fce4 Mon Sep 17 00:00:00 2001 From: Eivind Uggedal Date: Mon, 28 Jan 2013 08:30:54 -0500 Subject: [PATCH 012/548] Slackware os and os_version explorer support. --- cdist/conf/explorer/os | 5 +++++ cdist/conf/explorer/os_version | 3 +++ 2 files changed, 8 insertions(+) diff --git a/cdist/conf/explorer/os b/cdist/conf/explorer/os index e67d87ab..053177eb 100755 --- a/cdist/conf/explorer/os +++ b/cdist/conf/explorer/os @@ -88,6 +88,11 @@ if [ -f /etc/SuSE-release ]; then 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 diff --git a/cdist/conf/explorer/os_version b/cdist/conf/explorer/os_version index 8e6d37d3..50889429 100755 --- a/cdist/conf/explorer/os_version +++ b/cdist/conf/explorer/os_version @@ -54,6 +54,9 @@ case "$($__explorer/os)" in redhat|centos) cat /etc/redhat-release ;; + slackware) + cat /etc/slackware-version + ;; suse) cat /etc/SuSE-release ;; From 50208bc537773bcb44e54ac79a8a3dc64a1b6e4b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 28 Jan 2013 15:11:32 +0100 Subject: [PATCH 013/548] ++changes recorded Signed-off-by: Nico Schottelius --- docs/changelog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 12baa1a2..6c0231b3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,8 +5,10 @@ Changelog * Exception: No braces means author == Nico Schottelius next: - * Type __jail: State absent should implies stopped (Jake Guffey) * Core: Use dynamic dependency resolver to allow indirect self dependencies + * Type __git: Support mode and fix owner/group settings (contradict) + * Type __jail: State absent should implies stopped (Jake Guffey) + * Explorer os: Added Slackware support (Eivind Uggedal) 2.1.0: 2012-12-09 * Core: Ensure global explorers are executable From 919707d6f9baaa71df2caef817c77e2a7c90ec0f Mon Sep 17 00:00:00 2001 From: Jason Staten Date: Mon, 28 Jan 2013 10:06:04 -0700 Subject: [PATCH 014/548] Initialize variables to empty string Set mode, group, etc. to an empty string to ensure that no external environment variables can leak in. --- cdist/conf/type/__directory/gencode-remote | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index 154a46b5..f46a5967 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -27,10 +27,15 @@ mode_is="$(cat "$__object/explorer/mode")" state_should="present" [ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +mode="" [ -f "$__object/parameter/mode" ] && mode="$(cat "$__object/parameter/mode")" +owner="" [ -f "$__object/parameter/owner" ] && owner="$(cat "$__object/parameter/owner")" +group="" [ -f "$__object/parameter/group" ] && group="$(cat "$__object/parameter/group")" +mkdiropt="" [ -f "$__object/parameter/parents" ] && mkdiropt="-p" +recursive="" [ -f "$__object/parameter/recursive" ] && recursive="-R" case "$state_should" in From b772e09d532385ec66bb2e2061ab28b92d848a16 Mon Sep 17 00:00:00 2001 From: contradict Date: Wed, 30 Jan 2013 00:48:08 -0800 Subject: [PATCH 015/548] Exit with no error if directory absent Explorers need to handle the case of no directory. --- cdist/conf/type/__git/explorer/group | 2 +- cdist/conf/type/__git/explorer/owner | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__git/explorer/group b/cdist/conf/type/__git/explorer/group index 4be8c1a6..1308c710 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 +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 1f3c80e6..8c36b035 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 +stat --print "%U" ${destination} 2>/dev/null || exit 0 From 6fbc03076b293aebb6edc7002ea5fec79426d1ac Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 5 Feb 2013 22:39:07 +0100 Subject: [PATCH 016/548] debugging not easily possible with loss of parameter_path Signed-off-by: Nico Schottelius --- ...5.debugging-wrong-singleton-type-parameter | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 docs/dev/logs/2013-02-05.debugging-wrong-singleton-type-parameter diff --git a/docs/dev/logs/2013-02-05.debugging-wrong-singleton-type-parameter b/docs/dev/logs/2013-02-05.debugging-wrong-singleton-type-parameter new file mode 100644 index 00000000..5169b678 --- /dev/null +++ b/docs/dev/logs/2013-02-05.debugging-wrong-singleton-type-parameter @@ -0,0 +1,34 @@ +Traceback (most recent call last): + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 230, in + commandline() + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 104, in commandline + args.func(args) + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 107, in config + configinstall(args, mode=cdist.config.Config) + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 143, in configinstall + configinstall_onehost(host, args, mode, parallel=False) + File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 180, in configinstall_onehost + c.deploy_and_cleanup() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/config_install.py", line 74, in deploy_and_cleanup + self.deploy_to() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/config_install.py", line 68, in deploy_to + self.stage_prepare() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/config_install.py", line 91, in stage_prepare + self.context.local.type_path): + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/core/cdist_object.py", line 80, in list_objects + yield cls(cdist.core.CdistType(type_base_path, type_name), object_base_path, object_id=object_id) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/core/cdist_object.py", line 65, in __init__ + self.validate_object_id() + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/core/cdist_object.py", line 130, in validate_object_id + (self.cdist_type.name, self.parameters)) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/util/fsproperty.py", line 210, in __get__ + return self._get_attribute(instance, owner) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/util/fsproperty.py", line 202, in _get_attribute + path = self._get_path(instance) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/util/fsproperty.py", line 190, in _get_path + path = path(instance) + File "/home/users/nico/oeffentlich/rechner/projekte/cdist/cdist/cdist/core/cdist_object.py", line 192, in + parameters = fsproperty.DirectoryDictProperty(lambda obj: os.path.join(obj.base_path, obj.parameter_path)) +AttributeError: 'CdistObject' object has no attribute 'parameter_path' +[22:37] brief:~% + From cb829ec8d080e8224d55ec277af25aca62a003e3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 5 Feb 2013 22:50:22 +0100 Subject: [PATCH 017/548] introduce MissingObjectIdError Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 7beea130..73537f80 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-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -42,6 +42,14 @@ 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 + + def __str__(self): + return '%s' % (self.message) + class CdistObject(object): """Represents a cdist object. @@ -125,8 +133,12 @@ class CdistObject(object): # If no object_id and type is not singleton => error out if not self.object_id and not self.cdist_type.is_singleton: - raise IllegalObjectIdError(self.object_id, - "Missing object_id and type is not a singleton.") + raise MissingObjectIdError(self.cdist_type.name) + + # 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)) def object_from_name(self, object_name): """Convenience method for creating an object instance from an object name. From 06fb7491faf69135f5e765c3ab09caf4daba01b7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 18 Jan 2013 15:02:43 +0100 Subject: [PATCH 018/548] prevent requirements from leaking into autorequired objects and creating circular references Signed-off-by: Steven Armstrong Conflicts: cdist/test/autorequire/__init__.py --- cdist/resolver.py | 21 ++++++++++++------- cdist/test/autorequire/__init__.py | 6 ++++++ .../fixtures/conf/manifest/recursive_type | 2 ++ .../fixtures/conf/type/__git/manifest | 1 + 4 files changed, 23 insertions(+), 7 deletions(-) create mode 100755 cdist/test/autorequire/fixtures/conf/manifest/recursive_type create mode 100644 cdist/test/autorequire/fixtures/conf/type/__git/manifest diff --git a/cdist/resolver.py b/cdist/resolver.py index c1b2c292..ddcf382e 100644 --- a/cdist/resolver.py +++ b/cdist/resolver.py @@ -23,6 +23,7 @@ import logging import os import itertools import fnmatch +import pprint import cdist @@ -77,14 +78,15 @@ class DependencyResolver(object): lists of all dependencies including the key object itself. """ if self._dependencies is None: - log.info("Resolving dependencies...") - self._dependencies = d = {} + self.log.info("Resolving dependencies...") + self._dependencies = {} self._preprocess_requirements() for name,cdist_object in self.objects.items(): resolved = [] unresolved = [] self._resolve_object_dependencies(cdist_object, resolved, unresolved) - d[name] = resolved + self._dependencies[name] = resolved + self.log.debug(self._dependencies) return self._dependencies def find_requirements_by_name(self, requirements): @@ -120,9 +122,12 @@ class DependencyResolver(object): # that the parent has so that user defined requirements are # fullfilled and processed in the expected order. for auto_requirement in self.find_requirements_by_name(cdist_object.autorequire): - for requirement in cdist_object.requirements: - if requirement not in auto_requirement.requirements: - auto_requirement.requirements.append(requirement) + for requirement in self.find_requirements_by_name(cdist_object.requirements): + requirement_object_all_requirements = list(requirement.requirements) + list(requirement.autorequire) + if (requirement.name not in auto_requirement.requirements + and auto_requirement.name not in requirement_object_all_requirements): + self.log.debug('Adding %s to %s.requirements', requirement.name, auto_requirement) + auto_requirement.requirements.append(requirement.name) # On the other hand the parent shall depend on all the children # it created so that the user can setup dependencies on it as a # whole without having to know anything about the parents @@ -149,7 +154,9 @@ class DependencyResolver(object): self.log.debug("Object %s requires %s", cdist_object, required_object) if required_object not in resolved: if required_object in unresolved: - raise CircularReferenceError(cdist_object, required_object) + error = CircularReferenceError(cdist_object, required_object) + self.log.error('%s: %s', error, pprint.pformat(self._dependencies)) + raise error self._resolve_object_dependencies(required_object, resolved, unresolved) resolved.append(cdist_object) unresolved.remove(cdist_object) diff --git a/cdist/test/autorequire/__init__.py b/cdist/test/autorequire/__init__.py index 330680df..714a7d4b 100644 --- a/cdist/test/autorequire/__init__.py +++ b/cdist/test/autorequire/__init__.py @@ -83,3 +83,9 @@ class AutorequireTestCase(test.CdistTestCase): self.config.stage_prepare() # raises CircularDependecyError self.config.stage_run() + + def test_recursive_type(self): + self.context.initial_manifest = os.path.join(self.config.local.manifest_path, 'recursive_type') + self.config.stage_prepare() + # raises CircularDependecyError + self.config.stage_run() diff --git a/cdist/test/autorequire/fixtures/conf/manifest/recursive_type b/cdist/test/autorequire/fixtures/conf/manifest/recursive_type new file mode 100755 index 00000000..c32b7710 --- /dev/null +++ b/cdist/test/autorequire/fixtures/conf/manifest/recursive_type @@ -0,0 +1,2 @@ +__git foo +require="__git/foo" __git bar diff --git a/cdist/test/autorequire/fixtures/conf/type/__git/manifest b/cdist/test/autorequire/fixtures/conf/type/__git/manifest new file mode 100644 index 00000000..616ecca9 --- /dev/null +++ b/cdist/test/autorequire/fixtures/conf/type/__git/manifest @@ -0,0 +1 @@ +__package git From d1e06504a2952bfc83af0f53139d4a40b3d77f78 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 14 Feb 2013 15:28:40 +0100 Subject: [PATCH 019/548] merge back the dependency resolver into pseudo master Signed-off-by: Nico Schottelius --- cdist/config_install.py | 52 +++++++---------------------------------- 1 file changed, 8 insertions(+), 44 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index f1529cc1..e74145b0 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -134,49 +134,13 @@ class ConfigInstall(object): """The final (and real) step of deployment""" self.log.info("Generating and executing code") - # FIXME: think about parallel execution (same for stage_prepare) - self.all_resolved = False - while not self.all_resolved: - self.stage_run_iterate() + objects = core.CdistObject.list_objects( + self.local.object_path, + self.local.type_path) - def stage_run_iterate(self): - """ - Run one iteration of the run + dependency_resolver = resolver.DependencyResolver(objects) + self.log.debug(pprint.pformat(dependency_resolver.dependencies)) - To be repeated until all objects are done - """ - objects = list(core.CdistObject.list_objects(self.context.local.object_path, self.context.local.type_path)) - object_state_list=' '.join('%s:%s:%s:%s' % (o, o.state, o.all_requirements, o.satisfied_requirements) for o in objects) - - self.log.debug("Object state (name:state:requirements:satisfied): %s" % object_state_list) - - objects_changed = False - self.all_resolved = True - for cdist_object in objects: - if not cdist_object.state == cdist_object.STATE_DONE: - self.all_resolved = False - self.log.debug("Object %s not done" % cdist_object.name) - if cdist_object.satisfied_requirements: - self.log.debug("Running object %s with satisfied requirements" % cdist_object.name) - self.object_run(cdist_object, self.dry_run) - objects_changed = True - - self.log.debug("All resolved: %s Objects changed: %s" % (self.all_resolved, objects_changed)) - - # Not all are resolved, but nothing has been changed => bad dependencies! - if not objects_changed and not self.all_resolved: - # Create list of unfinished objects + their requirements for print - - evil_objects = [] - good_objects = [] - for cdist_object in objects: - if not cdist_object.state == cdist_object.STATE_DONE: - evil_objects.append("%s: required: %s, autorequired: %s" % - (cdist_object.name, cdist_object.requirements, cdist_object.autorequire)) - else: - evil_objects.append("%s (%s): required: %s, autorequired: %s" % - (cdist_object.state, cdist_object.name, - cdist_object.requirements, cdist_object.autorequire)) - - errormessage = "Cannot solve requirements for the following objects: %s - solved: %s" % (",".join(evil_objects), ",".join(good_objects)) - raise cdist.Error(errormessage) + for cdist_object in dependency_resolver: + self.log.debug("Run object: %s", cdist_object) + self.object_run(cdist_object) From 177c350747b677a373c75e8a4058b0f070188a20 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 14 Feb 2013 15:45:58 +0100 Subject: [PATCH 020/548] use self.context, not self.local Signed-off-by: Nico Schottelius --- cdist/config_install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index e74145b0..7c7a876d 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -135,8 +135,8 @@ class ConfigInstall(object): self.log.info("Generating and executing code") objects = core.CdistObject.list_objects( - self.local.object_path, - self.local.type_path) + self.context.local.object_path, + self.context.local.type_path) dependency_resolver = resolver.DependencyResolver(objects) self.log.debug(pprint.pformat(dependency_resolver.dependencies)) From 005c94556e80e1eecc4db15c46d9bee4c2fa71a2 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Tue, 19 Feb 2013 15:23:52 -0500 Subject: [PATCH 021/548] Fix to support FreeBSD's stat(1) Added check for OS type Added FreeBSD syntax in case of $os=freebsd --- cdist/conf/type/__directory/explorer/group | 14 +++++++++++++- cdist/conf/type/__directory/explorer/mode | 14 +++++++++++++- cdist/conf/type/__directory/explorer/owner | 14 +++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group index b14794e3..4da5b45d 100644 --- a/cdist/conf/type/__directory/explorer/group +++ b/cdist/conf/type/__directory/explorer/group @@ -22,7 +22,19 @@ # destination="/$__object_id" +# Since $__global isn't available, use uname directly, uname and tr are both part of POSIX +os="$(uname -s | tr '[:upper:]' '[:lower:]')" + +case "$os" in + "freebsd") + cmd="stat -f %Sg" + ;; + *) + cmd="stat -c %G" + ;; +esac if [ -e "$destination" ]; then - stat -c "%G" "$destination" + $cmd "$destination" fi + diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode index 3ffa497e..1d40c795 100644 --- a/cdist/conf/type/__directory/explorer/mode +++ b/cdist/conf/type/__directory/explorer/mode @@ -22,7 +22,19 @@ # destination="/$__object_id" +# Since $__global isn't available, use uname directly, uname and tr are both part of POSIX +os="$(uname -s | tr '[:upper:]' '[:lower:]')" + +case "$os" in + "freebsd") + cmd="stat -f %Op" + ;; + *) + cmd="stat -c %a" + ;; +esac if [ -e "$destination" ]; then - stat -c "%a" "$destination" + $cmd "$destination" fi + diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner index a691ac1b..452dc672 100644 --- a/cdist/conf/type/__directory/explorer/owner +++ b/cdist/conf/type/__directory/explorer/owner @@ -22,7 +22,19 @@ # destination="/$__object_id" +# Since $__global isn't available, use uname directly, uname and tr are both part of POSIX +os="$(uname -s | tr '[:upper:]' '[:lower:]')" + +case "$os" in + "freebsd") + cmd="stat -f %Su" + ;; + *) + cmd="stat -c %U" + ;; +esac if [ -e "$destination" ]; then - stat -c "%U" "$destination" + $cmd "$destination" fi + From 52fdf15a4b82dd238579e41aab862ad15522f484 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Tue, 19 Feb 2013 15:28:03 -0500 Subject: [PATCH 022/548] Add umask Some directories were being created 700 and causing problems, added umask 022 to fix this --- cdist/conf/type/__jail/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote index 7491754c..5223bc46 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail/gencode-remote @@ -160,10 +160,10 @@ EOF createJail() { # Create the jail directory cat < Date: Tue, 19 Feb 2013 16:24:22 -0500 Subject: [PATCH 023/548] Added support for multiple IP addresses FreeBSD jails support jail_${name}_ip="iface1|addr1, iface2|addr2" format for specifying multiple IP addresses --- cdist/conf/type/__jail/gencode-remote | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote index 5223bc46..b044e4b0 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail/gencode-remote @@ -92,6 +92,20 @@ fi present="$(cat "$__object/explorer/present")" status="$(cat "$__object/explorer/status")" +# Handle ip="iface|addr, iface|addr" format +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" + IFS=", " + for cur_ip in ${ip}; do + # Just get the last IP address for SSH to listen on + mgmt_ip=$(echo "${ip}" | sed -E -e 's/^.*\|(.*)\/[0-9]+$/\1/') + done + IFS="$SAVE_IFS" +else + mgmt_ip=$(echo "${ip}" | cut '-d ' -f1) +fi stopJail() { # Check $status before issuing command @@ -250,7 +264,7 @@ if [ -n "$interface" ]; then jail_${name}_interface="${interface}" END EOF -else +elif [ "$(expr "${ip}" : ".*|.*")" -eq "0" ]; then cat <>/etc/rc.conf <>"${jaildir}/rw/${name}/etc/rc.conf" EOF # Configure SSHd's listening address cat < Date: Tue, 19 Feb 2013 16:31:06 -0500 Subject: [PATCH 024/548] Use $__explorer to get os type --- cdist/conf/type/__directory/explorer/group | 3 +-- cdist/conf/type/__directory/explorer/mode | 3 +-- cdist/conf/type/__directory/explorer/owner | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group index 4da5b45d..e5be37da 100644 --- a/cdist/conf/type/__directory/explorer/group +++ b/cdist/conf/type/__directory/explorer/group @@ -22,8 +22,7 @@ # destination="/$__object_id" -# Since $__global isn't available, use uname directly, uname and tr are both part of POSIX -os="$(uname -s | tr '[:upper:]' '[:lower:]')" +os=$("$__explorer/os") case "$os" in "freebsd") diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode index 1d40c795..f75b282b 100644 --- a/cdist/conf/type/__directory/explorer/mode +++ b/cdist/conf/type/__directory/explorer/mode @@ -22,8 +22,7 @@ # destination="/$__object_id" -# Since $__global isn't available, use uname directly, uname and tr are both part of POSIX -os="$(uname -s | tr '[:upper:]' '[:lower:]')" +os=$("$__explorer/os") case "$os" in "freebsd") diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner index 452dc672..cebd199b 100644 --- a/cdist/conf/type/__directory/explorer/owner +++ b/cdist/conf/type/__directory/explorer/owner @@ -22,8 +22,7 @@ # destination="/$__object_id" -# Since $__global isn't available, use uname directly, uname and tr are both part of POSIX -os="$(uname -s | tr '[:upper:]' '[:lower:]')" +os=$("$__explorer/os") case "$os" in "freebsd") From 6d10f2e4f2b4827cf9536b58443c35ccb297851b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 21 Feb 2013 22:26:29 +0100 Subject: [PATCH 025/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 6c0231b3..e5badfac 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Type __git: Support mode and fix owner/group settings (contradict) * Type __jail: State absent should implies stopped (Jake Guffey) * Explorer os: Added Slackware support (Eivind Uggedal) + * Type __directory: Make stat call compatible with FreeBSD (Jake Guffey) 2.1.0: 2012-12-09 * Core: Ensure global explorers are executable From 44a0f5d7bbacdf7a6448a1909b88a5854e240b72 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 22 Feb 2013 11:13:44 +0100 Subject: [PATCH 026/548] restore resolver test Signed-off-by: Nico Schottelius --- cdist/test/resolver/__init__.py | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 cdist/test/resolver/__init__.py diff --git a/cdist/test/resolver/__init__.py b/cdist/test/resolver/__init__.py new file mode 100644 index 00000000..baae26de --- /dev/null +++ b/cdist/test/resolver/__init__.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +# +# 2010-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 . +# +# + +import os +import shutil + +import cdist +from cdist import test +from cdist import core +from cdist import resolver + +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') + + +class ResolverTestCase(test.CdistTestCase): + + def setUp(self): + self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) + self.object_index = dict((o.name, o) for o in self.objects) + self.dependency_resolver = resolver.DependencyResolver(self.objects) + + def tearDown(self): + for o in self.objects: + o.requirements = [] + + def test_find_requirements_by_name_string(self): + requirements = ['__first/man', '__second/on-the', '__third/moon'] + required_objects = [self.object_index[name] for name in requirements] + self.assertEqual(sorted(list(self.dependency_resolver.find_requirements_by_name(requirements))), + sorted(required_objects)) + + def test_find_requirements_by_name_pattern(self): + requirements = ['__first/*', '__second/*-the', '__third/moon'] + requirements_expanded = [ + '__first/child', '__first/dog', '__first/man', '__first/woman', + '__second/on-the', '__second/under-the', + '__third/moon' + ] + required_objects = [self.object_index[name] for name in requirements_expanded] + self.assertEqual(sorted(list(self.dependency_resolver.find_requirements_by_name(requirements))), + sorted(required_objects)) + + def test_dependency_resolution(self): + first_man = self.object_index['__first/man'] + second_on_the = self.object_index['__second/on-the'] + third_moon = self.object_index['__third/moon'] + first_man.requirements = [second_on_the.name] + second_on_the.requirements = [third_moon.name] + self.assertEqual( + self.dependency_resolver.dependencies['__first/man'], + [third_moon, second_on_the, first_man] + ) + + def test_circular_reference(self): + first_man = self.object_index['__first/man'] + first_woman = self.object_index['__first/woman'] + first_man.requirements = [first_woman.name] + first_woman.requirements = [first_man.name] + with self.assertRaises(resolver.CircularReferenceError): + self.dependency_resolver.dependencies + + def test_requirement_not_found(self): + first_man = self.object_index['__first/man'] + first_man.requirements = ['__does/not/exist'] + with self.assertRaises(cdist.Error): + self.dependency_resolver.dependencies From 459ea4cfd9c954adfc79476e64b0c0edaf091fc7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 25 Mar 2013 14:01:32 +0100 Subject: [PATCH 027/548] +some new speeches Signed-off-by: Nico Schottelius --- .../2013-02-05.weird-notsingleton-type-error | 15 +++++++++++++++ docs/gfx/cdist-and-sexy-white.png | Bin 0 -> 5589 bytes docs/speeches/2012-12-11_lisa.odp | Bin 0 -> 24180 bytes docs/speeches/2013-01-23_panter.notes | 10 ++++++++++ docs/speeches/2013-01-23_panter.odp | Bin 0 -> 28733 bytes docs/speeches/2013-03-25_ad_novum.odp | Bin 0 -> 26866 bytes 6 files changed, 25 insertions(+) create mode 100644 docs/dev/logs/2013-02-05.weird-notsingleton-type-error create mode 100644 docs/gfx/cdist-and-sexy-white.png create mode 100644 docs/speeches/2012-12-11_lisa.odp create mode 100644 docs/speeches/2013-01-23_panter.notes create mode 100644 docs/speeches/2013-01-23_panter.odp create mode 100644 docs/speeches/2013-03-25_ad_novum.odp diff --git a/docs/dev/logs/2013-02-05.weird-notsingleton-type-error b/docs/dev/logs/2013-02-05.weird-notsingleton-type-error new file mode 100644 index 00000000..23693777 --- /dev/null +++ b/docs/dev/logs/2013-02-05.weird-notsingleton-type-error @@ -0,0 +1,15 @@ + +Hard to find the source bug/problem: + +DEBUG: solr.petspremium.de: (emulator) __file//etc/solr/solr.xml: Finished __file/etc/solr/solr.xml/.cdist {'mode': '0644', 'source': '/home/users/nico/.tmp/tmpn27s24/out/conf/type/__petspremium_solr/files/solr/solr.xml'} ++ for file in '$(find . -type f | sed '\''s,^./,,'\'')' ++ dfile=/etc/solr/web.xml ++ reqdir=/etc/solr ++ require=__directory/etc/solr ++ __file /etc/solr/web.xml --source /home/users/nico/.tmp/tmpn27s24/out/conf/type/__petspremium_solr/files/solr/web.xml --mode 0644 +DEBUG: solr.petspremium.de: (emulator): /home/users/nico/.tmp/tmpn27s24/out/bin/__file: Namespace(mode='0644', object_id=['/etc/solr/web.xml'], source='/home/users/nico/.tmp/tmpn27s24/out/conf/type/__petspremium_solr/files/solr/web.xml') +DEBUG: solr.petspremium.de: (emulator) __file//etc/solr/web.xml: Recording requirement: __directory/etc/solr +DEBUG: solr.petspremium.de: (emulator) __file//etc/solr/web.xml: Finished __file/etc/solr/web.xml/.cdist {'source': '/home/users/nico/.tmp/tmpn27s24/out/conf/type/__petspremium_solr/files/solr/web.xml', 'mode': '0644'} +ERROR: solr.petspremium.de: Type __directory requires object id (is not a singleton type) +INFO: Total processing time for 1 host(s): 9.756716251373291 +ERROR: Failed to deploy to the following hosts: solr.petspremium.de diff --git a/docs/gfx/cdist-and-sexy-white.png b/docs/gfx/cdist-and-sexy-white.png new file mode 100644 index 0000000000000000000000000000000000000000..1366b9c2f31e4184c2a67c03b8fc958c5d9de303 GIT binary patch literal 5589 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 QV0;9$G#)=Fyl?mVf7E|34*&oF literal 0 HcmV?d00001 diff --git a/docs/speeches/2012-12-11_lisa.odp b/docs/speeches/2012-12-11_lisa.odp new file mode 100644 index 0000000000000000000000000000000000000000..342edab47eaaf6b3b11b5748b007b6eb5a05675b GIT binary patch literal 24180 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ΜijWIN zSawt2aNe33X&kUyJZ!I;mVf>%?g!L( z8blQ~e7Q!9hUc~u--q`hE5olnFHnX=x$$IX+LAHc1yj>yCrMZ+3&T>It17X{NsD6O zDI8O>>t&v({{D0<#58Us(y#F4TJ>dzFN}0n7d{%x=x4R+t+AP{x94Bmqj0DrEHW<# z7ooBcyA2smuZX+2QCK{_o_cRaLp9rzE-JD!dmh7>B^tdvy+}D*8jiOuF`O+6>8P04 z+$hRk!jBA5td*+?ojhRtw0>=hJ$ikSA)9!HaH@A&wlK1|-1sUj zXfR+EAtdAjy8zt$coF@=>B%#}Q}?XIZ+BvpE##vy!?-$^b)7Tem3dnx*-j7zQ0L(A zj)J?xxZQcDkOK$80Yc=F)09*#jOL>f51!W3FbZMmwVos=l#e^pi@5d z>!w$~88^cDC8o<-PE*iVHM*pycS6|xb+A}h&La&piTc-8dq)N{91-vPy{c8$Ier!l zkTwc2SLpf(0gMAnf|4!glP3{W6bai2jiE>V^7VJuNkVTlsJxu`SBL%@Ri}to1(T&& z;# zE$bU*;rZR<)BqB{eGOju)xuKzMil_+_9oP zn`xv860l`cU(m+cQT43V+K#BrLhK%^?!ppxX z)kT=|7MTt~lmcjz-`rZA!=Tu(h4|C0i9}l#%=`benR)e1?KOxmD@+^$t5=< zt;m7y@o?Zx9uxuy#e1dJrKgo3du)AN^Kul1ZjVNz&g^BrcbvjvWk9R6`MEP7Q+NX@ zPDv)u0Z(IZt#Li=a+TVV zP5Ct5A%5Q6Us3Q~ah+lqGrG9BL8SPa-wnGW@&mCWTzn@BqV?E&gQd-2l>TwFUjD#? z2-%GfD8;@}Gz=f{x6$6qQQ}%#E7xd~fZ78sPxJ7O5Rxj_=xDl31*xjCxZw-yd=f?P?wYTP~sUtHBoiPRrh29u1TVDQ-XTq<}y-d`vm+_jky=Q)zL&h$=BO7;KQVh5apYq+CpRlo$1x)%$`S<>QkcRwrLrt*cZ%^dE zZwHKL9UG1D$eN^pMY|z3_`@(8uXaatfz$i)$l54&UZZO04IyH(1;$++rR(b?joyRy zo(F%jf4JUhD@^U3g&@B7$tpfzlTEOKjrt-$X0kq)s72Ij!VT3uyf6$nNd$7VMGmT& z{~PV-Nb+w3e|?5?FGeO|eVb!CLrOB%GET%&f?(t(a_{WXuzWtfTPwy9!_r|k5hWx9 zVLm_a@EJ@k7!AOXEn9FC57s_^^~<9tH-dMO|FDoxZ<+=< zK$xfL2@fR}=mnpMrAC-A_{-&V)?f~(*jdJ>!5f2^6-V--f4kIicvQ!49N57VG=?!- zQMetlc4jI18uJh%cAgYm502%vzDWJZn-A97{$C8r6=8Cv3<>-q1lcOIvHL?~nJF+r>;AQfduMQzi-A#9T-7uJ8^b-U1)~b}rKzEr&0v2kfDrz#NxKSlB0pdmkTIT|6d|8|ym>4& z4ml`jez03TL_)_bHfNQqydC4;k|+Q|GVc0Xm8#5%qV`8rNJve+ zfXTx}QBRx=V)XR{b}FjXSWRDByz^6OqR+3HT}Qc^ZJ)aVGLlLP@|=jYN=}fxS3u4E@1X|}bw zu7Z8Pr~?uv=P59SVnj5`O7?g-dvXfu{qbq>M#ItqTivmE&82zWTQ*<9Rk^t3t*Zj@ z{Da_Yx3Bnt4uM%~=}36=ZmBq$eM`B;KIw8h6+u0VhxHQ1l7fI`;Uh~4?2UFf#uZ>d zJE8KsFqotZzLyab$O5aC!hh*3*fp)shqp>BA<7GQD~>5SG+pO|f`U{_AGvx73QpGY8lW;;)2+*5#l8A zvl0Ov2KrHf^i(B4Zr~c7aD}a6`r&Xq!3hJ+dmk#|rT-qSNSrE2lxoF7fH^7zmjz}? zRuw#nNb=&4L#e`)Jn_?fr30+#7PGy{`LNi}P=1M${bl9#NUu+O$RK8f&sWcc#;ISU ze1Run&!Y$)d$`Wv*YlbH>nq3r*pT3e;Ol4$B1~_Q`f%t@v^j zEy{QU^T&()Nv0qFR8fTg%AbKW;Un-HKMBVR@||ZAvO|7mAn7|IgHn5{e^QgptQW83 z=+7X6%oraX>7PbIoEmNEKPl!hO14W(z~Da#{(@AK7|mYr{=*OzjrBW6_#M7C@TH`E z5`$VikN;~>wOiFSuRqEc#z=;9+R^z&C<>B1J3qiZ;|N#sv%N#=41_3gd;NP)>z(sP4QLqN%fiD@8u!j8(opn}PUr{LSoD3Qu3o7bAotyPv;|I3mR>k+< z=KbRI+h1{H4(LDKFa-_{s59}%DmKA`^rynRKNSwWy^N1f=6jy`DP?{(*8f+@S->^5 zzki$%1~R%v36qwAQWK;H(ji?^V}NucAt=a2QV>KMq!mVu?hsH)q!~!Jq=W*-{crbP zUU=`--~ab}7UwLU&z^J6`10EOe4h^+qZw&0GkqE1O_BWeV-e6rC-ERU%;BJNAR`#v zq;6sd4$*GiYJ2vEhj4s7g1rz=8#AK6cgeuxj_%TL7xkJRP{sa}i6AZR0$76y6^9&C zd}ERFxNO~cWdyJ|#eW=T_?=%oQK#zcT+-Uw>V5JX3H{qFnYnCvz)@qUGJv41Fee8- zjx<(#201z1EK`aGRX9$Re%Wb^HMPQE23}s?T&37Bn`<9KLPAs$xZ3x761c75@O23! zApqbyRYh#z*N8thHbzNFiQ#ySeh0P(s{_SFMe`ZZfRBq^(b3VY_rJQ&w*~Ju9ccRd z`)g}!7iwk<4-c=mV3<%L=b`M-(2zyY31_WIV4#$%l1Y4GBEc?(&gd_xd9mKYx!0E0 z<}Zzbddtg*YZ>~*1_T!_JcvnE=PI8nHEZmE+1uMA5FC)h?di|&vgI+9jYZfNIC?>F zd2NlGlM{nHwXk4gCiarlRIy>%80L1no@%!7?rw|gTnjEfVO#KXQGbQ8ph;@7nr}?%vm(nMO2h9UlmJ z&w{2pE#1CbERU(wq}t)=ojiF(@qC&eEtgPvF$sfZ@Qo#OrCntj9mGhMepR@9W&VqO zC5FzWL7f@P(D`af!}0Z=YaIb__~p;*5y1CUcS21`!?GKUg08=+1+E^^>TX(U3GJH^LE4d1bAQlyEVdD4tB}< zlRQj!ydB1l2WIc(Y~|+pACiCepmH$HAWL!N#w<(Xk#$o?d>KHvK=__0(dQ>L^>*3_&JavmBc%k0eK$ zClQovZHJcSBWV)+Lp8P>+RvAL0yIwm;>&TrCs|NQbEKdyJ##u4av8vjf*R8lOVdSl z!6QzOH;Z>k&DkE`rjb-m%~8b%O}=q|xbpCD?O<-@<>BU%g>+6=NA*I#+^4BWauB7D z;}3@(h>+zll--LP7fS|H)DJ;$q@!&sq~yWCVMXC5{@o3WoLg2JX~OUdZ=l6eK@6{R zDSz_y-4x2G5*8p-gGtvU;fbWm$TB7 z2eQLpo%#OgEjf5vdQdZj$#J3&g=ZT;;ASml-RY+h-R1EqN1pa$u6uS(C?!8s!FUR50npG0><6+%vJLr z5>BXy3@n>MyqkLJ6~R*Y^l7;@Fye$Q!7#{uVU?S=mT{CXq`Hu(zv_}hN4UbY>9nlw zqo-VHEefJOBn0NRYG}L?{713)0E(6{ipHvozDP9Wb7;Co_+@qh{I!!4lbNlri_)>W*uLSw9D~SCvfuOqZ#RH3>&4+npqrs(Qz{Di# zzD378_3=AsRm1zruU^N#&%5Dd#y!M-tyAKej0k8Flu32WR zG{E&~1R0RlG`~GKr76XyTAb;t<=a2dz=l2-Q#>c)e zSG`mfmP&)7=#%z%vm^z1eNg2P9B#KnNS1f-$X|Sm_bKHnDgOidb|54t=7JuLqC$~X zwGo4OVlmtHjSwMs66UHW#%sj!g68ss?0o8vHt8vH)?e98WR>N%v%Uee&kLgnvwZzD ziDnhdJ083csz^!JS>u6Sujwh;$1CqE)Soh4{?1mnZVRduBEQflY7~DNRF0R{p9G@z z`To^poU=lKP1)}oOA!9=x5-;V*lxT*ObJaX3LZu^6&y)CCb-z^rP^k!HOjUiUGk+u z)saeYII=ZRz&eJ}kG$m)r{;K#&hzLTlf39Wy%$KIm7S)m>N=KKL zJw=pcS3NX5O-#p=8Ee!-9CTkhtiLDh9DlQ<+z}#t4ua;vtH?F-UP~)^3+Lk?i zB?Uy<8(9#`BMj?e?h-sQ>HQ#C7oLLig?7@cG?Y;qhj0GcV6Qjx4d>rrDaad?(JK>@ zj3>R$_A9eIQbCAD-ocpt;=W9>2*f4#21!lG;6x^13AZe71!4U3Sj(JKm-|%i6nhqk zH+_#nZq0~kjub)Ouc84Rx4zs~-ur!rX`&2qq1EM^_=<=PuPM5!z2inL5h}%Y92ROnV?e$#^#`&OPZEGvj1UbNjGL zIJ94)dc@!n(M(~+_~=_U#%6wbem!o98mqDHVkioB%GH>`Nt?WTIi6oZCwYf$KmT4* z{M9}vkBVSaERxN&?B$0+z=<#K}RYR+T-K%z_QC(j;J(EY~ZoTb#Djn0oITxpZO=N`*ozE2$q3lwgKbhgRc~ z7)Bh=7=(sBWH%71)^a$|A;z1acz?U80M?0YF?n;5s(}6-x#0u8O%YTw9;!on{6AqzYBq$_IqH)%vw9rAf z#vg0b*_K5}YJ6bVy4Rpjm1W5oMwE;m5}}!)%sGeD$?1;KwGF~+vnMd+;tOvEA>yLpj7B*U0%vzJSPug{LLyK_W!6<*ch zvX}9ls|%pBbb~!xuZ__tl{IQfSe+QsD zZR! zHwM;v0*4@n;VHMlu{_6YhV57ReB%rr7=?%u?AnOuo{&f0NG&h~yKHb-!5KGpJD)og z2{FcubR2%uGuHQF@3|ux1BglX9B2}v{vu1Er8!bY+9{em2?*H}87n32bXNy%uIcuj z6i5}96q+*jI7*|vkrLip-9E3r;z40=a70_#|nF8Zv0;b|(aqbw_5~o4Gwt=}Gut#75^W z!jcj5s6%!g!NJ%rTehS<_)wmgdPO$;HuLEI!YqI#A?xrH`DwP6sV3jBndJ%act1~- zQ$%SQy&9F4Zdmz!m^g=*T@9ioH^d#;HL-hvB1x>7sIhVIXxQ~Bd_J^@_9MPuD)y#S+ajONc)aBeE^#LK}&W;ZB{0?Cy;<}X5WVSIt$pWNt ze5EOMJhJRPhxhw%_4yL@t8(vWQq5ISvOLnV9Sy27(2P*1DlrSjG{^^?SXv?g4KP{U zG;=rhr-XdFyKW9HnpLQ+tTquus=N(nd3Newt9vQFVgF8=)|X0aYC6%Jl|Gs-M?%+| zTIwSX5nV6KN@fM2+b->Ij`q4aBcto5cr02T-{$ch`21Q*Yu$G^}s``>T)To{18bEV3j&D#04@z-4o?R|fv z6m-1aF)XYe$9I+^@JiD#3r0CHQd_X6lW_- z^C=7CGK{%dkdgVu&t37%J~#pB_rN>^1|=jI-j@}=l--b7#N60kQz-UUk-5U zW-VV^G0?$V67ts#o`p8{eL=^N%=2L(s$B=r+K%Sy#}3OQGc-N~{JN!~v+&Y7u=_KK4u;GeUl?Dv7d&eQ5#Uhm*1DOGaR+3eS?2 zfx9e{-xs@BkF#1KOXR#YcSeC+?_)@fvaCe$K*I{ zMnX%TPU%6uKQ>4iMQ;kOC8gP!`oKkd^u}TqFI*pRpb=3UN~Ry4i65Qy@~PoqAw~@m zF25AYpqb5?1fX>k6Wpznr>|;tCq64=$91Vz7afM1>5tM8wVrri;imaQ=(qi>;hxgS zH;-I~NYP9>!l*4I*P_2Q&&XFz(-B9r$Y!Y_xt4@jRPB5~&N_7oq8+5+rQJv4jEGRR z%^TM{;N8$*D|(`~H5s(q^%!-V zwYryV{$W+YWr9F31IWtJek$_bPR&UO(l8-^RS`;2F3DtEB)qU_z~QfJatXmhIzgdI zlkaWmz?Vb#aAo%^%C5l|A6FNZiZEPc$B@1ZNO;Y$AoKvec~7^=)owK9Q&^jO zG-KSz=p>URkrKkpm*x&mr^vTGFH0*@AC@5KjtlEi(t-{_nB9S9RQ@V|xqx)!%0Q}O z&Cq9Zc6A1NJQ|J(f3BR*pItx6lmaX~!wV8*bMxTg*F3)a>g=r_CT$H4mY))0_qsN$ zS5z1mGjSB-dwEL@7mo(#*LKcWbZ{PL=FVqXXO!Yck4>y!^LglFR{tmW<}>MEnRK2@ zH)5QKuts}WYH^lzR?v@5MOe4J^WeeQ6aDDD_s`59=iOqRjLw6Q>TkYAXNhNp{&QOH zd7=l#8~az2bpNSxo`r*hWoPG+sq}C9^CQ0d`*A$a`xD@uKOX;y&cATpuf_ge6t(id zi~14o{kJ-5KhgOS_x)N23;fRG;ZJn_j{knGghhGh(fkvoa~$~JsvP`83 e9)?E07}Ia55n%qVad0RxmnWD3YQPx#=>GtDN^Y|N literal 0 HcmV?d00001 diff --git a/docs/speeches/2013-01-23_panter.notes b/docs/speeches/2013-01-23_panter.notes new file mode 100644 index 00000000..d223c7bc --- /dev/null +++ b/docs/speeches/2013-01-23_panter.notes @@ -0,0 +1,10 @@ +sexy & sexy: ein glückliches Paar + +inhalt vom vortrag + +ziele von sexy und cdist + + systemadministration hochgradig zu automatisieren + effizientes (tägliches) arbeiten + + diff --git a/docs/speeches/2013-01-23_panter.odp b/docs/speeches/2013-01-23_panter.odp new file mode 100644 index 0000000000000000000000000000000000000000..7fa0e4c7ff68368c452d4d2af6948b7a5acae121 GIT binary patch literal 28733 zcma&M19&FOzb=~0#F*H&^ToF9WMY4@?M$3ZY#S5Xp6H8hOzes6J8P}|-*??}&OOiW zr>ncG>iwb6UDa=ulI&*)bTBX&FtDLWP7zkh%2EIr7}#IoPZF4|r7h6K(*bDY;9z5E zV&r0JZwGL*Gi9_la<+74w08j7ncADU+5+ud7#*B|&VTNIW0d|@3IhZ4x6(g){`+9~ z^Q2^H;^O)T4Pa*a*TEto_D@Wdg`JC8L|B4_iP6E%TwT+XFKP3^zX+AKnDphxvlI!O z36ZR^NP@3HKa6OiaFp=KVz}uTizp0^iS)|S?=kF`NuMYn6H9$GyTP+hPtDTB1IRh| zg=ebmko#fXd+NnkaUc;C=S;s&4+fSs=kq8;1g3zGf9IdY?KqF?$XG|zm6j{Wb^`&n zC<{XR9GB&FCp8>AJ+Ew@VY+47-3xU^_yzhK9n1uDc_;wnr=abF-Q%qS#k6IKBRRw|TY*A0n8z&_)oMj{H_(==jH14{hyLZ(Kw8uSP~4 z)qRI`OLv^t-w0LQYQxIVdI>F58fO}u#OsgY=5Hg`2QM2p@%WRzMf>yJ0KwQy(3X=% zLu$>}ZajhJZld&LBN>k*^6!b_tX5TiS?!OdJ36itscB93SGDOeLYZ;1_c;R8x3WAGiT+h0 zx1Fr3s`NaXRm8cPl@@opi1n`_4Lx@i$v77`wHjfW$s?--mDDe|WFq?cVKcS0`}~g_ z*5LirDltbG?nf|RjZEbiVay6+mBvKve}Q$3`p<{$Kj`M(+P(4lwoSr?#6Q5mv+CU9 zX({q6u1G!7zDzx_o8EV1+u7XE)IR5}r4B=AWNXewLxyfZgNxlz$F91JQu?2dpcL<> zJqN%JNX){Q>PX;h236<+G?9+A$Fh;&}oQKd5lYM)qF`MneXI7en$9&cOr zFhKlTewBJYR8^^f=BLCE6#K)RoZ>TLI+6}!j4Y!jq759^WBRR=%qd6ns9x6MSE)m~Mju=%un8Us@gqRBhDAE=*H zv2DE+qM?Oo7xXnkOA8e8%FI#{P$p|?Ts__FGwAFd?~~B|5=i-SiU?uENN`hpIOm8{ zyE_cl69F`vH=Wd6;a1hW)c6Z;+%o5ux-kcvwuKbzHrgsjdcntfqMG~o8@X6dm%rnU z6R-CXgXua6*=1uZ+kCD-t*UROO1`t=uam2YjoO*QTHNT~?4L)2-bn3u9hjmlRwY9V zQf2j0=RWyTM7kd+BTb)bbqGel(rm|rlWl?I9jWCV1*cZ+P!~YjL!tpvNqT1NgAD?w z8%7a){csAC84G0OnS+~a-D{S{9Ru)a`q&&?jaE)TT^eUWzzZU7hZwd9T7ek}SVG<~#C4rW|Im9OoRcS%PrF=C@^KxL-h z^`a$SOyz}1&ek({CEOnk$Sz->Y)Dh!#X3gdT&_~{TvBFlRG^<9i7F5Hy@jj`DFJj( zWem|?@vdRl^6bF5uXCeoTzjhY zees-2i=NI^`n~AtkV>bU-uI17_{~iOe-MO%5T(`;LMg4c&9Ro? z`xvUuSmBve&pqhdD}+sD2$YJHZMSI2DiTP%y+8%8)DKNJ4aQaqryUYOU5Nx^xRL~v zWNh8KNXUXk*vT!A4ie2JtC!y;1 zQT1Q@(mjsWNZzr14d)D=cEIYrvXsoqj$|D|Lu($%BNpsJKAfLClQ^yqsSJ(LB0%_d zfN-{qyMq*u<*&RTB1tGn(~fMR!l$@8ft25Yu#`~fPh+-iGWtuiCFmd$CvMCb8m77| zB2uJi2;$EXvXq&(VL@aW;D~0km|%w9z#ylcO#)@|b%Qa7pL0I424>3Z4~D^zx5CQ7 zCm-;;;4?Q(mFd=pEhPe0Xu8hBradwnj{;@!yf(07vKL9Ko-LsvmYl z&`GJ^wVQgnA0za0C0=y;5Qk)p_xI5DW-c;hg{+oE;9HOFzWZ)6?mv$ATI4;FsY-ez z-hy4lY6?8|WXlR3J@*t+!ECjC9~4c2kl;^;Bkb$=xhtQbk8qrBpmMFyn`$;-@->uw zkik^wSCM&$E($mGCmpI&eE##3%f?o@)Tor+2E{RHZ^(vNaxrQb{qt|%)8=N`$=xjB z7;sw>F^*xD`dv3xuj{pfsxN+uT&uYC9%>6egAcIef2mQ4?#6kRvT1lla1Xr>Ug})P zI%Hh^-dWzOlVXNe_bOmVdj5%`*+&gkpG%uqJ5DdnsX;-?N7#6ZChvkn)M)w z0O2}h`0%fSRPtum8tXh84tZ%UI=LpT)D!6*XQ0A0+2M-EQNe7p1)^RpP_%D{B&rGS$+N=5SN09PbCrJkcm{d6g%@%EeVca>bP27!}rb?Z9}=a+Lg! zG);bS6YucQnsckS;s)|uex{Le-q0s7kUgLOH#de0hq?S;c=dZSj;^ZiV>FCua9SNkcHDM*!Je<_09q3P zoHoSD*o)Kba|0AU#24!Nxhc&CSiE2lK_Q*n9s`%FWhCGytcGlINc^3kDjS;5BkjX$ zc~-Rb02Q7k>pm8QemM586k1-Kzuq_~X~|9~b=G~XPUb#|uI!)r*u4c1nCr|gSwufN zaoF#=(F`t5aZMS(al+U#VS>jlj}GiIq}VLA#tu$d?E7G<`7QYXrOW%6eke+By{Wu^ zHkcY6xcUKi{f#cg1$G|U2+}DP=~z#a))ht_vEw+tdSTzjP{;qHc{w-$(fL=0IgthQ zx|nMI6*Kt=N!1wXU=_)X+9%-eR~oR(6^XjQ*Esm`_*j=_rehf^VK3ByPhZ!Plf#}) zVPUtla(0|z`^x$ydpsIj=)SuDRKn^Xl^eZHJwCqJ7*VZ7{%Qt|w|;9_QhP4lbKL6Z z#8}Ogf)0+hVVukQijw8(Sw(h^Xg1H%R2dny8;S1VoqZha0QJb1)OX^(k7b zY1>kO5}z@!*m}gAx}#cq7le0l$>5O$C#agdkK@Q=_;{rfo%Kr6Hp5qkFNs@3tXG(K zstLLgUzRB|HC4!--n%U`TM;rh>3#EzkF;;O4>xW*5TmZ|_EP97y`C7N<1pD`*1lsN&V5fn;9^XRFE&?IpD-qj4Q)wHWUAr~VNWK+CH&sH2(XuLv zn6mH;ujQEv>u(Ms6q4@N_Xf`#E+3n_BgighqQB?EdG>-pVMeky?hSbZt9lgahXI+t zceFc27l=YtDaMC@93$GXl$}XyjKhfVY2%jHG4XoiFZK}~atAdr8s=h4W^L=U%nTiC zuOkjeMOYQXf#(5Q$y~)E!E~bpj3SLyE{Wsq=4~qo)}<5Anjd>I6Y3AEdaTEg&Ea&3 z0Px~dy7C?hUTw>%m$hd|o)3wy5m*Kz-;ce$6F3w{QT^}7DRo}80FyyaF9o%wBe>TP zkPm?$D0cKNL;QE~3_c2k9fL+}oplg&ChO=?RLS_vJBpQ%Wwq*Q526Izxv|U@zZ78` zv&T16VH=C^;B`0lzBIfOGSYSp)m$my`dkF@?fd!GRu!&IbvLSB8BHK8-EUC%b=F*0 z^$a)v{*1Q?G!1;^9cl@NK_?QBJtj?5iFo+)FQ^EzrsLko>Pm+ZUeC0)|*!db;~~vH2fd} z=qcKG*{96lTTIOgX&2=F3YMw`%;3=_Z|*E0hF@<^xdy&**SH8AQhQ_P=^SGWuZ{e; z^!?R7F)rZ`?Q=M3)S}9NS9bctMGDN(nz^Dqg=|1FP0=*K`Wv6DI~Ob=5VX-tzz~#> zdGW(kSnp$Eeew6FV=4ose4>;M z0i4ws+VO`1Ejuq6vh$FH*T&N#KZ2NA-_`s;F`+#U9wQd|!vT4TJx&Ytl}FtQ%JrU} ze9?TSy$<>v{cT2CP&gS^uW*~>!g^6Nm3S19SDsAor#Sod zf$f4x{o{5rj;kn1XZ{AGbg}bHaX(1%9g_i5l;8h3^yD%8ZS8A{bvdu6J^ORz*P(`i^YN zT_wr!&(r%Ps2h)R`6B=A7~jfd7Xcw;q*%F!}` zb|rnAkq=)!!1V>~aF*8Stv}juYcl$5k#+N1AIHM^A$5-LApU zNa>r-jL1bh^w9Tj0!V9fXQKSlE$iihdZn9TB*bHs&RAZaol%u-k8?& zB;do|pAnitz()z$qy=uSr1x)7jk3EAP z+qm~~xk|)C@;2jFu6ZYuTSu}!D~ zlfw$A2!!uWiyhl@vr&%)!R>)1c!v@qj)+|jvSDNl}>h8>$R-}oHet2L`ZEnS+ zKmFNiiU=omV^wKY4vpjehq@394ol82Di4<#*10%p-f?xDNI;WakJx#;!-Vi}Vz&Kd zyS(g^%`wLx&ob|u2p@(|JrtmOA;U?TXNVvDqlc{xpWvShu^Z6I`44x@Ps+^5L`n>_ zGqE?dv@_=?RacW>;35?ifa9|_GqW@S^8ANRX86N98xj8zwR7hACySrd)yaM!iSUHUg!{y)|6Z<&AV zvbVSYZ>RsNkAJG`Z`WCvnAiaS#Q)>9v#q7g|J34NSOyb&TZccSzOfDP-$sq>EN%a% zYW~9hy)5u=1?Ensrhgpy-y7wR&#VA*fT@v-5rdm0(4Fi*p8r#h|9fe<|CiF5IvKhD zUnQ8C0DoafiT}~g^RJG|LMrf|Uinw^3Gn^hh$c?Jzsth#$3dU~3llR7!=IChTaAf} zhmDkU?culrh$W# zy%o^J1;EO|WXnu0;%aGQ%E0s0~0d?3#%G47Y{2F4>JoN;6IuF zIPu?avh!bSLe4IhCd7YNjJ@$+hW>ObS34JeQWhq5Qh)&8e>EG=KNbC-*ng||JNf^A zQ3>JCqLMSv<*&MR{_C5wp{?h<(~9c5X%JsPI&BhfNfRetsZzcka$Y(1wz z{#1oUcurMWqp;;rRc13<15G1lFcgdZjI!t1pEctJCU>-WNWWtqsc7QMJEO)o;tw@! zcDJe1WOb13lDo|Vc6iJrwS^};rF)b9dQ}qb!8zwsgLLN0)Tv>$Kz01L?$NS}JK+AD zo&su$0ZP=b28L9&ix+Ou0rg%4DB)bFwh8$5QWlzW4y6j&UlW20=hCJi zZ1Wnz<$`6B_OY5O_vnQ8(sSoz+fQRqCStLgA1gg!6Szp!GO^1-hjoI7hmmkPK&0Rt z)Qsvqfj)np%kf#f++L8rP(malLLoK`+X3P?rF0S_h^IC(W7x4XRB^uOY89<{@oO8> z&}}jbY+dfki{t)GY5Vi&>>V)%Uu%?M z-r&4?HEj_=&`QCOv|Ws?N4;1a#Q|QgNIz}e5~uLu-lBW3ILJ`U?m05@DFZS$P6I+& z#?_0!D^|2 zt;uJ5%*m&7;T>^cco*-Yww5EzGAZ|zs0DvKgoVb^i27aUlK?SkQFMyGIeJV#@0`iY z?0$d?8oy{Al_XVz5CoB)N*9jvll7yc30p*oScs{|;&#DNaVu&}Q&?jhF7N>#fkc3n z$C9(?b{ynLTS{5KG_>_#v~-*O zOL|Np!1cdynIZ{&8(VsTL!F)JmI(=1;F*4TylYXyz3gEZ&Z&`ogjUFQsZ<$cB5oqA zP%*fZQ9rB(&;ZJ*OkA^9Svd)gKW{b6XX(o*aDkIxCNxteEQsYlf<}b-)`6@v&T)sr z*WEsc59``0lcBJI{seSVv(>((k4Sl6yl56+4Pkz>uPl~QWl_>Od=Ix0ES4xmxj1@t zerO|FqTV8bP2m~*aZK8ivehY!<5egI=JQll3m%;LzLH(cFdQ3)5;WF%5$Hg z1)6V_R?T;bG2-yuu?>WCI81M(XyJ-+>ztyDzvIYs`w5pFAO%#@Sj?2dSCu*Bjq{=I zCKuMVNig+uR8?{RJ5>%9x z4KNqpQVw)q02SlbT;CoGQ4Xddp(35q#O4x|9hV?LH0U3_XsPFW40e$8O8pK!%u>)p zfY(wT#lBMrM5kt`UEj>+sEDz2VNfJM4;!6mphnB-MwG=smgyEyA!SeOyuY&!h^(P3 zNy;8v4kBI0c-r*u?`x0VywUbPc=Y009H>n5LS4X^9lLN+d0zXwa>k+0Pp(^ZSR06x80G^vcR~F3^pB2NM-)pY3-xgOe`X5iZ(c_r5=($x~=_#BZT|`g2Qh zfx7(p?5pMJY&8;Djle=~w=2vw$1F)Z?Dl9B#)5(1$eHh zqVF_Q#*+RYR-{^9m6?!4a{)-76i@iesNV!`Kl_Niyy+&=*rDz}{E`?Y^6EKzxBqJ< zeFM-C&VvF2Bcb}wO#1({T>}2k$Yx@1=knJEi$4R~neRqIp;XGjn?OiSdpo@~gD}^J zn7WzbyIZlmnYx{X+JudKO9+XBv0p zd*Ay~J)?DfH)w(5W!{a$J(F(EDCL5wW9}!^=~~_3 zbHb|e^_ud#{l?IW){f74+WLSz>s(_<=RuL@1ihm`3qi)xUkSbQKKEstY&Y_IPO3z$ z-7w?JD+N14uALQFg`W7(=DSySckKQQSAJZ0CjCr9zpW)|lZ)X~^2bzG7SmdTH87)@ zV?n2l@Ti&c$Ay+RyXq|Qzq_J(9DetCZjG;Sm}z9pXzrz@a|s-pkW)FldFjrL zmtiFj%8sXl3*=MqJ5({aknD&tXKYQ3sjP$LOyWLYA-~+zP+xMqiY_~>xgU>F)R2_3iiwBf2AZEwG zi86qa9i=`AMm2oN;NbkE6q$BqK?qp)!jR~xPMj23tCoY?lQK~<&y#CS7OnQ@q}BYf z5ol=xOR0MIQeP|PsZ-1P8FPqDzC=MtjWd)k3)t*>0^sL84hs(0qa@B36-;LwbJL*C zH&n*osa}xN@Kl%m5_ZzDXWOmcbSt zVCqx2rNfWo;8Zyu7&w79h6UG&lBzK=q0O~tgfzAY{UQwmkKob`6q~2Gq4Fouz(13- z<5k|uXfZs0OUsxhkj8ekR^?^iC}kuGN82_Ib0U_8>cl(rXpA&6_D9f3WTh(U`e7+) z#ZOl)zFYi`JN3Non2jxy&f6^C>Ba5YxWfi7yK9e`@pHXyvF0;t(GC24kSvRGzeQ$# z_7(3$f;s!yr&7Re4RO$+w-ApvyQ^-?WgsnfY2V&~-_h%V>e*m=HS1>z6O>q^XybN_ zs-LSx+CrOcr?d2%ccOONYo08Lisw$-9`gk~*swiQ3Eqw{N}LZ?W{j9%4Rvu{uo2lG zgs40Fev0cr?VWkS23;x-W;kJ(9N5JjZrax;$_a1@g69P!xyTWH71h4s5VTOgwCf+@ zR4Fcf?P%_|N~>KY;rWmV;aQv7>RPxFZ^MYaZ)!GNi>UyKp3FYMK&80cVRr)FhZ3H% zFEh_$EZ?(_ZRu7DG@^sz{ScpL(caQGR8ekI=nTj<8_3S@TSU-j#;3=qp~lEhiKtQBuq zNW>>Xi+H~<1%2az*-HwWiD(yfLwKF8Yd$mUo&_|C1z%}a^A!Fsy(DTB5K&Wl$p zf>&siOc`*UF_ZF4M$-Rfo~|>{QT8Mjc4k#MR-ACmHr=26Xfebm0E?oG;t2$y%rFA# zEN|KC_K?e)OYlhtS?OF~I9Az2`lK&u&;A0}!k6Eb{k|UhoYyIpZUD706WC&E#ki3c znY~QWkx?gJFhCc$8Z&_EuakhyK;>Olsee)6(Ja=puFwRrf7h9E>+L63U^lRomthL* zth~jLw^?dLT|U^G>w(?we#Esq7jue87ny@ zTd9xVom0RI`xC{ovk%HAhqA_`Jk<6!JYoAXnz1qVhq9BkvFpQnc6QOknK+`3=ihw4#m z#uKxzS2g4o^o+Hi9LY+oDlk(Kci$Q{mlt+MV>2;Z68r0!ZRsA|e~67zHZfGOP?*1+ z^EC0~5HZTNbR%AC;3fE+PPw*mMpusHQb@^K7~PCYbWo6`k(OFJ+<~IjQ)G%dMQ2kq z%aW6HlTHeYi8y=|H+%JyE~N@J+?nCAD0KX|f)p1?b(0)~k!EjK*{doN*+iBqPfv7xfZC&qFcO4rGDjv)vYJBE0?2`U7}!?5tw~Y zdZ&I$_t`mO9>*%|`MCHtVerZrcb_gS2cG4U%I(^`|8Uj7x~=~$#`UJ zf~Zq0{wxtiSkf;p^6Truy|`7pup-G3qAJ06J{A6|har-u_!G-Q$uIm0{PKr>{B=^E zn%{XI+F-LVW08JTFdrzK*=1p?B8hGLzZvKuCpqEb&njSqM0U8QzAFJsaYNkW^Aqd* z`Nx#}sb2$V9=wINPsqg6-?kmj;*Cq+9a^ubpXP|*euOy^Qbc+MZ(|G6t8bu&$-0O1 z6M>z65nJoec&I(#uk_3%T_s%X3}e4An()@V`SYlVZzEU>jAvOSTp9|L7nJjP;dqG` z6n?nw5Q!TjSE4jW8)J~@k#l%q`*L-(j})_C=xlusVs^|126Nr66a{EhZ%L!q4#1|N z6<-Xwiub(6WVaTQa3(gmA6p7OMoXTmp0}(h3t+ZzAo`-suq0?^KbiRH)bZR1Cd^lR zo&t8+<|<+zMV3cJylE(yHy7EbG$CvTNT2P}`0lEJN$@98YVZ`XuQk6lmiM`b;pfUg~mgU zXz)*7={byJDpS%Evt~A#Bo~VDy=#ZzRS3N6$%^#2;;b5p7kHnBOuO~+qC2l2;2-T) zm`07%JTFlu!X-sCIO~1vPsUS@YeJ3#qUJ2-%k1(X&l$X{toWztNtkO`2It7#Q@FS) z15n!9LhiE-c$I_oLn3uD9L48)< zkB-K+6|p<2PfKJESPJf}jNpqLjz=B(G*9ZLIJm+`u3EZWw?hH5iVff9Kk#6m7{*yp zu)9?AEAkVOM}u+(dpBZfWREC6;?hL{_nie*B&=(Rf_}PEBaW!d=F3s$eY=04O%{t& zGqxrh#I1#Iatx*N(_$9-tYTvK;t`0t%+t+9Ybt{`P`)CF|skLku7FwOE5Z4#+0_}A3Is+by z8(riK%<^iFd$Kl8Q|Q$c3Bcwo2CVinh9lo?15w|tsYaR7Vlh8WGASZ$afM7gG_r>k z@g-JRt7-2yakjgFDx9?K@4-tYcz`aPjQ2A^(c2JB=h)!0?Ul`U6OoJU`UB?YHUGZd zc5*0|O>VFOGHW{plUZ={Zs*Q2%L(CR0q>iueohNxi7&7wfs8(z(Wrg4VR^X?Lya}N z=2TIs1FoAqaR%BEE9qIrgiP!4@z(;j?T)eQ^2&fdo^a}X({PlPB zWK0EJ&^A}-wh~nTOwYDbnATJoPRv)rMuc|4d1G)VBq)ewhspa7A@N*55MyGti-^b} zr1ERa$LR{AoKFr}Lic^jm3{UB+=V}%V9(+4jN#Yz6%5x}y0MDO)aL$Lka)AT1xtIQw|q>07GDLMscv3JT@tz14OhK5ZC4FfpE+%x6FF@`&Rb^| ztBeN_;(6VAY>sBsQtR+*Xo|s%T2e02F2An`6Ho2?HX7loODuB@BK1E3G~!bL!mjd@ut1y1^o?_ z@E&ghW!V&pzsSX;6T;^}jpbb|JKls+g+v;#;VN{*yhU43sqI**?iRutEa1qNV6dX2 z<7-u|IQ7;dN4~>Rvz_xZr!ftw#^?LvdZ>(-1a8F&D%9bppG@*Tmnl7DCDxWyk_)Fu z?%Rdg(+1k7N7?%1vwk5+HK7HJc~F6B!HFeC8W5CX3nE`UQaUGDOA|6xVytPW6C4mt z<+Mk>7tK)V{^V9(5H`h-w(o88LkL%!mV6;_#KnnYIAC#9yA8sa9cZlnHa1h(Om?U5 z7UGu(|JF=|#d*%jZ~p|&dCKpyz8-6(kj|H+uvT2sSZyVfE~9qpe_+P8uti`v;8rs+2MY#OBrZsFXeByo_+^1K^rX ztRYl6?PMl1u_*}XWu%RyQ}lAo(liaUQuKlmrLFo9xRDy?{wd?POyG{LrzRH1rA3?E z*hxF)raViRoFP>?D>f>DCTs*YD_&|E0$DlkiqQ}TCtg%RiV9g4LD~*DV5*8j z+KbViA^?k*An;bxLdm%Pk*i#TCDHY3suarucK03ntsk1`jaZ^;+FaW{Tv-h+yW~27 z$>M~Jwy@}EEu!a3w61uz!a@(xfN?JvMMscwifn@<{ zRxN6(2R$|Pi9?rum~%a&m8%SX_wh^eW9^38vfb>5sMzQ-n2nMZ1m>i%=2= z6tS%wB?v?F&ZghNh;?B!Jkj2$gC-znLQaSQk%o6xxDE5$U~r&5`b}W<6*kc?@1&o; z?yG&UqJsbY8_r#7rymUa>(6kRF5ZI@PcBP#)v05?=Ig{pGTo%!93b2z6dicsqZ9Fh zHl{rIi}g3bHp59V^rSdi)o7kX-7$`N??0c`7Zn3$s|NQFUpjsT&o?}K=^AfDL=!TmOpS<&v=mh*u9dFwMl7@RH0xA;}b6z-IUnATTB7sr0%}1 z`JAj5z%PE2C<51`Q-B!YNd3vEZsZD!S1E{O;9yzac9pU#gf zqXpK5t+`BUl!_+XJ`5IyhJ{KVjMwHLb>_LE);_RZo zp&2`$v*)T)AC&J_OO;GWh|O6`1vMS+l4l(QSy^3MS{Ft;g(MvKj^gd`YQdKm$q3O} zi1hRRTWDLR2L4nzBN1QT=R^gw-QQq~Oeu1_2W39 zwfb?vY|gQhb4QU<+9?~KH4Ev8l4{^0=y7VWa4`9n)?#VSA)Kt!{#tUA@e~PzB)nkm zb#Yg^Fbtq`*RGxK{nUU%(A3r^gCTCocxs&dRLsi?gF5^$G`T~nos4Z9k{V6QyEN29 z!AsZj!U9%1F`4y%of0rCCa~g`OML=n%Z6CPre2w%67Tg1kH0sgq@?&LKG@qy8r4I5 z8ve%g?vi5CWF}}EYstIoeLLShPFp3!t=`EFxZEFZQFEUn~KcgZ66}6 zhSrWogZYQ1x28Iql}kyZZD4}9_;k9n0xBYq0OP9;%8od z5{xg3Qk~@JF_}fHwF!kQQg&903%EH43I$R^#3~e!Q9SJ82{GIG*VNw?_?a3-`Js6m zSf<)^bX{zvzMSt3u!p3KESl@+YnY7j5ar+lXz&6QHPeC+4UT*3-~_C|p0^WS41Cx; zOd1*{drJna#T!?g@=U4-=g(A-Kj(>O#Y3&s%;hu#2-{RGzPcFG+sHv`?e>LV4Pfhqb zn-;iC+?OUQZ@SKUQ5jRnw{zg4@hMIqKC9oH#j?qui&s_`ixVj4}c%qKDZ1#JidX`wUA^{tn=Y^C1`solW?bxN!i;5ga& zkugs@^LFMAuBhe;&FH*5#uq%~2dJtT{7CX+ZBW6yD05sRfBASh=yDjYGUTu&PEGav z@PGl=$oOcvg>%->*$R8J-2Xfox7BAQJrirNegU$-)MTtm*+blyAE}@d|LvUu4esQ3 zEgI;9H0T^yJwpCz5}i?k_YG2L&KdLDg=ix?O05wgNGd!#WOt$!`SPAxo-p3PIuRfT z+9m#p3Pq2zKN^b}tLz^q@WCq&l_h7V5gcfUs2C*?|?Hb;kH!jE5YLBeEiPd9KcQe&lw$tYn2M_enI1TKZkI zG6m7b<%@Zr%4w%M?Xd3;2y%l<3(n%r-cM;c znYj>xc8|={HW+g8W{v&=gB^Um2KM0JlVCQ_(J})m>kilQ>v<{XH1nPV$=RZu@^C69 z!fcXJs+r8h0gvmB+ppvO1cMqOB1<;Yzph2 zdkOC-m?{teaoKmj=I9sDiNmZ;6YD@X2a8AV*eZJrQzC~ew^Ei~&-pY~yS7$W{$%}T z_wj!7ZF!3#pG}h8V`W&U`Sr_(?aqA~SDi+SqMoF&4HT>zt?k|WJxxlml%9_}!S41>xf1r&dFitY|2M(mt1njO*Zdq* zILgx8-t~1b;z_~w=Y{t%D~tdmeVJ)4eF&4qV%;O1uk3^wAlsiUn}lj~5hvBk9$gj)Kzy(1FYlqPCF+ z*4n!CZ+HKLj_*-|sIk*1&`IPF$kro%Grb=CYIh-G-5mvxW;%giA~;?c+-IVAO%A-{ zrYsa}&>0va#b#WN3mlG>Yhcr{*u>e$<%9ewDsibviPu~Yf!fLr+aRXOPZr4Y(s%^C zkwr7u%6&QFn_1xCw2J{y>P%w7{oilZu9En+%E-28_U$f{Tu5wd+_Mq#R(nj95KC)E zBV{DT#5phA0?S)s5OJ>-A7Hct?-2{rPC%z^IE6^VZodWjit}p_L_c6e4G2n9esCl| ztLdWhwW+IQr<&3%IS5Hwbst+pSDud*^;;d(W;_jRux1_?ya|6gdDy$t)|@~M7i@?1p{K%+V8{`Ew0CMhGwc@qR;n`yGyG zS4L;NGQn=1tdi`W2pwS#XvhVv(hh$uN2lAsQWQG1BqC7^)Fv0+5EaRk4_!?@;Kgaz z+!k*$O)qVu6=9I4(+wrL45iMQKk{`qVf=)(1&gp=={>c|B{FMQaM$=?{<;;wkP*1Q z;i_9fS+n^V{?$B$6@SRW5BswaICFp1K*O{F6n&LLRv}iNMxsh8+G5)@MUrp!q{&_k zFaG3?HC2xDrQ`nN80w;rhmQu7z$R?&!tUi0m!xlwL?fzg+Gir8FO^8nTdJ9#dthO+ zd-QDV^aLE7g{v^0-@@9&BT^f$$Fa9qhamH(Ha=WS{ZsVMg5?n>9#OXnR(vhFzPgCF z?eeFtu~!FZIulVwRreswEHyl?Z6rsF_EDbS2Q;N{m^vjBod2wD`IW*f0YD?{d^|}9 z4jr8ur24&{eN9b`pwf&1m#*J?0mq}1Xb!1UUnn-AvPTAqD&b7FmMurWW7YB~1Pw_{pD;S>%4Pr3-P zp@bpb3s=2NYm-j`e!yw{fXl`zq!m1__=)1)DPZv%Y9zHXKI1eGchV!8D*s!R*#dNy zU9FbQWuOYlb=z_Wr_KXR?O^5JeV^ShO3j_|9X$?#VfMiM1-s7Ka9ekY^Q~y7fn&1{ z0fhmB7o;n^pn|p#QB19R@R2R-@kUz{);<2tq0G$^Z#xHr(UkTSn%*FaH*AdH@*%^E zkL1rQ=$Canj6=3{hU2?L=x5NT>-2rN+34a4o~NZcK7P5J);@`bQ;cmIE8@_G!0urc zVjZTI`9L9>aSZskLyI?7a(L_zJ-s2TlU4Wbt-ILb_GNqMM-?z)feE^REwISZzEOF~wt{mSx%BV{b7Zu};)TD2$3< z&JF_E56@{XpdSUgG$+I{&q3WUqU`R%{ypX{Y9T^q7tDW#`W+_Dxsnu)87g=9t(;)@ zYOY`QaIG{<&Db5&=WiPbT^f6M-wfkCr5T|WgN^=dPWGqng{N5ZO2#VE z15wB}Z`~ZM9=78&@OeD}G-YQKkMe&D<> z-%g!Ofl3{{n}{l^QeN_d{j)=Z9ZGBk&5`D(`En`VA@;aocIVr+&B*lyCCJ}78>tcu zKtoA-VjWIEUrunA{*{EByb%Qk!sI7oonOv3hvB;i1BgmxWX$N86EqxIyeP(&nB)bY zQl342f3a}(x2?C#v|-Vj9F0cJYjj2>TgoL#tqhlq2grJ7*lNu*S00J0pwKi))L2FB z%D)|2h)f6SbETN^AOF0DMPI=4uLCRNnK7Cb7T*x(T|KK50mr#p_`FN@CNjsg20j5v zjvT*nc>KZ=rRb{Y8V>IjCEZ6b2uVN*J3$3Izgaw`B@)D-UgrdqJ^)r?KvmRh5t&=d zM$q}{iIy|-TkAueaE>u}icQX{iCibxk4i9G^C~c6sJ_v$D`9HBh2s?N!P?9?XSPn+ zQnednM)8YH+6Pk@_oVUbAcG;a{02TtHFy!{vSGae7%1Ne>RoQ3$Hv~3mfY{Xnzk%t z;iu>apP?Djq#t|Otu;d)?uI_M5Lzvz%769}6_F_vr%n=?y6 z#DO+GbU=$)B79HWv0TyRT@&I=lHXS&BzUny7O)ylu}2a%wQDukUMu#Qftj5>%l8z_ z=547Z9Lu3iHxqu(G2eOP%z|Jq;!KZi^>%hfBc> zF}~!yn;M92HZrg_p)+|^b09Snfd&rz^fEZSaYT@civOR=z5*bQEorw0cefw`0>LF{ zAh_!Q0fGjX;O+z`!2`iHXmEFTCj@tQcSvyFu)BG=yL<2MzcoWo58YMg^s%n<&8e@m z!Yg5n!8Ek{KC?MtWqR__sBd4z87ItW#_Qs1m!G4uV4B~12R+51a>Me~P<#q)x9gw$ zak#rjP)@|e;Jr@o4j`Yrym7^fa9g@Wzs_^BhTNz?0F`qXdw$<@X74ti@R82ssN{ZS zAc^gqhdy`^gD;Z^n!SGI<-x!eO#j4*@wrHVNxqkZposkU;Q$&9ESSdf;1wUkcY>!krWsJ!s&hxzp^Rwe@4E*wE6gfm{%c3;hZlCG~l79I#aBuo{ zS@nFS~oIN;>9h`ax1Yb#-25@ zWzJn(wY)PFYu6-nF7BWk!iN$QCGtbWYdd8o4BroEX>1KE-07v z&xY6fH#Da{(6QD^A{Ref?prwFlyF{b!USPgvave~lQF2tz3mYuw?z!&+m??iojyR7 zR;+B(ixGd;jJ9Hcr$-cu>)>ufG}J&KOryTO{NO7j!!#O{HU;PB*aK%Ch~t3b=P2>n z7tU{DUbl=MGv7CRVTrT3-Mn9fO=?RMsToJX6Do&S*i*aK*)QnSkgY zgvPF&^G2TulLFu7sM4CgE!Zb~n-S{zl@jh1Go8MWyNvLnI-Y^Hf|Drhw8yv43sLiz zF4^Tl-7@;-#Did>>2DT_VzupjNpaW+})srh41ao%$%H z19|)_tK(Q+Ygd~>)i;J_Ts_a7ts{Na;^VLLd5*?ZjFfl5#YNik`!ee$)bqXV@u5+I zX~DheGUkrnb&#}YRCiu;&iAEZctcx3Y`2S{hqXA>5^WiQTjS=onpgzMS5h{s&vgB) zDz@*{-0)E@a$pUJ!9zfrtjaggvqn`(lAT6c&s6g?sO*p$ce zv?iHS_YOZV16ZDmuzQqd8IV2cwU*o77FhlfiA1QOrColQYU5LDljs-*zN6yHj&a*g z_nUF(6{8XZx!$_iAjG<&@N&TnypMnP<=)g2GL<&lz4x$a%-y+2=HhF-`~Z_~&CF=O z>QuY1cA$4pMQTxwAh_RzrVw+TUm9W*7nUg`;8rm#<5Eez+o!XR5R|8+qFm^(q9oR2 z_Y59RMy}?Q5?_jZqbtwJ!Q5a;RRG?*tEafPaSx=AYuwsS&}#~)0Khm0^e@pO2c#ea z2#pNz_(uR)3?C@*%k^Lt~K~4e{i4X~L3aXT(s3HJ>AiF>-0u*Fx z7*59m02rU8M1_=Hk`Gdl6>uj=dsIa)A8?<8F(X|3Y0xi9)Gm8fGcv=XLtpSKzJ_O4 zR%XW>#Nxmqe*aZ>1)8>e#Dd|5J|-&W-Vz1YcG$llbD2jBn-K^3{Gq|3VxboOu&Ke_ znR)BxiSgF{%)-)_hTGHRHbEPprN4|tJGCg@NjUl9)2X3 zy}t@oGfNIQ-P_$ICP`Xu(WC?)2X}UNi;IgZuC8{4P)K}gv{`{lJz7~Izp9(9GLK76 zF7%`z3=?ncPNW1Y0G4~{qL!A7j6BYV3`=$M^Yf!)V@aWyaHhUcFHk=qu^E5ka@>t> zXyAdBd9Qi0mFm@eF{w%FagI6hSt(mqy~)in1ds7Ne4)mg^uTFvvIvtx+|by#+ImSF zfj4k}e;=I0sny`b$iQH6e|v?Ai3w-^_Otk9O3VHA-pi%;XPbjbmCy%AySsD*=?c`0 zjFvs0NPZqIk+K>hq_mHXv9Ys9e{!_7y}J9kL(`v&@Mh?@9i;+URKk+PdaBusTKvXB9| zZbkluZ|frGL$J=}7aCpJQtRxuz8^K;d^)03s1WotI8FsunU-ib(Fk2QK$0{wGxG-@ zHT`@_OGif+Jlfpctb8Mv@@hgCM9Ct&NK3G@)FMDDF795a5|NL$H^86nE|Zm!;kyc>7xN6suLr3n+}F>K z_C?wY@o7<#!^4FJZ9}G|b=MU*VhmS~u##(&$$ieEx&AHIcAT77AYZFT5jK zxJbI25c~0a&|F+x+wT;~Ia%V)QjGD7K6yhNE$nr<7FXX;dXBjG!5a%Qkbt@Fdxn77jAp13uH&04>)Gb z8kM<_a#?SF{``4fUfy^*y9<+4=x`a1^oe+P7}3`LK7+-xB$-%-o#`@)3lPo8<%vOh zQG>@#byAXMgVRCnHJRDzdS4u~PPPu?X5uu@DUx8y>j?gJGe{fFtW7W*+uk-Y_=%n8 z%%#^3laD45{uGRs)e!V5v#P3UoyGZZo?NG|w>K~(Bx(pDCieDAXec2^uv=4o5{;VI z`8H;XZ#{+|Jo;j_C6THZbG&CtYO0Q-BZsN?D*>G0mYc(daj&$_=Tf#AhWO@u{h)@{6(Y@x5C|i%oL_12Sk7ylZI z6BpZ7U&WWVM>5;Zg!$U@ZActSH#Rl3-2KpGc?YVWeg>nTg$evXxQ2{)lz2eW33{oH#W)lh64WjXImX{czp!Yi z7YiUk92n)m6@2}5p45r%bYe32k2--X3(BWA+$sd~sVQx3H$D~wXg)3hO1EFATm{~e z_6Fzi14}qGUqLPcrJyhe-wosdS?^N#>Co;Ys2MI|;VyKGpt>3%OKh|!XPySua2gXo!#4kt<+hwQhaT@kod=c>@MoIuU@=*6-~5oWTbJP09otU@KDtSSQAE z?|q)>aViyWN}&Uh9~L}Gu_U3FIy zj7rgJEK^LQg5U%@Eogni*7?XzPHwg`1ljqR44?QLH;=u#`dcvS&+k0*gGuv0m+YIH z=T|!39xc9oxSvlGdh5!q`ns*I-fm}S-Vc7hBVc}WQ2GH&mwucEXv%3HP*RLdvS0QF zX`p6(wGAh=x16(sh1Edi;zg?vONFD zZjQNXkQZ7h+8j!fY9>(ou_j`Wr1kwR7d}xz(L#gs)@BleUNR0xAaj_i|?>-nqFg z_Lna^9C+a9Rr}RA)8rDP0l}!YWiD6l46@$^m){Y~mM8T89T5fmu*;EYE)p}s$96Z~zNLIzjrn_6(ips27zXo_l+J&MiWH?KWm+AsA08R&_{qeEX zwOLi*HDxx;THDk%(-sK40fB($m|o73>p65}KpJFuXRNx`3G&}PwlrQ90ctz}Rvd^g z*O3fR5@(v@pDjU;l|Ba$weUzeqL4nXt&55aSs()5aDsr~!T!+q2x}Bt7$CaS;g*7T zo%OC%R`#(9Vlr+bWSUqEV*I%YY7(Xu7Z+Dr zpZb}vteB*J@b<#ovAHK0w|N%t=nhI)N!JvoGa2xfhD0o-591KbwWV=FaslAEdQ}(? zeuIP(j%enhdjB^sl|dKcu9cOQ!M*gj-pMiO`BY`=>g_@XAk#1~6c!ZRtOSrkK|?Pr zEYQ=@nW!r%tsNaLW#99lwH|r{3~7*CD8#*-u6HyyHr|9poUE;`vJ-}dhs!G~<8Ywq zGfa7DbUBeSLqTD9!*X$RkCeNfZBlw~Z*Px|j-rvgijIkSZ7eAnNHB0AqNPTRR>TE4 z@0i5f*B9yz>~Zs>%GK5z=D#@Ee>}Vi(>hD(-^yNy2v9J!3Fv|W;1+rkCT%lLZuk`~ z04Ze)HwROpAyL|RYyhbLqw4Se_AlOj$jUq6rE;TzLiGxiLz|WM52j<;Bs@;vx?!PJ z08qUCXqFV8+c^R%>Vye<02;~Z`8hGC#k3DJy!a>Lgs3PHD6;1;aB$a`m&&TDLkVou z^z`QK{)k&csU>-Nuj}_)8I{odC%0}dYQ0vZ&kKlFu98Xpu0snicGEiI#B zK*oP!mMP%uVN`kV%8S zzJ4zz8yj1L<6dlJr0~7-YG=^+_;`JN{aB7XJ}&NOktpSQ=OfR9*{Z%M>W2FI(V)nv zC{x$db*b5d-H8HNSXfB&de-9X;PC!<8I-cOKU2{YPD)*Jw;ICS-qGRV;UOi1hKBax z!-vnGKSSK%j1DPDbW;8-=$&z8N%EF9a>GWWf!Ka+HC!kV!E&6AC%Mj}Bi+S0PWZOb z#dbXRb@WV*JgFTRNsgD7H&^3pX~6peNcJGpzskh;cu8$JOymP4$h;K~Pvy-Uh@;NP zssgDS5 z`z~VzzKM&CJzQ#Ov0iEhfk2cfW=Nl&@=0%yr$T*5Yc!Y7i=fQyr&(A1|a!Kj`{$uiyw( zo9xqD9A3%93~6YB>0VpE4ZriPv!#u^^Sw14{*12ns+Dg-KV}1j7$i<6{YJdm(K4Qt zypNdViYLdY8({$WLygP$M95J_#o0c)b=R*x-`4{tvFVpNqUfw;htXOVGseF>O27;$ zB0=E<6Deu<=1sr%N#yhl<8}2hB)TFGT;OBU=6iX0Pgb0Ry2~FsH1k2Z3Mq?Q4zCUv&?L$gNON1BLXIMNlY&g*(5x z&Fl;5Cnb9}F%X$g4U|I}yTjTT@ELTvzF|q;%-84A*Cg#M2tG+cOOZoV1Xm9>wXl1y`(6-t?))l}qMYXw{9XB{}g z^s$fr!XKHHH`wYtrpy^Q(u)+ZFlxinb1Grqbm81eBT9&%i1@FeM2OjE%D9cNMU@46 zl*}3q&qg~0k>o^2ml~i1U6DnpdfKjRQq$HDj??>ASxpQPhr`2!mPqI^sYf z6JNGDosKlAfTC63+ny!zr==~lJm{m=1QgF;S!CIe&U8lh{Ibx-eTvagV&bp|R?V|y zCrxIgRlOuTdcxKZa`J)e%-`CnN8VkF%Ap4+io`L2-bCvq}+ij}3RwaSl) zIOP}v{C2%-d<;Ejm1aJH@7CbZvd#kBxc6zJF*i{ez46;n7&5|OlySsG^YyCKo^Zz$ zkR818Wwk{nuKcXNg&4`AEdobDFB`CjkCCz6@op-$B(sgQ7rt$otsE}Z#Z?YrQB=F# zJD0UAAzpEdM)+lQU;Zgn=|Ik#S*Z#5>L zmx+=|y55m^LO;AkZ}ug7)oVD*IxEg{9@3b7!Se|gsoz1mRb76ZY=yt*rcBx#i)A#p z#e>NpjL;Rm`RQ}H$!f*4&fa^XsB4WK@_u zitg@hp-?Xg*13D_Nu(;tiKfzeA%veWq%QP5;*PIl2S_)c)Y? za2ht@F5)hh3yuC=-rB$f;0AYEtJt5AAD~};G1Tu!{L1o!a6;iL%+QS~Uc#$>OVf=- z8a_|M2HK&p(}IC7XhDWgZR>gE7>1_4z^{QyvNjCWqc7#PpDR&c3tcaHJ*3bkA7cn@ zsSz!q8lr!b0&`9pJZmlOzdt0JDlvpa&MqflY3k~ce3M1-2cn19=tE!gZ0vYgEVRPW(a4eNEbrfe>A}?R# z8J7g{f_Ew8-`Br^`+{NxKbO%5?&MyPwHOW|s+0XXghl^K*iQezwDW*BgLD-2>74=F zSC%~oCN06Et8>1f0dBkMsrAamHfg+J7M8T4uNf+kx$^zR7!Aa*H^JHxI?%Ze-2@KH8Kf+XLC#=dMLzD-(2A?FyqSWgZ7GufxnjT0eUQ!*rCz7L{Vg&ukSI#ZDm6G4 zU8u4X>mkO8u)NF>K^)L z&y2L7_&b&I5xpJSo*e0-}j_)s04X|>>YkY>+Ricj1uOY~Q=0y4_Wut+^ zw(+RWtI71k$m2yds~+6Q<8J3f!$~c|#dSHQ+Sk1-7ko78f zrDC*SYunWAn~%t|{1H@rx0iuW7{fK_G3krGwIIA_&^LzsV}UHYMz9bgqY!ljuOq4F z8Rsq>O9fHqEb*2Oa+&SRz_3Mh{U|F8q88H5>;*DTSAjrv$cG1fpxBu?Cj>byGU^k?JOX<<^eZD?c<-E?$@bDs}$V!40&tH}q<7 ztIuPE;XE+mEqOT2C7Eg)GrdcMinp3C2kem%cjgs(@T?o>fo-aBN&W0t|o+rhM|j5>uCMu;JzB8A8A;?0Vfb2 zD_t@Xe28gHT`q*MXTx}uWS-J-K2UbKNS0Y>ej!m?x?GTkU$DJiT7WafpHmu<1Ve<|X(pz)h>6o(V|7o< zR^1Jg;m&zmn>>F}w5Fm;gQZaFdmu^dwOftS)5!W$lO*|@3Il9Bj*N`~oGx=XYcYA* zF|(kqypp0tCcJ}-)p2}9=CH1+ccXEuqS6#=qv;4OE_oJWg_VtVKZ9abtVj7hXwBSw zW~h8T2)GW4zcqzAh%N9**E_|P=_s^r`4+#PEY3D|oKcleWpavHBI457!!Ez}FXSiR zGsf8c$8LdqZ#|Q+hp(JgBh-hUXV_GSL1!?C{R*y4#|d?C>^q1W&-1`Gt-S^5lKk|N zY@jC-Haci%E|E)g_UUI=@NfEr?U;smc%ICcLDH$1>;O`~ug9=9` zFqV$)+Dq~4mwG&Xf)3-p!N#UWr5JC0nwYt=BjOJ$dn0N82F0A=MLrU5d5itn!Vf{5 z6Xr(YWVzSfQ^ZYFA>eohME6jtD#Nb`(g?v)o%qn53BLH|EOLKI zEZ%m*maRZ3<}BSU(i^PjhA+RaVt+$QPw@rNf@74gRr9unxs=Uy!470sp z&Z6j9Wrq7tDhcB=dn{XVN$)hB^f~&JC&E@?UJjb!u*;0Z7+TshKFmtaml(UV z%X|{d@dXbqWWSJV)y;rr>{d>5%v>wDiEl)xIV!xoX4ySs8@tG`jR5TMdH~1LFi6@s zYp|b7zP7eE(w0Nw2Cdp(Vs+LUl}BiLyCzT-RI^0)rTz^=aof!O>uK6UH1r?e5k~dl zXUqlMg{a(a1s*4;sxEJuP0;`#z4AXzP$3+k09Z^}h*3&ToY@k>@@Q;i|2LYVBIP!# z_7^BkXSi<;!D*wE%CCpJJ6+*_fYfbdvO4py;Ma+11JxR0U2?KZW*Cf6Ft}@WqE|FYX-%i!)hV=}mQ5Y?0U9Ec9}W6=#Jn$tDg4=0LG+EwnPwnue+ zujel;`L$KhE(M>?&FjJVVa@HBBOovZ<|&7&i2vuaoG2fOoE8i(&yO1~9}C@j6dr{Y zvb;qZ!l0@k1A@W<{`$FGkI2Dq`Sp~pUs}IFia)ZoK0bKsx4ePu{!fqL`epjB=w5%D zeuW2lY#4+u^AWW8rS&UAerGGg;w+5%lI$Q!(XlPm(f2C(~oH3Z}Em0 o{f!;|tKJ_+n#V!>w~(9t#gMKb0}JN~f95Z5YXATM literal 0 HcmV?d00001 diff --git a/docs/speeches/2013-03-25_ad_novum.odp b/docs/speeches/2013-03-25_ad_novum.odp new file mode 100644 index 0000000000000000000000000000000000000000..868c1168b07995343f272ab4b4907557f4614e7b GIT binary patch literal 26866 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

G4_z>kJIt3gzxv zB@FzlcTrM}4!XLH7b(I%Z%Ublqx)<7p;$-8lrBwzQY;{~;lR&f8VL@9ta7{0HRPE*(YWk_u{v&OjGaQ_x=(-X;89lDLKs ze-!ZAA6EiBl`wZGa+%%5$@yM4mOe}JY^=egxN*no6R*t+H;SmT<(8vYW|D}erD0ZR z@eekb!yK4&3zGUHkmNKK)@UtzXDv&vgJp+e4A%x$C*H;933>o?A^18KUBDqs zHm2D+nwI=8zC1^H4+ngxkGVz2-65Uj9EZm20*n##T)3%0T(x2#n_bo97MZdw#Lw05 z7;qc#i?XRizCyHoc@l`Z!oqoAzOub;ShH@H#C2j7DuuGqlgPPtUr^ zTqI%|5q8AH8_#w1L#fb@9w?{p3z|z%8y>lh)bD0FpKUj%%~vrXWHh6&nt4YYi2+7*%j#UPzhcO051DwSh+4;p z8XTA(YXC5m;fE2*$5;eh0?JHa-8;dgoYKymsO}p%WGn;O@_iwSK69KS8*G!WDUZqW z9yAn67=1$TZ5HB$s`E-d6u**-e%5`4QQ}6?*sgWV$0qEM`b;v0d4Z|gH?^Z(ZD1ps zf>Q9LK3wF^u}=|hY);hNr?f$FD|C2^ZLtJvVu{y20&8L5$w7>B@rOD3#c7%iN}G(d zg>7r}g#|v2*0B%pO&@GKKFWJFeXtf+v;CyJwC{|ceqOKOd~u;juArw`c)*1L-jX2B z<-llfYy8IkEHLbV4nt+8gfW;Vo%W7L#ShDB3C-;=L-(NI4`$Q* zjeC301_E7Tc%XzK7?lOXKbWS4p3 z3Plf72o>t?XA6%d(bM)WVVtz0;7LB5A`T8=K`3HR#(5b!c7tHTluy-m2xNcJoh>;> zVd9FZ*WtCCVx=pX<;Bq(65<(oK&gnOE%x-l%O(@OXfp{SH~VpaRG?l^HY6JsY6<*f0Iq9YGXD>P$Z zy;B%RXm_+%@9*ig*JD1pID~+{C(hrl7&*ufF&}Ff-k@Hd$tJ%tSL&^0C2E+dEWBAq zc&1iJZvYL<9e$8FxI{wD=Hj99b)#5N4tD8@`rhlYz}Q%Kb*68SpwiX-%?pOTGl9vS09+$8Wqt_R_|qb?2<6VWX>6CAa~hOeL-uixE%-`a){LO-kM7 zmn>aptMdqNr@C_w;!iD|sn_G}x3z<^?>rz9WpynM7g?a3#JcCLnmo-NRvB%=7`ydm z*%eGLHC&%3DD9SZY7rbZdU$e}mhS%;F|;Y2}jG|KSGr_JDca*cro%-z&tviu$xAF5e}UyfS;~$1ukEG&HD-Q zvW`#bKoHv|6*nF5bAjLi#LTW0nh(ED<~;}b5NB#^tT4v=`RQ3IoL%#1Oy^UUOD_hs z(ZPpkuBjI$gyGu8-vZ>*I~IfE3%FjCZ@2j-eNeDs<4zqzMVB(4gssvy zh1YDFsF5p>cv)vE@Og5Q)Kt ztL+Tdj*6aUqJcfY(o#64>Y0YJGsvv43=#Hp9m{|Aqp1R%6|+rTFhr5 zK~Zene~r>wB(=6t?V$d3VH1Ru4`t-adn)H7smm=Vq@v(5U#hgTnm@R{ZW^AEMQkXz z}SYm8pm)<5=AY(xZaRvv@J%?o@8G+eeFRP@K8wWv{94mLSgf1WmN<(kGnU|v8i*WnVz1>`S##VYhdtB_CBmYiP zcmR_W6eZQgSY?%@K-ORz3sV!vKm0n&)fH_!*fE+UEYQ|aP zj|;lQ4i8dY;GZf|m&D8OPWv2uimB0~de?`w99UQQ5XqZ{gcxjTF&p8vUw;))rj=N* zA;pVRB}k@I!nLxh`N%`<1*I_~<`j+`L4mX3E9P9}!1aS4HD*n22ykjO>Bd?uQjdGp znnhmLW)!RM^Y1fv*!b(k@{A{Jx;ZH0?q?fUy6`EcPex?`CQL0 z&p!*cf6sI;zW$2v-!T0WaQ{=5*59!F5_JDlmb2fm{1SNo!SeG|yx)VLD($_*`zx4X zOYr Date: Sat, 30 Mar 2013 14:12:21 +0100 Subject: [PATCH 028/548] +speech changes Signed-off-by: Nico Schottelius --- docs/speeches/2012-12-11_lisa.odp | Bin 24180 -> 23850 bytes docs/speeches/2013-03-25_ad_novum.odp | Bin 26866 -> 24181 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/speeches/2012-12-11_lisa.odp b/docs/speeches/2012-12-11_lisa.odp index 342edab47eaaf6b3b11b5748b007b6eb5a05675b..45c78955e931002333dd8bd150609909e1bfa2fa 100644 GIT binary patch delta 20727 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 z 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 diff --git a/docs/speeches/2013-03-25_ad_novum.odp b/docs/speeches/2013-03-25_ad_novum.odp index 868c1168b07995343f272ab4b4907557f4614e7b..305f0a5ea4d710c35e069ed39cb52ef3e2c9fdba 100644 GIT binary patch delta 15888 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

&l_gpCU>i9NCp2tZAtu%*be#*! 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 delta 18624 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 From d59953642edea42bd5070aacaed1d14c18434be2 Mon Sep 17 00:00:00 2001 From: Arkaitz Jimenez Date: Sat, 30 Mar 2013 22:15:39 +0100 Subject: [PATCH 029/548] crontab -l should be allowed to fail with "no crontab" without stopping exec --- cdist/conf/type/__cron/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index 37e0dc15..fac0170f 100755 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -38,7 +38,7 @@ if [ "$state_is" != "$state_should" ]; then present) cat << DONE tmp=\$($mktemp) -crontab -u $user -l > \$tmp +crontab -u $user -l > \$tmp || true cat >> \$tmp << EOC $(cat "$__object/parameter/entry") EOC From 60f85c5b852ff1651a72de786736dd0b89006bfb Mon Sep 17 00:00:00 2001 From: Arkaitz Jimenez Date: Sun, 31 Mar 2013 23:52:13 +0200 Subject: [PATCH 030/548] __user support for --create-home --- cdist/conf/type/__user/gencode-remote | 8 +++++++- cdist/conf/type/__user/parameter/boolean | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 cdist/conf/type/__user/parameter/boolean diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index baa6f354..52a8d198 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -39,6 +39,7 @@ shorten_property() { password) ret="-p";; shell) ret="-s";; uid) ret="-u";; + create-home) ret="-m";; esac echo "$ret" } @@ -76,6 +77,7 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then home) field=6 ;; shell) field=7 ;; uid) field=3 ;; + create-home) continue;; # Does not apply to user modification esac # If we haven't already set $current_value above, pull it from the @@ -102,7 +104,11 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then else for property in $(ls .); do new_value="$(cat "$property")" - set -- "$@" "$(shorten_property $property)" \'$new_value\' + if [ -z $new_value ];then # Boolean values have no value + set -- "$@" "$(shorten_property $property)" + else + set -- "$@" "$(shorten_property $property)" \'$new_value\' + fi done if [ "$os" = "freebsd" ]; then diff --git a/cdist/conf/type/__user/parameter/boolean b/cdist/conf/type/__user/parameter/boolean new file mode 100644 index 00000000..e0517c6a --- /dev/null +++ b/cdist/conf/type/__user/parameter/boolean @@ -0,0 +1 @@ +create-home From 4a89e6411597485bfef4baa7b0bccf272cc5203d Mon Sep 17 00:00:00 2001 From: Arkaitz Jimenez Date: Mon, 1 Apr 2013 00:47:57 +0200 Subject: [PATCH 031/548] Make global explorers available to initial manifest and fix hostname explorer --- cdist/conf/explorer/hostname | 4 ++-- cdist/core/manifest.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/conf/explorer/hostname b/cdist/conf/explorer/hostname index 2ae23759..881c910a 100755 --- a/cdist/conf/explorer/hostname +++ b/cdist/conf/explorer/hostname @@ -20,6 +20,6 @@ # # -if command -v hostname; then - hostname +if command -v hostname >/dev/null; then + hostname -f fi diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 19639618..8da7f96d 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -106,6 +106,7 @@ class Manifest(object): env.update(self.env) env['__cdist_manifest'] = initial_manifest env['__manifest'] = self.local.manifest_path + env['__explorer'] = self.local.global_explorer_out_path return env From d7f11332a9e50b97ad24f583655751e89e807b6c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Apr 2013 09:17:49 +0200 Subject: [PATCH 032/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e5badfac..17d5840e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ next: * Type __jail: State absent should implies stopped (Jake Guffey) * Explorer os: Added Slackware support (Eivind Uggedal) * Type __directory: Make stat call compatible with FreeBSD (Jake Guffey) + * Type __cron: Allow crontab without entries (Arkaitz Jimenez) 2.1.0: 2012-12-09 * Core: Ensure global explorers are executable From 352c7da46c78806dd4a22f7f543eba4713f5275e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 2 Apr 2013 09:21:01 +0200 Subject: [PATCH 033/548] quote the new value check - may contains spaces Signed-off-by: Nico Schottelius --- cdist/conf/type/__user/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index 52a8d198..a2cdfd22 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -104,7 +104,7 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then else for property in $(ls .); do new_value="$(cat "$property")" - if [ -z $new_value ];then # Boolean values have no value + if [ -z "$new_value" ];then # Boolean values have no value set -- "$@" "$(shorten_property $property)" else set -- "$@" "$(shorten_property $property)" \'$new_value\' From 0db80189d74c2bfcf4bc2a85a345b5ec4eabdafc Mon Sep 17 00:00:00 2001 From: Arkaitz Jimenez Date: Tue, 2 Apr 2013 10:15:03 +0000 Subject: [PATCH 034/548] Updated doc regarding global explorer availability --- docs/man/cdist-reference.text.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 225d647f..7ee2224a 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -179,7 +179,7 @@ ENVIRONMENT VARIABLES --------------------- __explorer:: Directory that contains all global explorers. - Available for: explorer, type explorer + Available for: initial manifest, explorer, type explorer __manifest:: Directory that contains the initial manifest. Available for: initial manifest, type manifest From d570e786ec42986d5feef160790a9097a8d6bc3f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 3 Apr 2013 16:34:04 +0200 Subject: [PATCH 035/548] ++changes next Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 17d5840e..bcb53be8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -11,6 +11,7 @@ next: * Explorer os: Added Slackware support (Eivind Uggedal) * Type __directory: Make stat call compatible with FreeBSD (Jake Guffey) * Type __cron: Allow crontab without entries (Arkaitz Jimenez) + * Type __user: Add support for creating user home (Arkaitz Jimenez) 2.1.0: 2012-12-09 * Core: Ensure global explorers are executable From 5152bdfce712b9e6620bc73b8dae4ca90cf2a0b6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 3 Apr 2013 16:49:03 +0200 Subject: [PATCH 036/548] add hint for 0700, root:root behaviour of __directory --parents Signed-off-by: Nico Schottelius --- cdist/conf/type/__directory/man.text | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__directory/man.text b/cdist/conf/type/__directory/man.text index 1f4def7d..cc327af2 100644 --- a/cdist/conf/type/__directory/man.text +++ b/cdist/conf/type/__directory/man.text @@ -36,7 +36,11 @@ owner:: BOOLEAN PARAMETERS ------------------ parents:: - Whether to create parents as well (mkdir -p behaviour) + 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:: If supplied the chgrp and chown call will run recursively. From dd3011f447d1bdb5b179742dcd4afc0be2cc418f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 3 Apr 2013 17:12:03 +0200 Subject: [PATCH 037/548] +discussion Signed-off-by: Nico Schottelius --- .../dev/logs/2013-04-03.dependency-discussion | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/dev/logs/2013-04-03.dependency-discussion diff --git a/docs/dev/logs/2013-04-03.dependency-discussion b/docs/dev/logs/2013-04-03.dependency-discussion new file mode 100644 index 00000000..29b5b5b5 --- /dev/null +++ b/docs/dev/logs/2013-04-03.dependency-discussion @@ -0,0 +1,30 @@ +Steven, Nico + +Discussion raised due to proposal from Arkaitz Jimenez + +-------------------------------------------------------------------------------- + +Proposal changes back to cdist behaviour as of 2011 (see commit 61b7b68). + +Change would introduce: + +- no direct stage based running +- stages only in object (not globally) +- cannot build full dependency list before beginning + - Thus wildcard requirements (require="__file/*") don't work anymore + +Accepting this or similar approaches means: + +- Drop wildcard requirements (is undocumented anyway) +- Type execution is closed (again) + +Furthermore/other points: + +- Change cdist to continue run as long as possible + - Don't stop if an object fails + - Record failure, print at the end (and exit non zero) + +- Logging + - Catch output of manifest, gencode, code, do not display directly + - Print at the end + - Prefix with hostname as usual! From 9dcad37acfc9769f39d22e1b672fc4d20e833751 Mon Sep 17 00:00:00 2001 From: Arkaitz Jimenez Date: Mon, 8 Apr 2013 17:35:45 +0000 Subject: [PATCH 038/548] Remove the umask requirement, set the proper permissions to base_path --- cdist/exec/remote.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index d4d2cb2b..4c029752 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -60,6 +60,7 @@ class Remote(object): def create_files_dirs(self): self.rmdir(self.base_path) self.mkdir(self.base_path) + self.run(["/bin/chmod", "700", self.base_path]) self.mkdir(self.conf_path) def rmdir(self, path): @@ -100,9 +101,6 @@ class Remote(object): cmd = self._exec.split() cmd.append(self.target_host) - # Always call umask before actual call to ensure proper file permissions - cmd.append("umask 077;") - # 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 af75aa9024956f4919284131bb75633a919b157c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 8 Apr 2013 19:57:28 +0200 Subject: [PATCH 039/548] use chmod to allow chmod being in a different path Signed-off-by: Nico Schottelius --- cdist/exec/remote.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 4c029752..bcb5fc4b 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -60,7 +60,7 @@ class Remote(object): def create_files_dirs(self): self.rmdir(self.base_path) self.mkdir(self.base_path) - self.run(["/bin/chmod", "700", self.base_path]) + self.run(["chmod", "0700", self.base_path]) self.mkdir(self.conf_path) def rmdir(self, path): From 6604c4c4ba4ea5fe9754af15bfe9c21bed918839 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 8 Apr 2013 20:00:43 +0200 Subject: [PATCH 040/548] more changes for 2.1.1 Signed-off-by: Nico Schottelius --- docs/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index bcb53be8..294db824 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,11 +4,12 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -next: +2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies + * Core: Remove umask call - protect /var/lib/cdist only (Arkaitz Jimenez) + * Explorer os: Added Slackware support (Eivind Uggedal) * Type __git: Support mode and fix owner/group settings (contradict) * Type __jail: State absent should implies stopped (Jake Guffey) - * Explorer os: Added Slackware support (Eivind Uggedal) * Type __directory: Make stat call compatible with FreeBSD (Jake Guffey) * Type __cron: Allow crontab without entries (Arkaitz Jimenez) * Type __user: Add support for creating user home (Arkaitz Jimenez) From 3e2dda81320fbb62724b3451f48ffe6ccb5fc62e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Apr 2013 15:12:02 +0200 Subject: [PATCH 041/548] changelog++ Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 294db824..4d9642d7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +next: + * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) + 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies * Core: Remove umask call - protect /var/lib/cdist only (Arkaitz Jimenez) From d975c8cc557934d2aa9ca427a553f26217d14570 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Apr 2013 15:12:11 +0200 Subject: [PATCH 042/548] +year Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index 1f408b94..fc605313 100755 --- a/build +++ b/build @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # From d42e25fca389e9dba443c4e0628c86bb050e7753 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Apr 2013 15:25:19 +0200 Subject: [PATCH 043/548] add discussion Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-04-10.discussion | 77 +++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 docs/dev/logs/2013-04-10.discussion diff --git a/docs/dev/logs/2013-04-10.discussion b/docs/dev/logs/2013-04-10.discussion new file mode 100644 index 00000000..648ed470 --- /dev/null +++ b/docs/dev/logs/2013-04-10.discussion @@ -0,0 +1,77 @@ +Steven, Nico (ETH office) + +- Try out patch for dependency resolver changing from [nico] + - Add tests + - Cleanup code: + - remove all old resolver parts (including tests!) + - remve wildcard matching pattern code + +- Cache: [nobody] + - Should cache be usable by types? + - Should all run outputs be stored? + - Different caches for install and config + +- Replace fsproperties with cconfig [steven] + +- Maybe support "rerun from previous version (cache)"? [nobody] + - need to include initial manifest(s!) + - copy/link types + - save remote-{exec,copy} parameters (copy or save argument list) + + - cdist replay / oldconfig ? + +- Support diffing two configurations [nobody] + - cdist diff ? + +- Nested Types [both] + - Motivation: + - Put everything related into one directory + - Have a look at it when Arkaitz pushes out pull request + - Implementations: + + 1) Arkaitz + + Folder structure Call Object + __package/ __package abc __package/abc + __package/type/pkg __package.pkg abc __package.pkg/abc + __package/type/pkg/type/green __package.pkg.green abc __package.pkg.green/abc + + ... + + __package.pkg __package.pkg abc __package.pkg/abc + + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + => Need to forbid types with "." in the name! + + 2) Steven (earlier version) + + Folder structure Call Object + __package/.type __package abc __package/abc + __package/pkg/.type __package.pkg abc __package.pkg/abc + __package/pkg/green/.type __package.pkg.green abc __package.pkg.green/abc + + - Clashes: + - if __. and __ and subtype exist both (in both implementations) + +- Install [nobody] + - Merge into master? + - Needs some cleanups + +- PreOS [nobody] + - cdist preos / preos-generate + --output= + --arch=[i386|amd64|arm??] + --type=[usb, cdrom/iso, floppy, pxe] + --other-params (?) + + - Maybe implement using cdist config indirectly and a type __preos + + - Can be: + - Internally only (devs) + - Usable by end users + + - Requirements: + - git + - buildchain + - toolchain for target arch + - ... From d8630dc6d406cc2e933e755ded0771e7e97eaeea Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 29 Apr 2013 17:55:03 +0200 Subject: [PATCH 044/548] +reasons Signed-off-by: Nico Schottelius --- docs/web/cdist/why.mdwn | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/web/cdist/why.mdwn b/docs/web/cdist/why.mdwn index 6dcfd441..f571555c 100644 --- a/docs/web/cdist/why.mdwn +++ b/docs/web/cdist/why.mdwn @@ -42,7 +42,8 @@ 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**). +(**/bin/sh**). Compared to other configuration management systems, +it does not require to open up an additional port. ## Push based distribution From a064cc19b3c65c7011e732930c5df25612996ec2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Apr 2013 10:58:23 +0200 Subject: [PATCH 045/548] try new object orientated (hrrr) code instead of stage based Signed-off-by: Nico Schottelius --- cdist/config_install.py | 68 ++++++++++++++++++++++-- cdist/core/cdist_object.py | 18 +++++++ docs/dev/logs/2013-04-12.execution-order | 39 ++++++++++++++ 3 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 docs/dev/logs/2013-04-12.execution-order diff --git a/cdist/config_install.py b/cdist/config_install.py index 7c7a876d..841a19df 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -65,8 +65,13 @@ class ConfigInstall(object): def deploy_to(self): """Mimic the old deploy to: Deploy to one host""" - self.stage_prepare() - self.stage_run() + + # Old Code + # self.stage_prepare() + # self.stage_run() + + # New Code + self.run() def deploy_and_cleanup(self): """Do what is most often done: deploy & cleanup""" @@ -76,6 +81,62 @@ class ConfigInstall(object): self.log.info("Finished successful run in %s seconds", time.time() - start_time) + ###################################################################### + # New code for running on object priority (not stage priority) + # + + def run(self): + """The main runner""" + self.explorer.run_global_explorers(self.context.local.global_explorer_out_path) + self.manifest.run_initial_manifest(self.context.initial_manifest) + self.iterate_until_finished() + + def object_list(self): + """Short name for object list retrieval""" + for cdist_object in core.CdistObject.list_objects(self.context.local.object_path, + self.context.local.type_path): + yield cdist_object + + def iterate_until_finished(self): + # Continue process until no new objects are created anymore + + objects_changed = True + + while objects_changed: + objects_changed = False + + for cdist_object in self.object_list(): + if not cdist_object.requirements_satisfied(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 not cdist_object.requirements_satisfied(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) + + # Check whether all objects have been finished + unfinished_object_names = [] + for cdist_object in self.object_list(): + if not cdist_object.state == cdist_object.STATE_DONE: + unfinished_object_names.append(cdist_object.name) + + if unfinished_object_names: + raise cdist.Error("The following objects could not be resolved: %s" % + (" ".join(unfinished_object_names)) + + ###################################################################### + # Stages based code + # + def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" self.explorer.run_global_explorers(self.context.local.global_explorer_out_path) @@ -89,6 +150,7 @@ class ConfigInstall(object): new_objects_created = False for cdist_object in core.CdistObject.list_objects(self.context.local.object_path, self.context.local.type_path): + if cdist_object.state == core.CdistObject.STATE_PREPARED: self.log.debug("Skipping re-prepare of object %s", cdist_object) continue diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 73537f80..30d002f6 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -61,6 +61,7 @@ class CdistObject(object): """ # Constants for use with Object.state + STATE_UNDEF = "" STATE_PREPARED = "prepared" STATE_RUNNING = "running" STATE_DONE = "done" @@ -223,6 +224,23 @@ class CdistObject(object): except EnvironmentError as error: raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) + @property + def requirements_satisfied(self): + """Return state whether normal depedencies are satisfied""" + + satisfied = True + + for requirement in self.requirements: + cdist_object = self.object_from_name(requirement) + + if not cdist_object.state == self.STATE_DONE: + satisfied = False + break + + log.debug("%s is satisfied: %s" % (self.name, satisfied)) + + return satisfied + @property def satisfied_requirements(self): """Return state whether all of our dependencies have been resolved already""" diff --git a/docs/dev/logs/2013-04-12.execution-order b/docs/dev/logs/2013-04-12.execution-order new file mode 100644 index 00000000..1739c287 --- /dev/null +++ b/docs/dev/logs/2013-04-12.execution-order @@ -0,0 +1,39 @@ +Old: + +- global explores (all) +- initial manifest +- for each object + execute type explorers + execute manifest + + continue until all objects (including newly created) + have their type explorers/manifests run +- build dependency tree +- for each object + execute gencode-* + execute code-* + +New: +- run all global explorers +- run initial manifest + creates zero or more cdist_objects +- for each cdist_object + if not cdist_object.has_unfullfilled_requirements: + execute type explorers + execute manifest + may create new objects, resulting in autorequirements + + # Gained requirements during manifest run + if object.has_auto_requirements(): + continue + + cdist_object.execute gencode-* + cdist_object.execute code-* + + +Requirements / Test cases for requirments / resolver: + + - omnipotence + - + +Test From 8a7c64f86afba67dace9c56f0bdd2526496ba29f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Apr 2013 11:04:01 +0200 Subject: [PATCH 046/548] cleanups + indent errors Signed-off-by: Nico Schottelius --- cdist/config_install.py | 4 ++-- cdist/core/cdist_object.py | 48 ++------------------------------------ 2 files changed, 4 insertions(+), 48 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 841a19df..b458ad56 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -127,11 +127,11 @@ class ConfigInstall(object): unfinished_object_names = [] for cdist_object in self.object_list(): if not cdist_object.state == cdist_object.STATE_DONE: - unfinished_object_names.append(cdist_object.name) + unfinished_object_names.append(cdist_object.name) if unfinished_object_names: raise cdist.Error("The following objects could not be resolved: %s" % - (" ".join(unfinished_object_names)) + (" ".join(unfinished_object_names))) ###################################################################### # Stages based code diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 30d002f6..566cde21 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -224,13 +224,12 @@ class CdistObject(object): except EnvironmentError as error: raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) - @property - def requirements_satisfied(self): + def requirements_satisfied(self, requirements): """Return state whether normal depedencies are satisfied""" satisfied = True - for requirement in self.requirements: + for requirement in requirements: cdist_object = self.object_from_name(requirement) if not cdist_object.state == self.STATE_DONE: @@ -241,49 +240,6 @@ class CdistObject(object): return satisfied - @property - def satisfied_requirements(self): - """Return state whether all of our dependencies have been resolved already""" - - satisfied = True - - for requirement in self.all_requirements: - log.debug("%s: Checking requirement %s (%s) .." % (self.name, requirement.name, requirement.state)) - if not requirement.state == self.STATE_DONE: - satisfied = False - break - log.debug("%s is satisfied: %s" % (self.name, satisfied)) - - return satisfied - - - def find_requirements_by_name(self, requirements): - """Takes a list of requirement patterns and returns a list of matching object instances. - - Patterns are expected to be Unix shell-style wildcards for use with fnmatch.filter. - - find_requirements_by_name(['__type/object_id', '__other_type/*']) -> - [, , ] - """ - - - # FIXME: think about where/when to store this - probably not here - self.objects = dict((o.name, o) for o in self.list_objects(self.base_path, self.cdist_type.base_path)) - object_names = self.objects.keys() - - for pattern in requirements: - found = False - for requirement in fnmatch.filter(object_names, pattern): - found = True - yield self.objects[requirement] - if not found: - # FIXME: get rid of the singleton object_id, it should be invisible to the code -> hide it in Object - singleton = os.path.join(pattern, 'singleton') - if singleton in self.objects: - yield self.objects[singleton] - else: - raise RequirementNotFoundError(pattern) - @property def all_requirements(self): """ From 85d24ce2595b972fe5c236ffab1528e19b89b362 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Apr 2013 15:07:27 +0200 Subject: [PATCH 047/548] fix execution order - seems to be fine now Signed-off-by: Nico Schottelius --- cdist/config_install.py | 30 +++++++++++++++++++----- cdist/core/cdist_object.py | 25 ++++---------------- docs/dev/logs/2013-04-12.execution-order | 7 +++++- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index b458ad56..f33efdf9 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -106,7 +106,7 @@ class ConfigInstall(object): objects_changed = False for cdist_object in self.object_list(): - if not cdist_object.requirements_satisfied(cdist_object.requirements): + if cdist_object.requirements_unfinished(cdist_object.requirements): """We cannot do anything for this poor object""" continue @@ -116,22 +116,40 @@ class ConfigInstall(object): self.object_prepare(cdist_object) objects_changed = True - if not cdist_object.requirements_satisfied(cdist_object.autorequire): + 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 # Check whether all objects have been finished - unfinished_object_names = [] + unfinished_objects = [] for cdist_object in self.object_list(): if not cdist_object.state == cdist_object.STATE_DONE: - unfinished_object_names.append(cdist_object.name) + unfinished_objects.append(cdist_object) + + if unfinished_objects: + info_string = [] + + for cdist_object in unfinished_objects: + + requirement_names = [] + autorequire_names = [] + + 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): + autorequire_names.append(requirement.name) + + requirements = ", ".join(requirement_names) + autorequire = ", ".join(autorequire_names) + info_string.append("%s requires: %s autorequires: %s" % (cdist_object.name, requirements, autorequire)) - if unfinished_object_names: raise cdist.Error("The following objects could not be resolved: %s" % - (" ".join(unfinished_object_names))) + ("; ".join(info_string))) ###################################################################### # Stages based code diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 566cde21..a9306aaa 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -224,35 +224,18 @@ class CdistObject(object): except EnvironmentError as error: raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) - def requirements_satisfied(self, requirements): + def requirements_unfinished(self, requirements): """Return state whether normal depedencies are satisfied""" - satisfied = True + object_list = [] for requirement in requirements: cdist_object = self.object_from_name(requirement) if not cdist_object.state == self.STATE_DONE: - satisfied = False - break - - log.debug("%s is satisfied: %s" % (self.name, satisfied)) - - return satisfied - - @property - def all_requirements(self): - """ - Return resolved autorequirements and requirements so that - a complete list of requirements is returned - """ - - all_reqs= [] - all_reqs.extend(self.find_requirements_by_name(self.requirements)) - all_reqs.extend(self.find_requirements_by_name(self.autorequire)) - - return set(all_reqs) + object_list.append(cdist_object) + return object_list class RequirementNotFoundError(cdist.Error): def __init__(self, requirement): diff --git a/docs/dev/logs/2013-04-12.execution-order b/docs/dev/logs/2013-04-12.execution-order index 1739c287..5100eeda 100644 --- a/docs/dev/logs/2013-04-12.execution-order +++ b/docs/dev/logs/2013-04-12.execution-order @@ -36,4 +36,9 @@ Requirements / Test cases for requirments / resolver: - omnipotence - -Test + +-------------------------------------------------------------------------------- +ERROR: localhost: The following objects could not be resolved: __cdistmarker/singleton requires autorequires ; __directory/etc/sudoers.d requires autorequires ; __file/etc/sudoers.d/nico requires __directory/etc/sudoers.d autorequires ; __file/etc/motd requires autorequires ; __package_pacman/atop requires autorequires ; __package_pacman/screen requires autorequires ; __package_pacman/strace requires autorequires ; __package_pacman/vim requires autorequires ; __package_pacman/zsh requires autorequires ; __package_pacman/lftp requires autorequires ; __package_pacman/nmap requires autorequires ; __package_pacman/ntp requires autorequires ; __package_pacman/rsync requires autorequires ; __package_pacman/rtorrent requires autorequires ; __package_pacman/wget requires autorequires ; __package_pacman/nload requires autorequires ; __package_pacman/iftop requires autorequires ; __package_pacman/mosh requires autorequires ; __package_pacman/git requires autorequires ; __package_pacman/mercurial requires autorequires ; __package_pacman/netcat requires autorequires ; __package_pacman/python-virtualenv requires autorequires ; __package_pacman/wireshark-cli requires autorequires ; __package_pacman/sudo requires autorequires +INFO: Total processing time for 1 host(s): 32.30426597595215 +ERROR: Failed to deploy to the following hosts: localhost + From 2dac681f2561d26e32864752d1400273f53cc00d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Apr 2013 15:07:59 +0200 Subject: [PATCH 048/548] better error message Signed-off-by: Nico Schottelius --- cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index f33efdf9..7e8eb0f1 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -148,7 +148,7 @@ class ConfigInstall(object): autorequire = ", ".join(autorequire_names) info_string.append("%s requires: %s autorequires: %s" % (cdist_object.name, requirements, autorequire)) - raise cdist.Error("The following objects could not be resolved: %s" % + raise cdist.Error("The requirements of the following objects could not be resolved: %s" % ("; ".join(info_string))) ###################################################################### From 956f400da6fca8d904c96f6958c3ea3a5beab9d9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Apr 2013 15:15:22 +0200 Subject: [PATCH 049/548] re-arrange for future cleanup Signed-off-by: Nico Schottelius --- cdist/config_install.py | 77 ++++++++++-------- cdist/resolver.py | 175 ---------------------------------------- 2 files changed, 42 insertions(+), 210 deletions(-) delete mode 100644 cdist/resolver.py diff --git a/cdist/config_install.py b/cdist/config_install.py index 7e8eb0f1..b62af3e0 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -63,20 +63,16 @@ class ConfigInstall(object): shutil.rmtree(destination) shutil.move(self.context.local.out_path, destination) - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" + def deploy_and_cleanup(self): + """Do what is most often done: deploy & cleanup""" + start_time = time.time() # Old Code - # self.stage_prepare() - # self.stage_run() + #self.deploy_to() # New Code self.run() - def deploy_and_cleanup(self): - """Do what is most often done: deploy & cleanup""" - start_time = time.time() - self.deploy_to() self.cleanup() self.log.info("Finished successful run in %s seconds", time.time() - start_time) @@ -151,10 +147,48 @@ class ConfigInstall(object): raise cdist.Error("The requirements of the following objects could not be resolved: %s" % ("; ".join(info_string))) + ###################################################################### + # Code required by both methods (which will stay) + # + + def object_run(self, cdist_object, dry_run=False): + """Run gencode and code for an object""" + self.log.debug("Trying to run 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) + + cdist_type = cdist_object.cdist_type + + # Generate + self.log.info("Generating and executing code for " + 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 not dry_run: + if cdist_object.code_local: + self.code.run_code_local(cdist_object) + if cdist_object.code_remote: + self.code.transfer_code_remote(cdist_object) + self.code.run_code_remote(cdist_object) + + # Mark this object as done + self.log.debug("Finishing run of " + cdist_object.name) + cdist_object.state = core.CdistObject.STATE_DONE + + ###################################################################### # Stages based code # + def deploy_to(self): + """Mimic the old deploy to: Deploy to one host""" + self.stage_prepare() + self.stage_run() + + def stage_prepare(self): """Do everything for a deploy, minus the actual code stage""" self.explorer.run_global_explorers(self.context.local.global_explorer_out_path) @@ -183,33 +217,6 @@ class ConfigInstall(object): self.manifest.run_type_manifest(cdist_object) cdist_object.state = core.CdistObject.STATE_PREPARED - def object_run(self, cdist_object, dry_run=False): - """Run gencode and code for an object""" - self.log.debug("Trying to run 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) - - cdist_type = cdist_object.cdist_type - - # Generate - self.log.info("Generating and executing code for " + 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 not dry_run: - if cdist_object.code_local: - self.code.run_code_local(cdist_object) - if cdist_object.code_remote: - self.code.transfer_code_remote(cdist_object) - self.code.run_code_remote(cdist_object) - - # Mark this object as done - self.log.debug("Finishing run of " + cdist_object.name) - cdist_object.state = core.CdistObject.STATE_DONE - def stage_run(self): """The final (and real) step of deployment""" self.log.info("Generating and executing code") diff --git a/cdist/resolver.py b/cdist/resolver.py deleted file mode 100644 index ddcf382e..00000000 --- a/cdist/resolver.py +++ /dev/null @@ -1,175 +0,0 @@ -# -*- coding: utf-8 -*- -# -# 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 . -# -# - -import logging -import os -import itertools -import fnmatch -import pprint - -import cdist - -log = logging.getLogger(__name__) - - -class CircularReferenceError(cdist.Error): - def __init__(self, cdist_object, required_object): - self.cdist_object = cdist_object - self.required_object = required_object - - def __str__(self): - return 'Circular reference detected: %s -> %s' % (self.cdist_object.name, self.required_object.name) - - -class RequirementNotFoundError(cdist.Error): - def __init__(self, requirement): - self.requirement = requirement - - def __str__(self): - return 'Requirement could not be found: %s' % self.requirement - - -class DependencyResolver(object): - """Cdist's dependency resolver. - - Usage: - >> resolver = DependencyResolver(list_of_objects) - # Easy access to the objects we are working with - >> resolver.objects['__some_type/object_id'] - - # Easy access to a specific objects dependencies - >> resolver.dependencies['__some_type/object_id'] - [, ] - # Pretty print the dependency graph - >> from pprint import pprint - >> pprint(resolver.dependencies) - # Iterate over all existing objects in the correct order - >> for cdist_object in resolver: - >> do_something_with(cdist_object) - """ - def __init__(self, objects, logger=None): - self.objects = dict((o.name, o) for o in objects) - self._dependencies = None - self.log = logger or log - - @property - def dependencies(self): - """Build the dependency graph. - - Returns a dict where the keys are the object names and the values are - lists of all dependencies including the key object itself. - """ - if self._dependencies is None: - self.log.info("Resolving dependencies...") - self._dependencies = {} - self._preprocess_requirements() - for name,cdist_object in self.objects.items(): - resolved = [] - unresolved = [] - self._resolve_object_dependencies(cdist_object, resolved, unresolved) - self._dependencies[name] = resolved - self.log.debug(self._dependencies) - return self._dependencies - - def find_requirements_by_name(self, requirements): - """Takes a list of requirement patterns and returns a list of matching object instances. - - Patterns are expected to be Unix shell-style wildcards for use with fnmatch.filter. - - find_requirements_by_name(['__type/object_id', '__other_type/*']) -> - [, , ] - """ - object_names = self.objects.keys() - for pattern in requirements: - found = False - for requirement in fnmatch.filter(object_names, pattern): - found = True - yield self.objects[requirement] - if not found: - # FIXME: get rid of the singleton object_id, it should be invisible to the code -> hide it in Object - singleton = os.path.join(pattern, 'singleton') - if singleton in self.objects: - yield self.objects[singleton] - else: - raise RequirementNotFoundError(pattern) - - def _preprocess_requirements(self): - """Find all autorequire dependencies and merge them to be just requirements - for further processing. - """ - for cdist_object in self.objects.values(): - if cdist_object.autorequire: - # The objects (children) that this cdist_object (parent) defined - # in it's type manifest shall inherit all explicit requirements - # that the parent has so that user defined requirements are - # fullfilled and processed in the expected order. - for auto_requirement in self.find_requirements_by_name(cdist_object.autorequire): - for requirement in self.find_requirements_by_name(cdist_object.requirements): - requirement_object_all_requirements = list(requirement.requirements) + list(requirement.autorequire) - if (requirement.name not in auto_requirement.requirements - and auto_requirement.name not in requirement_object_all_requirements): - self.log.debug('Adding %s to %s.requirements', requirement.name, auto_requirement) - auto_requirement.requirements.append(requirement.name) - # On the other hand the parent shall depend on all the children - # it created so that the user can setup dependencies on it as a - # whole without having to know anything about the parents - # internals. - cdist_object.requirements.extend(cdist_object.autorequire) - # As we changed the object on disc, we have to ensure it is not - # preprocessed again if someone would call us multiple times. - cdist_object.autorequire = [] - - def _resolve_object_dependencies(self, cdist_object, resolved, unresolved): - """Resolve all dependencies for the given cdist_object and store them - in the list which is passed as the 'resolved' arguments. - - e.g. - resolved = [] - unresolved = [] - resolve_object_dependencies(some_object, resolved, unresolved) - print("Dependencies for %s: %s" % (some_object, resolved)) - """ - self.log.debug('Resolving dependencies for: %s' % cdist_object.name) - try: - unresolved.append(cdist_object) - for required_object in self.find_requirements_by_name(cdist_object.requirements): - self.log.debug("Object %s requires %s", cdist_object, required_object) - if required_object not in resolved: - if required_object in unresolved: - error = CircularReferenceError(cdist_object, required_object) - self.log.error('%s: %s', error, pprint.pformat(self._dependencies)) - raise error - self._resolve_object_dependencies(required_object, resolved, unresolved) - resolved.append(cdist_object) - unresolved.remove(cdist_object) - except RequirementNotFoundError as e: - raise cdist.CdistObjectError(cdist_object, "requires non-existing " + e.requirement) - - def __iter__(self): - """Iterate over all unique objects and yield them in the correct order. - """ - iterable = itertools.chain(*self.dependencies.values()) - # Keep record of objects that have already been seen - seen = set() - seen_add = seen.add - for cdist_object in itertools.filterfalse(seen.__contains__, iterable): - seen_add(cdist_object) - yield cdist_object From 4882c2cf190258c98f46578701b603ad306c2b4f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Apr 2013 15:16:38 +0200 Subject: [PATCH 050/548] --resolver in config_install Signed-off-by: Nico Schottelius --- cdist/config_install.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index b62af3e0..ceba1887 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -32,8 +32,6 @@ import pprint import cdist from cdist import core -from cdist import resolver - class ConfigInstall(object): """Cdist main class to hold arbitrary data""" From f95052e56f5dc453077af716c5fd9aa992c55b5f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 30 Apr 2013 15:18:03 +0200 Subject: [PATCH 051/548] remove unused modules Signed-off-by: Nico Schottelius --- cdist/config_install.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index ceba1887..4bf9ad32 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -22,12 +22,8 @@ import logging import os -import stat import shutil -import sys -import tempfile import time -import itertools import pprint import cdist From a265d870373ed7fbb91a7ec87eca02978464623d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 2 May 2013 16:41:16 +0200 Subject: [PATCH 052/548] begin dry run in command line Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 1 - scripts/cdist | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index a9306aaa..5d3efbdd 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -50,7 +50,6 @@ class MissingObjectIdError(cdist.Error): def __str__(self): return '%s' % (self.message) - class CdistObject(object): """Represents a cdist object. diff --git a/scripts/cdist b/scripts/cdist index fd18933a..00c55ae8 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -62,6 +62,8 @@ def commandline(): parser['configinstall'].add_argument('-i', '--initial-manifest', help='Path to a cdist manifest or \'-\' to read from stdin.', dest='manifest', required=False) + parser['configinstall'].add_argument('-n', '--dry-run', + help='Do not execute code', action='store_true') parser['configinstall'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', action='store_true', dest='parallel') From e49ccedefff31e86c49d721b30c0f40e7bc4af85 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 4 May 2013 01:31:44 +0200 Subject: [PATCH 053/548] callback ideas Signed-off-by: Nico Schottelius --- callback.py | 26 ++++++++++++++++++++++++++ docs/dev/logs/2013-05-04.ssh | 5 +++++ 2 files changed, 31 insertions(+) create mode 100644 callback.py create mode 100644 docs/dev/logs/2013-05-04.ssh diff --git a/callback.py b/callback.py new file mode 100644 index 00000000..b9103837 --- /dev/null +++ b/callback.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# 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 + +# SSH_CLIENT and SSH_CONNECTION available +src_ip = os.environ['SSH_CLIENT'].split()[0] diff --git a/docs/dev/logs/2013-05-04.ssh b/docs/dev/logs/2013-05-04.ssh new file mode 100644 index 00000000..b00aa44b --- /dev/null +++ b/docs/dev/logs/2013-05-04.ssh @@ -0,0 +1,5 @@ +- analysis of ssh connections for callback + SSH_CLIENT='::1 38502 22' + SSH_CONNECTION='::1 38502 ::1 22' + + -> callback possible to source host From 4ff34a7aa86ab707ee5c5643ed890547f1c436ba Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 May 2013 14:09:56 +0200 Subject: [PATCH 054/548] +ideas +callback.py Signed-off-by: Nico Schottelius --- callback.py | 2 ++ docs/dev/logs/2013-05-04.ssh | 56 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/callback.py b/callback.py index b9103837..1bf5545a 100644 --- a/callback.py +++ b/callback.py @@ -24,3 +24,5 @@ import os # SSH_CLIENT and SSH_CONNECTION available src_ip = os.environ['SSH_CLIENT'].split()[0] + +print("Plain version: Connecting back to %s" % src_ip) diff --git a/docs/dev/logs/2013-05-04.ssh b/docs/dev/logs/2013-05-04.ssh index b00aa44b..9985ff05 100644 --- a/docs/dev/logs/2013-05-04.ssh +++ b/docs/dev/logs/2013-05-04.ssh @@ -3,3 +3,59 @@ SSH_CONNECTION='::1 38502 ::1 22' -> callback possible to source host + + + +[ target host ] <--------------| + | | + | | + | | + | trigger | configuration + | | + v | +[ configuration host ] ----| + + +- dynamic port allocation for tunneling + + [1:37] bento:~% ssh -R 0:localhost:22 localhost + Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts. + Allocated port 53161 for remote forward to localhost:22 + + SSH_AUTH_SOCK=/tmp/ssh-zDCWbUVcUK/agent.30749 + SSH_CLIENT='::1 38587 22' + SSH_CONNECTION='::1 38587 ::1 22' + SSH_TTY=/dev/pts/21 + + +- ssh_config: + DynamicForward + LocalForward + RemoteForward + +- testing + +[1:52] bento:cdist% netstat -anp | grep 56844 +(Not all processes could be identified, non-owned process info + will not be shown, you would have to be root to see it all.) +tcp 0 0 127.0.0.1:56844 0.0.0.0:* LISTEN - +tcp6 0 0 ::1:56844 :::* LISTEN - +[1:53] bento:cdist% + + +[1:48] bento:~% ssh -R 0:localhost:22 localhost +Allocated port 56844 for remote forward to localhost:22 +... + +- chatting + +01:42 -!- Irssi: Join to #openssh was synced in 0 secs +01:42 < telmich> good evening +01:43 < telmich> I am trying to make use of remote port forwarding using dynamic port + allocation (port=0) -- I am wondering if there is an easy way to + access the port number on the remote side easily? +01:44 < telmich> background for this question is: I'd like to allow various clients to + login to a configuration server, which then configures the clients by + using the tunnel the client provides for the server to ssh back into +02:07 < BasketCase> telmich: afaik you need to use a tool like ss/netstat/lsof to see what port it has open + From 119ea2f8fef3f601cdf09a20d64979fce5855cc3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 May 2013 15:13:42 +0200 Subject: [PATCH 055/548] add makefile for convenience Signed-off-by: Nico Schottelius --- Makefile | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..948bdcd9 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +%: + ./build $@ From d72afd390377890fa1a1ec10c212275c162838cb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 10 May 2013 12:35:22 +0200 Subject: [PATCH 056/548] dont change parameters; dont use tmpfile; update copyright Signed-off-by: Steven Armstrong --- cdist/conf/type/__cron/explorer/entry | 2 +- cdist/conf/type/__cron/gencode-remote | 25 ++++++++----------------- cdist/conf/type/__cron/man.text | 2 +- cdist/conf/type/__cron/manifest | 16 ++++++++-------- 4 files changed, 18 insertions(+), 27 deletions(-) diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry index 1b4bec42..9b52d6e4 100755 --- a/cdist/conf/type/__cron/explorer/entry +++ b/cdist/conf/type/__cron/explorer/entry @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index fac0170f..af06edb3 100755 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -18,38 +18,29 @@ # along with cdist. If not, see . # -os="$(cat "$__global/explorer/os")" user="$(cat "$__object/parameter/user")" -state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" state_is=$(diff -q "$__object/parameter/entry" "$__object/explorer/entry" \ && echo present \ || echo absent ) -# FreeBSD mktemp doesn't allow execution without at least one param -if [ "$os" = "freebsd" ]; then - mktemp="mktemp -t tmp" -else - mktemp="mktemp" -fi - if [ "$state_is" != "$state_should" ]; then case "$state_should" in present) cat << DONE -tmp=\$($mktemp) -crontab -u $user -l > \$tmp || true -cat >> \$tmp << EOC +( +crontab -u $user -l || true +cat << EOC $(cat "$__object/parameter/entry") EOC -crontab -u $user \$tmp -rm \$tmp +) | crontab -u $user - DONE ;; absent) - # defined in type manifest - prefix="$(cat "$__object/parameter/prefix")" - suffix="$(cat "$__object/parameter/suffix")" + # NOTE: keep variables in sync in manifest/explorer/gencode-* + prefix="#cdist:__cron/$name" + suffix="#/cdist:__cron/$name" cat << DONE crontab -u $user -l | awk -v prefix="$prefix" -v suffix="$suffix" ' { diff --git a/cdist/conf/type/__cron/man.text b/cdist/conf/type/__cron/man.text index 47f47456..22627234 100644 --- a/cdist/conf/type/__cron/man.text +++ b/cdist/conf/type/__cron/man.text @@ -68,5 +68,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is +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/__cron/manifest b/cdist/conf/type/__cron/manifest index 7aca41ff..71910bf5 100755 --- a/cdist/conf/type/__cron/manifest +++ b/cdist/conf/type/__cron/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -21,9 +21,7 @@ name="$__object_id" user="$(cat "$__object/parameter/user")" command="$(cat "$__object/parameter/command")" - -# set defaults -test -f "$__object/parameter/state" || echo "present" > "$__object/parameter/state" +state="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" if [ -f "$__object/parameter/raw" ]; then raw="$(cat "$__object/parameter/raw")" @@ -37,9 +35,11 @@ else entry="$minute $hour $day_of_month $month $day_of_week $command" fi -# NOTE: if changed, also change in explorers +# NOTE: keep variables in sync in manifest/explorer/gencode-* prefix="#cdist:__cron/$name" suffix="#/cdist:__cron/$name" -echo "$prefix" | tee "$__object/parameter/prefix" > "$__object/parameter/entry" -echo "$entry" >> "$__object/parameter/entry" -echo "$suffix" | tee "$__object/parameter/suffix" >> "$__object/parameter/entry" +cat >> "$__object/parameter/entry" << DONE +"$prefix" +"$entry" +"$suffix" +DONE From d4bad031e9fbfc5030662c499a13be862777512d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 10 May 2013 12:41:56 +0200 Subject: [PATCH 057/548] bugfix: the parameter is named 'state' not 'present' 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 268b1fbe..47cdf746 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -19,7 +19,7 @@ # owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" -state="$(cat "$__object/parameter/present" 2>/dev/null || echo "present")" +state="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" if [ -f "$__object/parameter/file" ]; then file="$(cat "$__object/parameter/file")" else From a09ee9a8145280b381f3c9fdca798a3bf76cff6a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 May 2013 13:02:45 +0200 Subject: [PATCH 058/548] +debug info Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-05-04.ssh | 279 +++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) diff --git a/docs/dev/logs/2013-05-04.ssh b/docs/dev/logs/2013-05-04.ssh index 9985ff05..176e5b62 100644 --- a/docs/dev/logs/2013-05-04.ssh +++ b/docs/dev/logs/2013-05-04.ssh @@ -59,3 +59,282 @@ Allocated port 56844 for remote forward to localhost:22 using the tunnel the client provides for the server to ssh back into 02:07 < BasketCase> telmich: afaik you need to use a tool like ss/netstat/lsof to see what port it has open +- ssh debug + +[11:37] bento:~% ssh -R 0:localhost:22 localhost +Allocated port 33562 for remote forward to localhost:22 + + .. . .x+=:. s + dF @88> z` ^% :8 + '88bu. %8P . server aes128-ctr hmac-md5-etm@openssh.com zlib@openssh.com [preauth] +debug1: kex: server->client aes128-ctr hmac-md5-etm@openssh.com zlib@openssh.com [preauth] +debug1: expecting SSH2_MSG_KEX_ECDH_INIT [preauth] +debug1: SSH2_MSG_NEWKEYS sent [preauth] +debug1: expecting SSH2_MSG_NEWKEYS [preauth] +debug1: SSH2_MSG_NEWKEYS received [preauth] +debug1: KEX done [preauth] +debug1: userauth-request for user root service ssh-connection method none [preauth] +debug1: attempt 0 failures 0 [preauth] +debug1: PAM: initializing for "root" +debug1: PAM: setting PAM_RHOST to "localhost.localdomain" +debug1: PAM: setting PAM_TTY to "ssh" +debug1: userauth-request for user root service ssh-connection method publickey [preauth] +debug1: attempt 1 failures 0 [preauth] +debug1: test whether pkalg/pkblob are acceptable [preauth] +debug1: temporarily_use_uid: 0/0 (e=0/0) +debug1: trying public key file /root/.ssh/authorized_keys +debug1: fd 4 clearing O_NONBLOCK +debug1: matching key found: file /root/.ssh/authorized_keys, line 2 +Found matching RSA key: 2e:1b:3f:10:01:1d:21:6c:6c:1e:3d:a9:33:ba:3c:f7 +debug1: restore_uid: 0/0 +Postponed publickey for root from ::1 port 57848 ssh2 [preauth] +debug1: userauth-request for user root service ssh-connection method publickey [preauth] +debug1: attempt 2 failures 0 [preauth] +debug1: temporarily_use_uid: 0/0 (e=0/0) +debug1: trying public key file /root/.ssh/authorized_keys +debug1: fd 4 clearing O_NONBLOCK +debug1: matching key found: file /root/.ssh/authorized_keys, line 2 +Found matching RSA key: 2e:1b:3f:10:01:1d:21:6c:6c:1e:3d:a9:33:ba:3c:f7 +debug1: restore_uid: 0/0 +debug1: ssh_rsa_verify: signature correct +debug1: do_pam_account: called +Accepted publickey for root from ::1 port 57848 ssh2 +debug1: monitor_child_preauth: root has been authenticated by privileged process +debug1: Enabling compression at level 6. [preauth] +debug1: monitor_read_log: child log fd closed +debug1: PAM: establishing credentials +debug1: Entering interactive session for SSH2. +debug1: server_init_dispatch_20 +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 0 +debug1: Local forwarding listening on ::1 port 0. +debug1: Allocated listen port 33562 +debug1: channel 0: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 33562. +debug1: channel 1: new [port listener] +debug1: server_input_channel_open: ctype session rchan 0 win 1048576 max 16384 +debug1: input_session_request +debug1: channel 2: new [server-session] +debug1: session_new: session 0 +debug1: session_open: channel 2 +debug1: session_open: session 0: link with channel 2 +debug1: server_input_channel_open: confirm session +debug1: server_input_global_request: rtype no-more-sessions@openssh.com want_reply 0 +debug1: server_input_channel_req: channel 2 request auth-agent-req@openssh.com reply 0 +debug1: session_by_channel: session 0 channel 2 +debug1: session_input_channel_req: session 0 req auth-agent-req@openssh.com +debug1: temporarily_use_uid: 0/0 (e=0/0) +debug1: restore_uid: 0/0 +debug1: channel 3: new [auth socket] +debug1: server_input_channel_req: channel 2 request pty-req reply 1 +debug1: session_by_channel: session 0 channel 2 +debug1: session_input_channel_req: session 0 req pty-req +debug1: Allocating pty. +debug1: session_pty_req: session 0 alloc /dev/pts/32 +debug1: server_input_channel_req: channel 2 request shell reply 1 +debug1: session_by_channel: session 0 channel 2 +debug1: session_input_channel_req: session 0 req shell +debug1: Setting controlling tty using TIOCSCTTY. + +-------------------------------------------------------------------------------- +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 0 +debug1: Local forwarding listening on ::1 port 0. +debug1: Allocated listen port 33562 +debug1: channel 0: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 33562. + +[11:49] bento:openssh-6.2p1% grep "Allocated listen port" -r . +./channels.c: debug("Allocated listen port %d", +[11:49] bento:openssh-6.2p1% + + +-------------------------------------------------------------------------------- +[11:54] bento:~% ssh -R 0:localhost:22 -R 0:192.168.1.1:33 localhost +Allocated port 48392 for remote forward to localhost:22 +Allocated port 37515 for remote forward to 192.168.1.1:33 + + + + +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 0 +debug1: Local forwarding listening on ::1 port 0. +debug1: Allocated listen port 48392 +debug1: channel 0: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 48392. +debug1: channel 1: new [port listener] +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 0 +debug1: Local forwarding listening on ::1 port 0. +debug1: Allocated listen port 37515 +debug1: channel 2: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 37515. +debug1: channel 3: new [port listener] +debug1: server_input_channel_open: ctype session rchan 0 win 1048576 max 16384 +debug1: input_session_request +debug1: channel 4: new [server-session] +debug1: session_new: session 0 +debug1: session_open: channel 4 +debug1: session_open: session 0: link with channel 4 + +debug1: Local forwarding listening on ::1 port 5555. +debug1: channel 0: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 5555. +debug1: channel 1: new [port listener] +debug1: server_input_global_request: rtype tcpip-forward want_reply 1 +debug1: server_input_global_request: tcpip-forward listen localhost port 4444 +debug1: Local forwarding listening on ::1 port 4444. +debug1: channel 2: new [port listener] +debug1: Local forwarding listening on 127.0.0.1 port 4444. +debug1: channel 3: new [port listener] +debug1: server_input_channel_open: ctype session rchan 0 win 1048576 max 16384 +debug1: input_session_request +debug1: channel 4: new [server-session] +debug1: session_new: session 0 +debug1: session_open: channel 4 + +-------------------------------------------------------------------------------- + +[12:06] bento:openssh-6.2p1% grep SSH_CONNECTION -r * +audit-bsm.c: case SSH_CONNECTION_CLOSE: +audit.c: {SSH_CONNECTION_CLOSE, "CONNECTION_CLOSE"}, +audit.c: {SSH_CONNECTION_ABANDON, "CONNECTION_ABANDON"}, +audit.h: SSH_CONNECTION_CLOSE, /* closed after attempting auth or session */ +audit.h: SSH_CONNECTION_ABANDON, /* closed without completing auth */ +audit-linux.c: case SSH_CONNECTION_CLOSE: +monitor.c: case SSH_CONNECTION_CLOSE: +regress/proxy-connect.sh: SSH_CONNECTION=`${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 'echo $SSH_CONNECTION'` +regress/proxy-connect.sh: if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then +regress/proxy-connect.sh: fail "bad SSH_CONNECTION" +session.c: child_set_env(&env, &envsize, "SSH_CONNECTION", buf); +sftp-server.c: if ((cp = getenv("SSH_CONNECTION")) != NULL) { +sftp-server.c: error("Malformed SSH_CONNECTION variable: \"%s\"", +sftp-server.c: getenv("SSH_CONNECTION")); +ssh.0: SSH_CONNECTION Identifies the client and server ends of the +ssh.1:.It Ev SSH_CONNECTION +sshd.c: PRIVSEP(audit_event(SSH_CONNECTION_CLOSE)); +sshd.c: audit_event(SSH_CONNECTION_ABANDON); +[12:06] bento:openssh-6.2p1% + +-------------------------------------------------------------------------------- +debug1: Remote connections from LOCALHOST:5555 forwarded to local address localhost:22 + +-------------------------------------------------------------------------------- +[12:42] bento:openssh-6.2p1% grep tcpip-forward * +channels.c: packet_put_cstring("tcpip-forward"); +channels.c: packet_put_cstring("cancel-tcpip-forward"); +Binary file channels.o matches +grep: contrib: Is a directory +Binary file libssh.a matches +grep: openbsd-compat: Is a directory +grep: regress: Is a directory +grep: scard: Is a directory +serverloop.c: if (strcmp(rtype, "tcpip-forward") == 0) { +serverloop.c: debug("server_input_global_request: tcpip-forward listen %s port %d", +serverloop.c: } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) { +serverloop.c: debug("%s: cancel-tcpip-forward addr %s port %d", __func__, +Binary file serverloop.o matches +Binary file ssh matches +Binary file sshd matches +Binary file ssh-keyscan matches +Binary file ssh-keysign matches +[12:42] bento:openssh-6.2p1% + +-------------------------------------------------------------------------------- +Channel information for (remote) forwarding: + + c = channel_new("port listener", type, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, + 0, "port listener", 1); + c->path = xstrdup(host); + c->host_port = port_to_connect; + c->listening_addr = addr == NULL ? NULL : xstrdup(addr); + if (listen_port == 0 && allocated_listen_port != NULL && + !(datafellows & SSH_BUG_DYNAMIC_RPORT)) + c->listening_port = *allocated_listen_port; + else + c->listening_port = listen_port; + +-------------------------------------------------------------------------------- + +Code handling remote forwarding in the client: +- ssh_init_forwarding + - channel_request_remote_forwarding + Sends hostname + port for ssh1 only - not send in ssh2 + +Code handling forwarding / listening in the server: + +- channel_new: creates channels, 2 per listener (ipv4/ipv6) + - channels_alloc contains number of channels +- server_input_global_request + Reads only listen port, not hostname/port to connect to + - channel_setup_remote_fwd_listener + - channel_setup_remote_fwd_listener + +Code handling environment variables: + +- child_set_env +1236 child_set_env(&env, &envsize, "SSH_CONNECTION", buf); + From 0b4914a7f36ee5dc49e559f01bb055e8b19ee2e5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 May 2013 09:16:52 +0200 Subject: [PATCH 059/548] +comment wording Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index a9306aaa..54009f6c 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -225,7 +225,7 @@ class CdistObject(object): raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) def requirements_unfinished(self, requirements): - """Return state whether normal depedencies are satisfied""" + """Return state whether requirements are satisfied""" object_list = [] From a9ffa86b74c285e5ad8a0ef73fd6b132efbe34f3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 May 2013 09:19:36 +0200 Subject: [PATCH 060/548] remove some old code, merge run into deploy_and_cleanup Signed-off-by: Nico Schottelius --- cdist/config_install.py | 80 +++-------------------------------------- 1 file changed, 5 insertions(+), 75 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 4bf9ad32..5adf8b9d 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -57,30 +57,18 @@ class ConfigInstall(object): shutil.rmtree(destination) shutil.move(self.context.local.out_path, destination) - def deploy_and_cleanup(self): + def run(self): """Do what is most often done: deploy & cleanup""" start_time = time.time() - # Old Code - #self.deploy_to() - - # New Code - self.run() - - self.cleanup() - self.log.info("Finished successful run in %s seconds", - time.time() - start_time) - - ###################################################################### - # New code for running on object priority (not stage priority) - # - - def run(self): - """The main runner""" self.explorer.run_global_explorers(self.context.local.global_explorer_out_path) self.manifest.run_initial_manifest(self.context.initial_manifest) self.iterate_until_finished() + self.cleanup() + 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.context.local.object_path, @@ -141,10 +129,6 @@ class ConfigInstall(object): raise cdist.Error("The requirements of the following objects could not be resolved: %s" % ("; ".join(info_string))) - ###################################################################### - # Code required by both methods (which will stay) - # - def object_run(self, cdist_object, dry_run=False): """Run gencode and code for an object""" self.log.debug("Trying to run object " + cdist_object.name) @@ -171,57 +155,3 @@ class ConfigInstall(object): # Mark this object as done self.log.debug("Finishing run of " + cdist_object.name) cdist_object.state = core.CdistObject.STATE_DONE - - - ###################################################################### - # Stages based code - # - - def deploy_to(self): - """Mimic the old deploy to: Deploy to one host""" - self.stage_prepare() - self.stage_run() - - - def stage_prepare(self): - """Do everything for a deploy, minus the actual code stage""" - self.explorer.run_global_explorers(self.context.local.global_explorer_out_path) - self.manifest.run_initial_manifest(self.context.initial_manifest) - - self.log.info("Running object manifests and type explorers") - - # Continue process until no new objects are created anymore - new_objects_created = True - while new_objects_created: - new_objects_created = False - for cdist_object in core.CdistObject.list_objects(self.context.local.object_path, - self.context.local.type_path): - - if cdist_object.state == core.CdistObject.STATE_PREPARED: - self.log.debug("Skipping re-prepare of object %s", cdist_object) - continue - else: - self.object_prepare(cdist_object) - new_objects_created = True - - def object_prepare(self, cdist_object): - """Prepare object: Run type explorer + manifest""" - 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 - - def stage_run(self): - """The final (and real) step of deployment""" - self.log.info("Generating and executing code") - - objects = core.CdistObject.list_objects( - self.context.local.object_path, - self.context.local.type_path) - - dependency_resolver = resolver.DependencyResolver(objects) - self.log.debug(pprint.pformat(dependency_resolver.dependencies)) - - for cdist_object in dependency_resolver: - self.log.debug("Run object: %s", cdist_object) - self.object_run(cdist_object) From 782d84870dfd3c47250b4e4bd9424bbcc7e409b1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 May 2013 09:21:09 +0200 Subject: [PATCH 061/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 4d9642d7..3774c81f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog next: * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) + * Change execution order to run object as one unit 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From ae8040536f85c3fee1ddfcbcd27d4ac71a0c658f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 May 2013 09:26:48 +0200 Subject: [PATCH 062/548] mere tests of autorequire and resolver into execution_order Signed-off-by: Nico Schottelius --- cdist/test/autorequire/__init__.py | 91 ------------------- .../{resolver => execution_order}/__init__.py | 91 +++++++++++++++++++ .../fixtures/conf/explorer/.keep | 0 .../conf/manifest/circular_dependency | 0 .../conf/manifest/implicit_dependencies | 0 .../fixtures/conf/manifest/recursive_type | 0 .../conf/type/__addifnosuchline/.keep | 0 .../fixtures/conf/type/__directory/.keep | 0 .../fixtures/conf/type/__git/manifest | 0 .../conf/type/__nfsroot_client/manifest | 0 .../fixtures/conf/type/__package/manifest | 0 .../conf/type/__package_special/.keep | 0 .../type/__root_ssh_authorized_key/manifest | 0 .../fixtures/conf/type/__top/manifest | 0 .../fixtures/conf/type/__user/.keep | 0 .../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 | 0 .../__third/moon/.cdist/parameter/planet | 0 .../fixtures/type/__first/.keep | 0 .../fixtures/type/__second/.keep | 0 .../fixtures/type/__third/.keep | 0 30 files changed, 91 insertions(+), 91 deletions(-) delete mode 100644 cdist/test/autorequire/__init__.py rename cdist/test/{resolver => execution_order}/__init__.py (51%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/explorer/.keep (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/manifest/circular_dependency (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/manifest/implicit_dependencies (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/manifest/recursive_type (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/type/__addifnosuchline/.keep (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/type/__directory/.keep (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/type/__git/manifest (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/type/__nfsroot_client/manifest (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/type/__package/manifest (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/type/__package_special/.keep (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/type/__root_ssh_authorized_key/manifest (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/type/__top/manifest (100%) rename cdist/test/{autorequire => execution_order}/fixtures/conf/type/__user/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__first/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__first/child/.cdist/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__first/dog/.cdist/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__first/man/.cdist/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__first/woman/.cdist/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__second/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__second/on-the/.cdist/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__second/under-the/.cdist/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__third/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__third/moon/.cdist/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__third/moon/.cdist/parameter/name (100%) rename cdist/test/{resolver => execution_order}/fixtures/object/__third/moon/.cdist/parameter/planet (100%) rename cdist/test/{resolver => execution_order}/fixtures/type/__first/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/type/__second/.keep (100%) rename cdist/test/{resolver => execution_order}/fixtures/type/__third/.keep (100%) diff --git a/cdist/test/autorequire/__init__.py b/cdist/test/autorequire/__init__.py deleted file mode 100644 index 714a7d4b..00000000 --- a/cdist/test/autorequire/__init__.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -# -# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 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 . -# -# - -import os -import shutil - -import cdist -from cdist import test -from cdist.exec import local -from cdist import core -from cdist.core import manifest -from cdist import resolver -from cdist import config -import cdist.context - -import os.path as op -my_dir = op.abspath(op.dirname(__file__)) -fixtures = op.join(my_dir, 'fixtures') -add_conf_dir = op.join(fixtures, 'conf') - -class AutorequireTestCase(test.CdistTestCase): - - def setUp(self): - self.orig_environ = os.environ - os.environ = os.environ.copy() - self.temp_dir = self.mkdtemp() - - self.out_dir = os.path.join(self.temp_dir, "out") - self.remote_out_dir = os.path.join(self.temp_dir, "remote") - - os.environ['__cdist_out_dir'] = self.out_dir - os.environ['__cdist_remote_out_dir'] = self.remote_out_dir - - self.context = cdist.context.Context( - target_host=self.target_host, - remote_copy=self.remote_copy, - remote_exec=self.remote_exec, - add_conf_dirs=[add_conf_dir], - exec_path=test.cdist_exec_path, - debug=False) - - self.config = config.Config(self.context) - - def tearDown(self): - os.environ = self.orig_environ - shutil.rmtree(self.temp_dir) - - def test_implicit_dependencies(self): - self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'implicit_dependencies') - self.config.stage_prepare() - - objects = core.CdistObject.list_objects(self.context.local.object_path, self.context.local.type_path) - dependency_resolver = resolver.DependencyResolver(objects) - expected_dependencies = [ - dependency_resolver.objects['__package_special/b'], - dependency_resolver.objects['__package/b'], - dependency_resolver.objects['__package_special/a'] - ] - resolved_dependencies = dependency_resolver.dependencies['__package_special/a'] - self.assertEqual(resolved_dependencies, expected_dependencies) - - def test_circular_dependency(self): - self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'circular_dependency') - self.config.stage_prepare() - # raises CircularDependecyError - self.config.stage_run() - - def test_recursive_type(self): - self.context.initial_manifest = os.path.join(self.config.local.manifest_path, 'recursive_type') - self.config.stage_prepare() - # raises CircularDependecyError - self.config.stage_run() diff --git a/cdist/test/resolver/__init__.py b/cdist/test/execution_order/__init__.py similarity index 51% rename from cdist/test/resolver/__init__.py rename to cdist/test/execution_order/__init__.py index baae26de..c792a772 100644 --- a/cdist/test/resolver/__init__.py +++ b/cdist/test/execution_order/__init__.py @@ -86,3 +86,94 @@ class ResolverTestCase(test.CdistTestCase): first_man.requirements = ['__does/not/exist'] with self.assertRaises(cdist.Error): self.dependency_resolver.dependencies +# -*- coding: utf-8 -*- +# +# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 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 . +# +# + +import os +import shutil + +import cdist +from cdist import test +from cdist.exec import local +from cdist import core +from cdist.core import manifest +from cdist import resolver +from cdist import config +import cdist.context + +import os.path as op +my_dir = op.abspath(op.dirname(__file__)) +fixtures = op.join(my_dir, 'fixtures') +add_conf_dir = op.join(fixtures, 'conf') + +class AutorequireTestCase(test.CdistTestCase): + + def setUp(self): + self.orig_environ = os.environ + os.environ = os.environ.copy() + self.temp_dir = self.mkdtemp() + + self.out_dir = os.path.join(self.temp_dir, "out") + self.remote_out_dir = os.path.join(self.temp_dir, "remote") + + os.environ['__cdist_out_dir'] = self.out_dir + os.environ['__cdist_remote_out_dir'] = self.remote_out_dir + + self.context = cdist.context.Context( + target_host=self.target_host, + remote_copy=self.remote_copy, + remote_exec=self.remote_exec, + add_conf_dirs=[add_conf_dir], + exec_path=test.cdist_exec_path, + debug=False) + + self.config = config.Config(self.context) + + def tearDown(self): + os.environ = self.orig_environ + shutil.rmtree(self.temp_dir) + + def test_implicit_dependencies(self): + self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'implicit_dependencies') + self.config.stage_prepare() + + objects = core.CdistObject.list_objects(self.context.local.object_path, self.context.local.type_path) + dependency_resolver = resolver.DependencyResolver(objects) + expected_dependencies = [ + dependency_resolver.objects['__package_special/b'], + dependency_resolver.objects['__package/b'], + dependency_resolver.objects['__package_special/a'] + ] + resolved_dependencies = dependency_resolver.dependencies['__package_special/a'] + self.assertEqual(resolved_dependencies, expected_dependencies) + + def test_circular_dependency(self): + self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'circular_dependency') + self.config.stage_prepare() + # raises CircularDependecyError + self.config.stage_run() + + def test_recursive_type(self): + self.context.initial_manifest = os.path.join(self.config.local.manifest_path, 'recursive_type') + self.config.stage_prepare() + # raises CircularDependecyError + self.config.stage_run() diff --git a/cdist/test/autorequire/fixtures/conf/explorer/.keep b/cdist/test/execution_order/fixtures/conf/explorer/.keep similarity index 100% rename from cdist/test/autorequire/fixtures/conf/explorer/.keep rename to cdist/test/execution_order/fixtures/conf/explorer/.keep diff --git a/cdist/test/autorequire/fixtures/conf/manifest/circular_dependency b/cdist/test/execution_order/fixtures/conf/manifest/circular_dependency similarity index 100% rename from cdist/test/autorequire/fixtures/conf/manifest/circular_dependency rename to cdist/test/execution_order/fixtures/conf/manifest/circular_dependency diff --git a/cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies b/cdist/test/execution_order/fixtures/conf/manifest/implicit_dependencies similarity index 100% rename from cdist/test/autorequire/fixtures/conf/manifest/implicit_dependencies rename to cdist/test/execution_order/fixtures/conf/manifest/implicit_dependencies diff --git a/cdist/test/autorequire/fixtures/conf/manifest/recursive_type b/cdist/test/execution_order/fixtures/conf/manifest/recursive_type similarity index 100% rename from cdist/test/autorequire/fixtures/conf/manifest/recursive_type rename to cdist/test/execution_order/fixtures/conf/manifest/recursive_type diff --git a/cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep b/cdist/test/execution_order/fixtures/conf/type/__addifnosuchline/.keep similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__addifnosuchline/.keep rename to cdist/test/execution_order/fixtures/conf/type/__addifnosuchline/.keep diff --git a/cdist/test/autorequire/fixtures/conf/type/__directory/.keep b/cdist/test/execution_order/fixtures/conf/type/__directory/.keep similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__directory/.keep rename to cdist/test/execution_order/fixtures/conf/type/__directory/.keep diff --git a/cdist/test/autorequire/fixtures/conf/type/__git/manifest b/cdist/test/execution_order/fixtures/conf/type/__git/manifest similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__git/manifest rename to cdist/test/execution_order/fixtures/conf/type/__git/manifest diff --git a/cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest b/cdist/test/execution_order/fixtures/conf/type/__nfsroot_client/manifest similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__nfsroot_client/manifest rename to cdist/test/execution_order/fixtures/conf/type/__nfsroot_client/manifest diff --git a/cdist/test/autorequire/fixtures/conf/type/__package/manifest b/cdist/test/execution_order/fixtures/conf/type/__package/manifest similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__package/manifest rename to cdist/test/execution_order/fixtures/conf/type/__package/manifest diff --git a/cdist/test/autorequire/fixtures/conf/type/__package_special/.keep b/cdist/test/execution_order/fixtures/conf/type/__package_special/.keep similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__package_special/.keep rename to cdist/test/execution_order/fixtures/conf/type/__package_special/.keep diff --git a/cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest b/cdist/test/execution_order/fixtures/conf/type/__root_ssh_authorized_key/manifest similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__root_ssh_authorized_key/manifest rename to cdist/test/execution_order/fixtures/conf/type/__root_ssh_authorized_key/manifest diff --git a/cdist/test/autorequire/fixtures/conf/type/__top/manifest b/cdist/test/execution_order/fixtures/conf/type/__top/manifest similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__top/manifest rename to cdist/test/execution_order/fixtures/conf/type/__top/manifest diff --git a/cdist/test/autorequire/fixtures/conf/type/__user/.keep b/cdist/test/execution_order/fixtures/conf/type/__user/.keep similarity index 100% rename from cdist/test/autorequire/fixtures/conf/type/__user/.keep rename to cdist/test/execution_order/fixtures/conf/type/__user/.keep diff --git a/cdist/test/resolver/fixtures/object/__first/.keep b/cdist/test/execution_order/fixtures/object/__first/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/.keep rename to cdist/test/execution_order/fixtures/object/__first/.keep diff --git a/cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep b/cdist/test/execution_order/fixtures/object/__first/child/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/child/.cdist/.keep rename to cdist/test/execution_order/fixtures/object/__first/child/.cdist/.keep diff --git a/cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/execution_order/fixtures/object/__first/dog/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/dog/.cdist/.keep rename to cdist/test/execution_order/fixtures/object/__first/dog/.cdist/.keep diff --git a/cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep b/cdist/test/execution_order/fixtures/object/__first/man/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/man/.cdist/.keep rename to cdist/test/execution_order/fixtures/object/__first/man/.cdist/.keep diff --git a/cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/execution_order/fixtures/object/__first/woman/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__first/woman/.cdist/.keep rename to cdist/test/execution_order/fixtures/object/__first/woman/.cdist/.keep diff --git a/cdist/test/resolver/fixtures/object/__second/.keep b/cdist/test/execution_order/fixtures/object/__second/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__second/.keep rename to cdist/test/execution_order/fixtures/object/__second/.keep diff --git a/cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/execution_order/fixtures/object/__second/on-the/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__second/on-the/.cdist/.keep rename to cdist/test/execution_order/fixtures/object/__second/on-the/.cdist/.keep diff --git a/cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/execution_order/fixtures/object/__second/under-the/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__second/under-the/.cdist/.keep rename to cdist/test/execution_order/fixtures/object/__second/under-the/.cdist/.keep diff --git a/cdist/test/resolver/fixtures/object/__third/.keep b/cdist/test/execution_order/fixtures/object/__third/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__third/.keep rename to cdist/test/execution_order/fixtures/object/__third/.keep diff --git a/cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/execution_order/fixtures/object/__third/moon/.cdist/.keep similarity index 100% rename from cdist/test/resolver/fixtures/object/__third/moon/.cdist/.keep rename to cdist/test/execution_order/fixtures/object/__third/moon/.cdist/.keep diff --git a/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/execution_order/fixtures/object/__third/moon/.cdist/parameter/name similarity index 100% rename from cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/name rename to cdist/test/execution_order/fixtures/object/__third/moon/.cdist/parameter/name diff --git a/cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/execution_order/fixtures/object/__third/moon/.cdist/parameter/planet similarity index 100% rename from cdist/test/resolver/fixtures/object/__third/moon/.cdist/parameter/planet rename to cdist/test/execution_order/fixtures/object/__third/moon/.cdist/parameter/planet diff --git a/cdist/test/resolver/fixtures/type/__first/.keep b/cdist/test/execution_order/fixtures/type/__first/.keep similarity index 100% rename from cdist/test/resolver/fixtures/type/__first/.keep rename to cdist/test/execution_order/fixtures/type/__first/.keep diff --git a/cdist/test/resolver/fixtures/type/__second/.keep b/cdist/test/execution_order/fixtures/type/__second/.keep similarity index 100% rename from cdist/test/resolver/fixtures/type/__second/.keep rename to cdist/test/execution_order/fixtures/type/__second/.keep diff --git a/cdist/test/resolver/fixtures/type/__third/.keep b/cdist/test/execution_order/fixtures/type/__third/.keep similarity index 100% rename from cdist/test/resolver/fixtures/type/__third/.keep rename to cdist/test/execution_order/fixtures/type/__third/.keep From e0193fec564a00ace0368cd4519b2be34b21ba4f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 May 2013 09:28:41 +0200 Subject: [PATCH 063/548] add logo that is used on cdist flyers Signed-off-by: Nico Schottelius --- docs/gfx/label-cdist-ngcm.odt | Bin 0 -> 14805 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/gfx/label-cdist-ngcm.odt diff --git a/docs/gfx/label-cdist-ngcm.odt b/docs/gfx/label-cdist-ngcm.odt new file mode 100644 index 0000000000000000000000000000000000000000..5e73b3326e45b71746136c75f65ed475997e9ab6 GIT binary patch literal 14805 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 Date: Wed, 15 May 2013 09:40:53 +0200 Subject: [PATCH 064/548] add some older logfiles (xournal and inkscape based) Signed-off-by: Nico Schottelius --- docs/dev/logs/2012-09-03.dep-ideas.xoj | Bin 0 -> 34893 bytes .../2012-11-15.cdist-sexy-interaction.svg | 282 ++++++++++++++++++ .../2013-01-03.dependencies-visualised.xoj | Bin 0 -> 91819 bytes docs/dev/logs/2013-04-08.execution-graph.xoj | Bin 0 -> 57083 bytes 4 files changed, 282 insertions(+) create mode 100644 docs/dev/logs/2012-09-03.dep-ideas.xoj create mode 100644 docs/dev/logs/2012-11-15.cdist-sexy-interaction.svg create mode 100644 docs/dev/logs/2013-01-03.dependencies-visualised.xoj create mode 100644 docs/dev/logs/2013-04-08.execution-graph.xoj diff --git a/docs/dev/logs/2012-09-03.dep-ideas.xoj b/docs/dev/logs/2012-09-03.dep-ideas.xoj new file mode 100644 index 0000000000000000000000000000000000000000..b2ab927eb659afee302fed8b461362f6c8f7a6e3 GIT binary patch literal 34893 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 + + + + + + + + + image/svg+xml + + + + + + + + + cdist + + + + configures hosts + + + + + sexy + + + + + + manages inventory + + + + + + installs hosts(missing) + + + + interact + + + + + + + + visualises inventory(missing) + + + + + + diff --git a/docs/dev/logs/2013-01-03.dependencies-visualised.xoj b/docs/dev/logs/2013-01-03.dependencies-visualised.xoj new file mode 100644 index 0000000000000000000000000000000000000000..715d25838f4f1f26a46fc9795e1173b19da07ecd GIT binary patch literal 91819 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 Date: Wed, 15 May 2013 10:08:23 +0200 Subject: [PATCH 065/548] re-add object_prepare, use new run() method Signed-off-by: Nico Schottelius --- cdist/config_install.py | 7 +++++++ scripts/cdist | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 5adf8b9d..43bfb7e4 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -129,6 +129,13 @@ class ConfigInstall(object): raise cdist.Error("The requirements of the following objects could not be resolved: %s" % ("; ".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.explorer.run_type_explorers(cdist_object) + self.manifest.run_type_manifest(cdist_object) + cdist_object.state = core.CdistObject.STATE_PREPARED + def object_run(self, cdist_object, dry_run=False): """Run gencode and code for an object""" self.log.debug("Trying to run object " + cdist_object.name) diff --git a/scripts/cdist b/scripts/cdist index 00c55ae8..bca4fea7 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -160,7 +160,7 @@ def configinstall(args, mode): (time_end - time_start)) if len(failed_hosts) > 0: - raise cdist.Error("Failed to deploy to the following hosts: " + + raise cdist.Error("Failed to configure the following hosts: " + " ".join(failed_hosts)) def configinstall_onehost(host, args, mode, parallel): @@ -179,7 +179,7 @@ def configinstall_onehost(host, args, mode, parallel): debug=args.debug) c = mode(context) - c.deploy_and_cleanup() + c.run() context.cleanup() except cdist.Error as e: From 14853813405b7f698178b802c43a9062dacd6d5c Mon Sep 17 00:00:00 2001 From: Tyler Akins Date: Sun, 26 May 2013 15:54:28 -0500 Subject: [PATCH 066/548] Fixing apt_ppa type - can't use double equals with dash --- cdist/conf/type/__apt_ppa/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_ppa/gencode-remote b/cdist/conf/type/__apt_ppa/gencode-remote index 0ea8011c..300a0e1e 100755 --- a/cdist/conf/type/__apt_ppa/gencode-remote +++ b/cdist/conf/type/__apt_ppa/gencode-remote @@ -22,7 +22,7 @@ name="$__object_id" state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" -if [ "$state_should" == "$state_is" ]; then +if [ "$state_should" = "$state_is" ]; then # Nothing to do, move along exit 0 fi From 9647d8f7e50c380690da998a6c7c691f4fb1bee7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 27 May 2013 12:55:49 +0200 Subject: [PATCH 067/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 3774c81f..fe7507f8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog next: * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) * Change execution order to run object as one unit + * Type __apt_ppa: Fix comparision operator (Tyler Akins) 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From 3d73cd2fd3a5bfdf91ad032f4453b4fe1bee7d29 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 27 May 2013 16:36:20 +0200 Subject: [PATCH 068/548] better debugging for wrong type, fix emulator tests, fixes #176 Signed-off-by: Nico Schottelius --- cdist/emulator.py | 7 ++++++- cdist/test/emulator/__init__.py | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index a9c760cb..5a23fca5 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -184,7 +184,12 @@ class Emulator(object): if len(requirement) == 0: continue # Raises an error, if object cannot be created - cdist_object = self.cdist_object.object_from_name(requirement) + try: + cdist_object = self.cdist_object.object_from_name(requirement) + except core.cdist_type.NoSuchTypeError: + self.log.error("%s requires object %s with non-existing type at %s" % (self.cdist_object.name, requirement, self.object_source)) + raise + self.log.debug("Recording requirement: " + requirement) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index fc0b6695..a9746f99 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -63,13 +63,13 @@ class EmulatorTestCase(test.CdistTestCase): def test_nonexistent_type_exec(self): argv = ['__does-not-exist'] - self.assertRaises(core.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'] self.env['require'] = '__does-not-exist/some-id' emu = emulator.Emulator(argv, env=self.env) - self.assertRaises(core.NoSuchTypeError, emu.run) + self.assertRaises(core.cdist_type.NoSuchTypeError, emu.run) def test_illegal_object_id_requirement(self): argv = ['__file', '/tmp/foobar'] @@ -81,7 +81,7 @@ class EmulatorTestCase(test.CdistTestCase): argv = ['__file', '/tmp/foobar'] self.env['require'] = '__file' emu = emulator.Emulator(argv, env=self.env) - self.assertRaises(core.IllegalObjectIdError, emu.run) + self.assertRaises(core.cdist_object.MissingObjectIdError, emu.run) def test_singleton_object_requirement(self): argv = ['__file', '/tmp/foobar'] From 3c58eee0032754e495278d70ec7f4669f333e361 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 28 May 2013 10:57:55 +0200 Subject: [PATCH 069/548] +semi finished decentralised/centralised picture Signed-off-by: Nico Schottelius --- ...12-11-02.cdist-vs-centralised-development.xoj | Bin 0 -> 9512 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/dev/logs/2012-11-02.cdist-vs-centralised-development.xoj diff --git a/docs/dev/logs/2012-11-02.cdist-vs-centralised-development.xoj b/docs/dev/logs/2012-11-02.cdist-vs-centralised-development.xoj new file mode 100644 index 0000000000000000000000000000000000000000..5630389304d5ce97e7a574d084346e19b4c761a3 GIT binary patch literal 9512 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 a3jJHr&E@f?`NR3cBhb7f>HOrQNB;+G2ke&s literal 0 HcmV?d00001 From 260b6f6ae19d6b10fc300f3f29f46ac614a4d7e4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 14:49:10 +0200 Subject: [PATCH 070/548] clean-dist -> distclean && make xtaran happy Signed-off-by: Nico Schottelius --- build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build b/build index fc605313..d764143c 100755 --- a/build +++ b/build @@ -367,7 +367,7 @@ eof find * -name __pycache__ | xargs rm -rf ;; - clean-dist) + distclean) rm -f cdist/version.py MANIFEST PKGBUILD rm -rf cache/ dist/ From 614a5cfe553a8deab24f6a64c73cea4ae2e97b82 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 14:51:06 +0200 Subject: [PATCH 071/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index fe7507f8..3b92bd56 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,8 +6,9 @@ Changelog next: * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) + * Build: Change clean-dist target to "distclean" * Change execution order to run object as one unit - * Type __apt_ppa: Fix comparision operator (Tyler Akins) + * Type __apt_ppa: Fix comparison operator (Tyler Akins) 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From e55d328c9eadbd888d458fb32cb1433da9a3d451 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 14:55:54 +0200 Subject: [PATCH 072/548] ++ideen Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-05-17.ssh-callback-socat | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/dev/logs/2013-05-17.ssh-callback-socat diff --git a/docs/dev/logs/2013-05-17.ssh-callback-socat b/docs/dev/logs/2013-05-17.ssh-callback-socat new file mode 100644 index 00000000..69428309 --- /dev/null +++ b/docs/dev/logs/2013-05-17.ssh-callback-socat @@ -0,0 +1,40 @@ + +start ssh +to controlhost, +bind other side to +localhost:22 + + +targethost ------> ssh ------> controlhost + | + | + socat: connect stdin/stdout to ? + start cdist with port information + added + + +Use + +socat + + +-------------------------------------------------------------------------------- + TCP:: + Connects to [TCP service] on [IP address] using TCP/IP version 4 or 6 depending on address specifi‐ + cation, name resolution, or option pf. + Option groups: FD,SOCKET,IP4,IP6,TCP,RETRY + Useful options: crnl, bind, pf, connect-timeout, tos, mtudiscover, mss, nodelay, nonblock, sourceport, retry, + readbytes + See also: TCP4, TCP6, TCP-LISTEN, UDP, SCTP-CONNECT, UNIX-CONNECT + +forever +-------------------------------------------------------------------------------- +[root@nico-dev-vm-snr01 yum.repos.d]# ps aux | grep socat +nico 25035 0.0 0.0 41640 1524 ? Ss 13:27 0:00 socat - TCP-LISTEN:1234 +root 25037 0.0 0.0 103240 836 pts/1 S+ 13:27 0:00 grep socat +[root@nico-dev-vm-snr01 yum.repos.d]# + + + +-------------------------------------------------------------------------------- + From 68d4bcbcb45d5bbe5bbef766dd12b8aa5657ff4a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 15:05:43 +0200 Subject: [PATCH 073/548] begin to fix syntax errors of merge Signed-off-by: Nico Schottelius --- cdist/test/execution_order/__init__.py | 59 ++++++++------------------ 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/cdist/test/execution_order/__init__.py b/cdist/test/execution_order/__init__.py index c792a772..d9804833 100644 --- a/cdist/test/execution_order/__init__.py +++ b/cdist/test/execution_order/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -25,13 +26,18 @@ import shutil import cdist from cdist import test from cdist import core -from cdist import resolver +from cdist import config +from cdist.exec import local +from cdist.core import manifest +import cdist.context + 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') class ResolverTestCase(test.CdistTestCase): @@ -39,7 +45,6 @@ class ResolverTestCase(test.CdistTestCase): def setUp(self): self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) self.object_index = dict((o.name, o) for o in self.objects) - self.dependency_resolver = resolver.DependencyResolver(self.objects) def tearDown(self): for o in self.objects: @@ -48,8 +53,9 @@ class ResolverTestCase(test.CdistTestCase): def test_find_requirements_by_name_string(self): requirements = ['__first/man', '__second/on-the', '__third/moon'] required_objects = [self.object_index[name] for name in requirements] - self.assertEqual(sorted(list(self.dependency_resolver.find_requirements_by_name(requirements))), - sorted(required_objects)) + # self.assertEqual(sorted(list(self.dependency_resolver.find_requirements_by_name(requirements))), + # sorted(required_objects)) + self.assertTrue(False) def test_find_requirements_by_name_pattern(self): requirements = ['__first/*', '__second/*-the', '__third/moon'] @@ -61,6 +67,7 @@ class ResolverTestCase(test.CdistTestCase): required_objects = [self.object_index[name] for name in requirements_expanded] self.assertEqual(sorted(list(self.dependency_resolver.find_requirements_by_name(requirements))), sorted(required_objects)) + self.assertTrue(False) def test_dependency_resolution(self): first_man = self.object_index['__first/man'] @@ -72,6 +79,7 @@ class ResolverTestCase(test.CdistTestCase): self.dependency_resolver.dependencies['__first/man'], [third_moon, second_on_the, first_man] ) + self.assertTrue(False) def test_circular_reference(self): first_man = self.object_index['__first/man'] @@ -80,50 +88,14 @@ class ResolverTestCase(test.CdistTestCase): first_woman.requirements = [first_man.name] with self.assertRaises(resolver.CircularReferenceError): self.dependency_resolver.dependencies + self.assertTrue(False) def test_requirement_not_found(self): first_man = self.object_index['__first/man'] first_man.requirements = ['__does/not/exist'] with self.assertRaises(cdist.Error): self.dependency_resolver.dependencies -# -*- coding: utf-8 -*- -# -# 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 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 . -# -# - -import os -import shutil - -import cdist -from cdist import test -from cdist.exec import local -from cdist import core -from cdist.core import manifest -from cdist import resolver -from cdist import config -import cdist.context - -import os.path as op -my_dir = op.abspath(op.dirname(__file__)) -fixtures = op.join(my_dir, 'fixtures') -add_conf_dir = op.join(fixtures, 'conf') + self.assertTrue(False) class AutorequireTestCase(test.CdistTestCase): @@ -165,15 +137,18 @@ class AutorequireTestCase(test.CdistTestCase): ] resolved_dependencies = dependency_resolver.dependencies['__package_special/a'] self.assertEqual(resolved_dependencies, expected_dependencies) + self.assertTrue(False) def test_circular_dependency(self): self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'circular_dependency') self.config.stage_prepare() # raises CircularDependecyError self.config.stage_run() + self.assertTrue(False) def test_recursive_type(self): self.context.initial_manifest = os.path.join(self.config.local.manifest_path, 'recursive_type') self.config.stage_prepare() # raises CircularDependecyError self.config.stage_run() + self.assertTrue(False) From 11ecd73bf04a013cf354d95ac3fd7d89eec94a42 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 16:52:58 +0200 Subject: [PATCH 074/548] rename build -> build-cdist, as setup.py uses build/ Signed-off-by: Nico Schottelius --- build => build-cdist | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename build => build-cdist (100%) diff --git a/build b/build-cdist similarity index 100% rename from build rename to build-cdist From c789d9a5bf2b31180b05f9813fd17f84515a7ddc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 17:34:03 +0200 Subject: [PATCH 075/548] use build-cdist for the moment, begin to export targets Signed-off-by: Nico Schottelius --- Makefile | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 948bdcd9..f4fd36b1 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,13 @@ +DIST=dist-tag dist-branch-merge dist-pypi dist-archlinux-makepkg +PUBLISH=web man-pub pub dist-blog dist-freecode dist-ml dist-manual dist-archlinux-aur-upload + + %: - ./build $@ + ./build-cdist $@ + +$(DIST): dist-check + +dist: $(DIST) + echo "Run \"make release\" to release to the public" + +release: From 53fe3844cbb79f6cf3dd9e4bf78eb104845a2fdd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 18:11:19 +0200 Subject: [PATCH 076/548] (xtaran && lintian)++ Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-hacker.text | 2 +- docs/man/man7/cdist-manifest.text | 2 +- docs/man/man7/cdist-stages.text | 2 +- docs/man/man7/cdist-type.text | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/man/man7/cdist-hacker.text b/docs/man/man7/cdist-hacker.text index d0f9a399..9dd52d35 100644 --- a/docs/man/man7/cdist-hacker.text +++ b/docs/man/man7/cdist-hacker.text @@ -51,7 +51,7 @@ work nor kill the authors brain: - 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 - seperate branches. This way one feature can already be included, even if + separate branches. This way one feature can already be included, even if the other needs to be improved. As soon as your work meets these requirements, write a mail diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 19f6053e..2c6ec5c1 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -107,7 +107,7 @@ DEPENDENCIES ------------ 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 seperated. +requirements can be added white space separated. -------------------------------------------------------------------------------- # No dependency diff --git a/docs/man/man7/cdist-stages.text b/docs/man/man7/cdist-stages.text index fa5e28d1..5f2d2e4c 100644 --- a/docs/man/man7/cdist-stages.text +++ b/docs/man/man7/cdist-stages.text @@ -33,7 +33,7 @@ be created, if it has different parameters. 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 transfered back +executed on the target host. The results are transferred back and can be used in the following stages to decide what changes need to be made on the target to implement the desired state. diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text index 54b67be5..18deda9a 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.text @@ -73,7 +73,7 @@ To begin a new type, just create the directory **cdist/conf/type/__NAME**. DEFINING PARAMETERS ------------------- Every type consists of required, optional and boolean parameters, which must -be created in a newline seperated file in ***parameter/required***, +be created 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 From 6945d8ebc9de8444a8d5bbcb61a4b452ac78b460 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 18:13:56 +0200 Subject: [PATCH 077/548] build -> build-helper Signed-off-by: Nico Schottelius --- .gitignore | 1 + Makefile | 46 +++++++++++++++++++++++++++++++++---- build-cdist => build-helper | 0 3 files changed, 42 insertions(+), 5 deletions(-) rename build-cdist => build-helper (100%) diff --git a/.gitignore b/.gitignore index 6e2d4437..27455cd9 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ cdist/version.py /cdist-*.tar.gz /pkg /src +build diff --git a/Makefile b/Makefile index f4fd36b1..c9fa387b 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,49 @@ +# +# 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 . +# +# + DIST=dist-tag dist-branch-merge dist-pypi dist-archlinux-makepkg -PUBLISH=web man-pub pub dist-blog dist-freecode dist-ml dist-manual dist-archlinux-aur-upload +RELEASE=web release-man pub release-blog dist-freecode dist-ml dist-manual dist-archlinux-aur-upload - -%: - ./build-cdist $@ +version: $(DIST): dist-check +$(RELEASE): $(DIST) + dist: $(DIST) echo "Run \"make release\" to release to the public" -release: +release: $(RELEASE) + +man: mangen mantype manbuild + +man-pub: man + +dist-archlinux: dist-pypi + +dist-archlinux-makepkg: PKGBUILD + makepkg -c --source + +PKGBUILD: PKGBUILD.in + ./PKGBUILD.in + +%: + ./build-helper $@ + diff --git a/build-cdist b/build-helper similarity index 100% rename from build-cdist rename to build-helper From fd72c607c158275509d19b78a13b7319159503ba Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 18:16:50 +0200 Subject: [PATCH 078/548] reorder manpage Signed-off-by: Nico Schottelius --- Makefile | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index c9fa387b..d751a4e9 100644 --- a/Makefile +++ b/Makefile @@ -19,28 +19,31 @@ # DIST=dist-tag dist-branch-merge dist-pypi dist-archlinux-makepkg -RELEASE=web release-man pub release-blog dist-freecode dist-ml dist-manual dist-archlinux-aur-upload +RELEASE=web release-man pub +RELEASE+=release-blog release-ml +RELEASE+=dist-freecode dist-manual dist-archlinux-aur-upload version: $(DIST): dist-check $(RELEASE): $(DIST) +man: mangen mantype manbuild dist: $(DIST) echo "Run \"make release\" to release to the public" release: $(RELEASE) -man: mangen mantype manbuild - -man-pub: man - dist-archlinux: dist-pypi +dist-check: clean man + dist-archlinux-makepkg: PKGBUILD makepkg -c --source +release-pub: man + PKGBUILD: PKGBUILD.in ./PKGBUILD.in From 4dfa6538233d9990dc819cacaa8aa2a932cc3b58 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 22:29:30 +0200 Subject: [PATCH 079/548] callback not yet ready for master Signed-off-by: Nico Schottelius --- callback.py | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 callback.py diff --git a/callback.py b/callback.py deleted file mode 100644 index 1bf5545a..00000000 --- a/callback.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 - -# SSH_CLIENT and SSH_CONNECTION available -src_ip = os.environ['SSH_CLIENT'].split()[0] - -print("Plain version: Connecting back to %s" % src_ip) From 96e58af1dae265654c4b156da936b582e5ca2635 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 3 Jun 2013 22:29:49 +0200 Subject: [PATCH 080/548] more stuff in the makefile Signed-off-by: Nico Schottelius --- Makefile | 73 +++++++++++++++++++++++------ build-helper | 130 +++++---------------------------------------------- 2 files changed, 70 insertions(+), 133 deletions(-) diff --git a/Makefile b/Makefile index d751a4e9..b97acf12 100644 --- a/Makefile +++ b/Makefile @@ -18,35 +18,78 @@ # # -DIST=dist-tag dist-branch-merge dist-pypi dist-archlinux-makepkg -RELEASE=web release-man pub -RELEASE+=release-blog release-ml -RELEASE+=dist-freecode dist-manual dist-archlinux-aur-upload +MANDIR=docs/man +MAN1DSTDIR=$(MANDIR)/man1 +MAN7DSTDIR=$(MANDIR)/man7 +MANREF=$(MAN7DSTDIR)/cdist-reference.text +MANREFSH=$(MANDIR)/cdist-reference.text.sh + +CHECKS=check-version check-date + +DIST=dist-tag dist-branch-merge + +RELEASE=release-web release-man release-pypi release-archlinux-makepkg +RELEASE+=release-blog release-ml +RELEASE+=release-freecode release-archlinux-aur-upload + +helper=./build-helper +version=`git describe` +versionchangelog=`$(helper) changelog-version` +versionfile=cdist/version.py + +archlinuxtar=cdist-${versionchangelog}-1.src.tar.gz + +$(versionfile): + echo $(version) > $@ -version: $(DIST): dist-check -$(RELEASE): $(DIST) +$(RELEASE): $(DIST) $(CHECKS) -man: mangen mantype manbuild +man: $(MANREF) mantype manbuild + +$(MANREF): $(MANREFSH) + $(MANREFSH) + +################################################################################ +# generic code +# + + +################################################################################ +# dist code +# +dist-check: man dist: $(DIST) echo "Run \"make release\" to release to the public" -release: $(RELEASE) +dist-pypi: man version + python3 setup.py sdist upload -dist-archlinux: dist-pypi - -dist-check: clean man - -dist-archlinux-makepkg: PKGBUILD +$(archlinuxtar): PKGBUILD dist-pypi makepkg -c --source +################################################################################ +# release code +# +release: pub $(RELEASE) + echo "Don't forget...: linkedin" + + +release-archlinux: $(archlinuxtar) + burp -c system $^ + +release-blog: blog +release-ml: release-blog release-pub: man +release-web: web-doc + PKGBUILD: PKGBUILD.in ./PKGBUILD.in +################################################################################ +# generic call %: - ./build-helper $@ - + $(helper) $@ diff --git a/build-helper b/build-helper index d764143c..c3ffe045 100755 --- a/build-helper +++ b/build-helper @@ -18,14 +18,9 @@ # along with cdist. If not, see . # # -# Push a directory to a target, both sides have the same name (i.e. explorers) -# or -# Pull a directory from a target, both sides have the same name (i.e. explorers) +# This file contains the heavy lifting found usually in the Makefile # -# exit on any error -#set -e - basedir=${0%/*} version=$(cd "$basedir" && git describe) @@ -51,13 +46,6 @@ SPEECHESDIR=docs/speeches cd "$basedir" case "$1" in - man) - set -e - "$0" mangen - "$0" mantype - "$0" manbuild - ;; - manbuild) trap abort INT abort() { @@ -86,13 +74,7 @@ case "$1" in done ;; - mangen) - ${MANDIR}/cdist-reference.text.sh - ;; - - man-pub) - $0 man - + release-man) version=$($0 changelog-version) rm -rf "${WEBMAN}" @@ -102,36 +84,6 @@ case "$1" in cd ${WEBMAN} && git add . && git commit -m "Cdist Manpage update: $version" ;; - dist) - set -e - # Do the checks - $0 dist-check - - # Git changes - everything depends on this - $0 dist-tag - $0 dist-branch-merge - - # Pypi first - is the base for others - $0 dist-pypi - - # Archlinux depends on successful pypi ;-) - $0 dist-archlinux - - # Update website (includes documentation) - $0 web - - # Update manpages on website - $0 man-pub - - # update git repos - $0 pub - - $0 dist-blog - $0 dist-freecode - $0 dist-ml - $0 dist-manual - ;; - changelog-changes) awk -F: 'BEGIN { start=0 } { if ($0 ~ /^[[:digit:]]/) { if(start == 0) {start = 1 } else { exit } } else { if(start==1) {print $0 }} }' "$basedir/docs/changelog" ;; @@ -141,12 +93,7 @@ case "$1" in grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/:.*//' ;; - dist-check) - set -e - echo "Verifying documentation building works ..." - $0 clean - $0 man - + check-version) changelog_version=$($0 changelog-version) echo "Target version from changelog: $changelog_version" @@ -154,7 +101,9 @@ case "$1" in echo "Version $changelog_version already exists, aborting." exit 1 fi + ;; + check-date) # verify date in changelog date_today="$(date +%Y-%m-%d)" date_changelog=$(grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/.*: //') @@ -164,7 +113,6 @@ case "$1" in echo "Changelog: $date_changelog" exit 1 fi - ;; blog) @@ -186,8 +134,7 @@ For more information visit the [[cdist homepage|software/cdist]]. eof ;; - dist-blog) - $0 blog + release-blog) version=$($0 changelog-version) file=cdist-${version}-released.mdwn cd "$WEBBLOG" @@ -196,8 +143,7 @@ eof git push ;; - dist-ml) - $0 blog + release-ml) version=$($0 changelog-version) to_a=cdist to_d=l.schottelius.org @@ -233,16 +179,6 @@ eof ;; - dist-manual) - cat << notes - - To be done manually... - - - linkedin entry -notes - - ;; - dist-tag) version=$($0 changelog-version) # add tag @@ -267,23 +203,7 @@ notes fi ;; - dist-archlinux) - $0 dist-archlinux-makepkg - $0 dist-archlinux-aur-upload - ;; - - dist-archlinux-makepkg) - ./PKGBUILD.in - makepkg -c --source - ;; - - dist-archlinux-aur-upload) - version=$($0 changelog-version) - tar=cdist-${version}-1.src.tar.gz - burp -c system "$tar" - ;; - - dist-freecode) + release-freecode) version=$($0 changelog-version) api_token=$(awk '/machine freecode login/ { print $8 }' ~/.netrc) @@ -316,13 +236,7 @@ eof ;; - dist-pypi) - $0 man - $0 version - python3 setup.py sdist upload - ;; - - speeches) + dist-speeches) cd "$SPEECHESDIR" for speech in *tex; do pdflatex "$speech" @@ -339,16 +253,15 @@ eof cd "${WEBDIR}" && make pub ;; - web) + release-web) set -e - "$0" web-doc # Fix ikiwiki, which does not like symlinks for pseudo security ssh tee.schottelius.org \ "cd /home/services/www/nico/www.nico.schottelius.org/www/software/cdist/man && rm -f latest && ln -sf "$version" latest" ;; - p|pu|pub) + pub) for remote in "" github sf; do echo "Pushing to $remote" git push --mirror $remote @@ -376,11 +289,6 @@ eof rm -rf pkg/ src/ ;; - very-clean) - $0 clean - $0 clean-dist - ;; - test) shift # skip t export PYTHONPATH="$(pwd -P)" @@ -392,22 +300,8 @@ eof fi ;; - version) - echo "VERSION=\"$version\"" > cdist/version.py - ;; - *) - echo '' - echo 'Welcome to cdist!' - echo '' - echo 'Here are the possible targets:' - echo '' - echo ' clean: Remove build stuff' - echo ' man: Build manpages (requires Asciidoc)' - echo ' test: Run tests' - echo '' - echo '' - echo "Unknown target, \"$1\"" >&2 + echo "Unknown target $@ - aborting" exit 1 ;; From 9195c9b8e87680d702c008edb4de77de54dfa012 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Jun 2013 21:10:57 +0200 Subject: [PATCH 081/548] Remove ugly argumentparser bug Before: [21:09] bento:~% cdist Traceback (most recent call last): File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 232, in commandline() File "/home/users/nico/p/cdist/cdist/bin/../scripts/cdist", line 106, in commandline args.func(args) AttributeError: 'Namespace' object has no attribute 'func' After: [21:11] bento:~% cdist usage: cdist [-h] [-d] [-v] [-V] {banner,config} ... cdist 2.1.1-48-gfd72c60 optional arguments: -h, --help show this help message and exit -d, --debug Set log level to debug -v, --verbose Set log level to info, be more verbose -V, --version Show version Commands: {banner,config} Get cdist at http://www.nico.schottelius.org/software/cdist/ [21:11] bento:~% Signed-off-by: Nico Schottelius --- scripts/cdist | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/cdist b/scripts/cdist index bca4fea7..3c94b38b 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -103,7 +103,14 @@ def commandline(): logging.root.setLevel(logging.DEBUG) log.debug(args) - args.func(args) + + # Work around python 3.3 bug: + # http://bugs.python.org/issue16308 + # http://bugs.python.org/issue9253 + try: + args.func(args) + except AttributeError: + parser['main'].print_help() def config(args): configinstall(args, mode=cdist.config.Config) From 0cf0cdd0c354020455b88a99d4bab0a3b74fc660 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 7 Jun 2013 21:14:51 +0200 Subject: [PATCH 082/548] keep version generating in build-helper, so people cloning from git don't need make Signed-off-by: Nico Schottelius --- Makefile | 13 +++++++++++-- bin/cdist | 2 +- build-helper | 3 +++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b97acf12..cf83a591 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,10 @@ # # +A2XM=a2x -f manpage --no-xmllint -a encoding=UTF-8 +A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 +helper=./build-helper + MANDIR=docs/man MAN1DSTDIR=$(MANDIR)/man1 MAN7DSTDIR=$(MANDIR)/man7 @@ -32,7 +36,6 @@ RELEASE=release-web release-man release-pypi release-archlinux-makepkg RELEASE+=release-blog release-ml RELEASE+=release-freecode release-archlinux-aur-upload -helper=./build-helper version=`git describe` versionchangelog=`$(helper) changelog-version` versionfile=cdist/version.py @@ -40,7 +43,7 @@ versionfile=cdist/version.py archlinuxtar=cdist-${versionchangelog}-1.src.tar.gz $(versionfile): - echo $(version) > $@ + $(helper) version $(DIST): dist-check @@ -48,6 +51,12 @@ $(RELEASE): $(DIST) $(CHECKS) man: $(MANREF) mantype manbuild +$(MAN7DSTDIR)/cdist-type__motd.7: $(MAN7DSTDIR)/cdist-type__motd.text + $(A2XM) $^ + +$(MAN7DSTDIR)/cdist-type__motd.text: cdist/conf/type/__motd/man.text + echo ln -sf $@ $^ + $(MANREF): $(MANREFSH) $(MANREFSH) diff --git a/bin/cdist b/bin/cdist index dfe4fa00..f8fec000 100755 --- a/bin/cdist +++ b/bin/cdist @@ -25,7 +25,7 @@ dir=${0%/*} # Ensure version is present - the bundled/shipped version contains a static version, # the git version contains a dynamic version -"$dir/../build" version +"$dir/../build-helper" version libdir=$(cd "${dir}/../" && pwd -P) export PYTHONPATH="${libdir}" diff --git a/build-helper b/build-helper index c3ffe045..3bbf4dfc 100755 --- a/build-helper +++ b/build-helper @@ -299,6 +299,9 @@ eof python3 -m unittest "$@" fi ;; + version) + git describe > cdist/version.py + ;; *) echo "Unknown target $@ - aborting" From 59bc29fbe38acf85bbb0560ab66670559fbec2c8 Mon Sep 17 00:00:00 2001 From: nuex Date: Fri, 7 Jun 2013 21:10:34 -0400 Subject: [PATCH 083/548] add example of using non-root user with sudo --- other/examples/remote/sudo/copy | 51 +++++++++++++++++++++++++++++++++ other/examples/remote/sudo/exec | 30 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100755 other/examples/remote/sudo/copy create mode 100755 other/examples/remote/sudo/exec diff --git a/other/examples/remote/sudo/copy b/other/examples/remote/sudo/copy new file mode 100755 index 00000000..577f270e --- /dev/null +++ b/other/examples/remote/sudo/copy @@ -0,0 +1,51 @@ +#!/bin/sh +# +# 2012 Matt Coddington (mcoddington at gmail.com) +# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2013 Chase Allen James (nx-cdist at nu-ex.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 . +# +# +# Use rsync over ssh to copy files. Uses the "--rsync-path" option +# to run the remote rsync instance with sudo. +# +# This command assumes your ssh configuration is already set up +# in ~/.ssh/config. +# +# Usage: +# cdist config --remote-copy /path/to/this/script target_host +# + +# For rsync to do the right thing, the source has to end with "/" if it is +# a directory. The below preprocessor loop takes care of that. + +# second last argument is the source +source_index=$(($#-1)) +index=0 +for arg in $@; do + if [ $index -eq 0 ]; then + # reset $@ + set -- + fi + index=$((index+=1)) + if [ $index -eq $source_index -a -d "$arg" ]; then + arg="${arg%/}/" + fi + set -- "$@" "$arg" +done + +rsync --copy-links --rsync-path="sudo rsync" -e 'ssh' "$@" diff --git a/other/examples/remote/sudo/exec b/other/examples/remote/sudo/exec new file mode 100755 index 00000000..b4ebe4cf --- /dev/null +++ b/other/examples/remote/sudo/exec @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2013 Chase Allen James (nx-cdist at nu-ex.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 . +# +# Prefixes all remote commands with sudo. +# +# This command assumes your ssh configuration is already set up +# in ~/.ssh/config. +# +# Usage: +# cdist config --remote-exec "/path/to/this/script" target_host +# + +host="$1"; shift +ssh -q "$host" sudo "$@" From 6985c1faba74e0e69d18f70eb466ba983974bc77 Mon Sep 17 00:00:00 2001 From: nuex Date: Fri, 7 Jun 2013 21:36:59 -0400 Subject: [PATCH 084/548] fix auto-generating the version file --- build-helper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-helper b/build-helper index 3bbf4dfc..dd0d5d93 100755 --- a/build-helper +++ b/build-helper @@ -300,7 +300,7 @@ eof fi ;; version) - git describe > cdist/version.py + echo "VERSION = \"$(git describe)\"" > cdist/version.py ;; *) From 2acce10497d83dcd7f49d94081bf1f13bda1b548 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 9 Jun 2013 23:45:22 +0200 Subject: [PATCH 085/548] change __start_on_boot to use systemd on archlinux Signed-off-by: Nico Schottelius --- .../conf/type/__start_on_boot/explorer/state | 20 +++++++------------ .../conf/type/__start_on_boot/gencode-remote | 10 +++------- docs/changelog | 1 + 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 6fd0ea92..b156fc82 100755 --- 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 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -29,19 +29,13 @@ name="$__object_id" case "$os" in archlinux) # convert bash array to shell - daemons=$(grep ^DAEMONS /etc/rc.conf | sed -e 's/^.*=(//' -e 's/)$//') + systemctl is-enabled "$name" >/dev/null 2>&1; ret=$? - # absent, as long as not found - state="absent" - - # iterate, last one wins. - for daemon in $daemons; do - if [ "$daemon" = "$name" -o "$daemon" = "@${name}" ]; then - state="present" - elif [ "$daemon" = "!${name}" ]; then - state="absent" - fi - done + if [ "$ret" = 0 ]; then + state="present" + else + state="absent" + fi ;; debian|ubuntu|openwrt) diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 7724e8c7..58ff6a4a 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -32,8 +32,7 @@ case "$state_should" in present) case "$os" in archlinux) - echo "sed 's/^\\(DAEMONS=.*\\))/\\1 $name)/' /etc/rc.conf > /etc/rc.conf.cdist-tmp" - echo "mv /etc/rc.conf.cdist-tmp /etc/rc.conf" + echo "systemctl enable \"$name\"" ;; debian|ubuntu) echo "update-rc.d \"$name\" defaults >/dev/null" @@ -65,10 +64,7 @@ case "$state_should" in absent) case "$os" in archlinux) - # Replace a) at the beginning b) in the middle c) end d) only - # Support @name as well...makes it more ugly, but well... - echo "sed /etc/rc.conf -e 's/^\\(DAEMONS=(\\)@\\{0,1\\}$name /\\1/' -e 's/^\\(DAEMONS=(.* \\)@\\{0,1\\}$name \\(.*\\)/\\1\\2/' -e 's/^\\(DAEMONS=(.*\\) @\\{0,1\\}$name)/\\1)/' -e 's/^\\(DAEMONS=(\\)@\\{0,1\\}$name)/\\1)/' > /etc/rc.conf.cdist-tmp" - echo "mv /etc/rc.conf.cdist-tmp /etc/rc.conf" + echo "systemctl disable \"$name\"" ;; debian|ubuntu) echo update-rc.d -f \"$name\" remove diff --git a/docs/changelog b/docs/changelog index 3b92bd56..ec59b937 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ next: * Build: Change clean-dist target to "distclean" * Change execution order to run object as one unit * Type __apt_ppa: Fix comparison operator (Tyler Akins) + * Type __start_on_boot: Archlinux changed to use systemd - adapt 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From 483cc06211ffa3f44510ba15e07c92594dceb450 Mon Sep 17 00:00:00 2001 From: nuex Date: Mon, 10 Jun 2013 01:27:34 -0400 Subject: [PATCH 086/548] start a shell under sudo to support things like filename globbing --- other/examples/remote/sudo/exec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/examples/remote/sudo/exec b/other/examples/remote/sudo/exec index b4ebe4cf..90eae2da 100755 --- a/other/examples/remote/sudo/exec +++ b/other/examples/remote/sudo/exec @@ -27,4 +27,4 @@ # host="$1"; shift -ssh -q "$host" sudo "$@" +ssh -q "$host" sudo sh -c \""$@"\" From bac593822db61cdfe4b6faabf6f099fecc7eaef8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Jun 2013 08:16:57 +0200 Subject: [PATCH 087/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/changelog b/docs/changelog index ec59b937..ad04d4a4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,11 +5,12 @@ Changelog * Exception: No braces means author == Nico Schottelius next: - * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) * Build: Change clean-dist target to "distclean" - * Change execution order to run object as one unit + * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) + * Core: Change execution order to run object as one unit + * New Remote Example: Add support for sudo operations (James Chase) * Type __apt_ppa: Fix comparison operator (Tyler Akins) - * Type __start_on_boot: Archlinux changed to use systemd - adapt + * Type __start_on_boot: Archlinux changed to use systemd - adapt type 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From b06a77ff8db0f54b25a2a73da5ed838eba15501d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Jun 2013 09:07:28 +0200 Subject: [PATCH 088/548] fixed early in the morning/evening name typo Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index ad04d4a4..13d010cb 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,7 +8,7 @@ next: * Build: Change clean-dist target to "distclean" * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) * Core: Change execution order to run object as one unit - * New Remote Example: Add support for sudo operations (James Chase) + * New Remote Example: Add support for sudo operations (Chase James) * Type __apt_ppa: Fix comparison operator (Tyler Akins) * Type __start_on_boot: Archlinux changed to use systemd - adapt type From 211363d5be5bc9d4847edc2b663528f06ce4fae9 Mon Sep 17 00:00:00 2001 From: nuex Date: Sun, 16 Jun 2013 01:40:11 -0400 Subject: [PATCH 089/548] __git: quote variables in gencode-remote, add optional parameters in manpage --- cdist/conf/type/__git/gencode-remote | 10 +++++----- cdist/conf/type/__git/man.text | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote index bc0c66cc..d719a492 100644 --- a/cdist/conf/type/__git/gencode-remote +++ b/cdist/conf/type/__git/gencode-remote @@ -51,12 +51,12 @@ 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 - echo chown -R ${owner}:${group} ${destination} + 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} + if [ -n "$mode" ]; then + echo chmod -R "$mode" "$destination" fi ;; # Handled in manifest diff --git a/cdist/conf/type/__git/man.text b/cdist/conf/type/__git/man.text index 5597a52d..7c6b83cd 100644 --- a/cdist/conf/type/__git/man.text +++ b/cdist/conf/type/__git/man.text @@ -27,6 +27,15 @@ state:: branch:: Create this branch by checking out the remote branch of this name +group:: + Group to chgrp to. + +mode:: + Unix permissions, suitable for chmod. + +owner:: + User to chown to. + EXAMPLES -------- From 1846175135797772baa42d3902ec7b89eb71cff2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 16 Jun 2013 12:47:58 +0200 Subject: [PATCH 090/548] ++git changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 13d010cb..997eb4a4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -11,6 +11,7 @@ next: * New Remote Example: Add support for sudo operations (Chase James) * Type __apt_ppa: Fix comparison operator (Tyler Akins) * Type __start_on_boot: Archlinux changed to use systemd - adapt type + * Type __git: Missing quotes added (Chase James) 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From dc39099730fbffb47cddffe74d80aaaba919533f Mon Sep 17 00:00:00 2001 From: nuex Date: Mon, 17 Jun 2013 11:05:23 -0400 Subject: [PATCH 091/548] __postgres_role: make state parameter optional, fix password parameter checking in gencode-remote --- cdist/conf/type/__postgres_role/gencode-remote | 3 ++- cdist/conf/type/__postgres_role/man.text | 15 ++++++--------- .../conf/type/__postgres_role/parameter/optional | 1 + .../conf/type/__postgres_role/parameter/required | 1 - 4 files changed, 9 insertions(+), 11 deletions(-) delete mode 100644 cdist/conf/type/__postgres_role/parameter/required diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index c9de4707..8fb2c91d 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -21,13 +21,14 @@ name="$__object_id" state_is="$(cat "$__object/explorer/state")" state_should="$(cat "$__object/parameter/state")" +[ ! "$state_should" ] && state_should="present" [ "$state_is" = "$state_should" ] && exit 0 case "$state_should" in present) if [ -f "$__object/parameter/password" ]; then - password="$(cat "$__object/parameter/$parameter")" + password="$(cat "$__object/parameter/password")" fi booleans="" for boolean in login createdb createrole superuser; do diff --git a/cdist/conf/type/__postgres_role/man.text b/cdist/conf/type/__postgres_role/man.text index 904f0831..ac87754b 100644 --- a/cdist/conf/type/__postgres_role/man.text +++ b/cdist/conf/type/__postgres_role/man.text @@ -13,15 +13,12 @@ DESCRIPTION This cdist type allows you to create or drop postgres roles. -REQUIRED PARAMETERS +OPTIONAL PARAMETERS ------------------- state:: Either "present" or "absent", defaults to "present" - -OPTIONAL PARAMETERS -------------------- -All parameter map directly to the corresponding postgres createrole +All other parameters map directly to the corresponding postgres createrole parameters. password:: @@ -41,13 +38,13 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -__postgres_role myrole --state present +__postgres_role myrole -__postgres_role myrole --state present --password 'secret' +__postgres_role myrole --password 'secret' -__postgres_role admin --state present --password 'very-secret' --superuser +__postgres_role admin --password 'very-secret' --superuser -__postgres_role dbcustomer --state present --password 'bla' --createdb +__postgres_role dbcustomer --password 'bla' --createdb -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__postgres_role/parameter/optional b/cdist/conf/type/__postgres_role/parameter/optional index f3097ab1..cb9b2c48 100644 --- a/cdist/conf/type/__postgres_role/parameter/optional +++ b/cdist/conf/type/__postgres_role/parameter/optional @@ -1 +1,2 @@ +state password diff --git a/cdist/conf/type/__postgres_role/parameter/required b/cdist/conf/type/__postgres_role/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/cdist/conf/type/__postgres_role/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state From 48b6344645edd77c4bb836521eb8026f5797099f Mon Sep 17 00:00:00 2001 From: nuex Date: Mon, 17 Jun 2013 11:16:26 -0400 Subject: [PATCH 092/548] __postgres_role: check if state parameter exists before reading it --- 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 8fb2c91d..65a9d588 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -20,8 +20,8 @@ name="$__object_id" state_is="$(cat "$__object/explorer/state")" -state_should="$(cat "$__object/parameter/state")" -[ ! "$state_should" ] && state_should="present" +state_should="present" +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" [ "$state_is" = "$state_should" ] && exit 0 From 90f7ec40fe812c47a81c27d8b4d18f6a7c39a857 Mon Sep 17 00:00:00 2001 From: nuex Date: Mon, 17 Jun 2013 12:10:19 -0400 Subject: [PATCH 093/548] __postgres_database: make state parameter optional --- cdist/conf/type/__postgres_database/gencode-remote | 3 ++- cdist/conf/type/__postgres_database/man.text | 7 ++----- cdist/conf/type/__postgres_database/parameter/optional | 1 + cdist/conf/type/__postgres_database/parameter/required | 1 - 4 files changed, 5 insertions(+), 7 deletions(-) delete mode 100644 cdist/conf/type/__postgres_database/parameter/required diff --git a/cdist/conf/type/__postgres_database/gencode-remote b/cdist/conf/type/__postgres_database/gencode-remote index c097efce..0ffc842a 100755 --- a/cdist/conf/type/__postgres_database/gencode-remote +++ b/cdist/conf/type/__postgres_database/gencode-remote @@ -19,7 +19,8 @@ # name="$__object_id" -state_should="$(cat "$__object/parameter/state")" +state_should="present" +[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" if [ "$state_should" != "$state_is" ]; then diff --git a/cdist/conf/type/__postgres_database/man.text b/cdist/conf/type/__postgres_database/man.text index d01ca8f6..88259b6f 100644 --- a/cdist/conf/type/__postgres_database/man.text +++ b/cdist/conf/type/__postgres_database/man.text @@ -13,14 +13,11 @@ DESCRIPTION This cdist type allows you to create or drop postgres databases. -REQUIRED PARAMETERS +OPTIONAL PARAMETERS ------------------- state:: either 'present' or 'absent' - -OPTIONAL PARAMETERS -------------------- owner:: the role owning this database @@ -29,7 +26,7 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -__postgres_database mydbname --state present --owner mydbusername +__postgres_database mydbname --owner mydbusername -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__postgres_database/parameter/optional b/cdist/conf/type/__postgres_database/parameter/optional index 7ee3bde8..d86b6469 100644 --- a/cdist/conf/type/__postgres_database/parameter/optional +++ b/cdist/conf/type/__postgres_database/parameter/optional @@ -1 +1,2 @@ +state owner diff --git a/cdist/conf/type/__postgres_database/parameter/required b/cdist/conf/type/__postgres_database/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/cdist/conf/type/__postgres_database/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state From 8d3639db50c1f9b843e9789f0f5bee50bde6a84e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Jun 2013 13:27:33 +0200 Subject: [PATCH 094/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 997eb4a4..cba79dcc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -12,6 +12,7 @@ next: * Type __apt_ppa: Fix comparison operator (Tyler Akins) * Type __start_on_boot: Archlinux changed to use systemd - adapt type * Type __git: Missing quotes added (Chase James) + * Type __postgres_database: Make state parameter optional (Chase James) 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From bc4af64a75b621bc0afb7b12290c298490e5cec7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 18 Jun 2013 14:48:36 +0200 Subject: [PATCH 095/548] even more changes - time for a release soon Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index cba79dcc..b97d3ace 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,7 @@ next: * Type __start_on_boot: Archlinux changed to use systemd - adapt type * Type __git: Missing quotes added (Chase James) * Type __postgres_database: Make state parameter optional (Chase James) + * Type __postgres_role: Make state parameter optional, fix password bug (Chase James) 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From 1c94c615b1de13fe6ac3cdafd01194a5a3d594d0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Jun 2013 10:55:07 +0200 Subject: [PATCH 096/548] __cron: remove parameter changing code, remove multiline code, remove early execution of included $() code, simplify __cron Signed-off-by: Nico Schottelius --- cdist/conf/type/__cron/explorer/entry | 20 +------ cdist/conf/type/__cron/gencode-remote | 79 ++++++++++++++------------- cdist/conf/type/__cron/manifest | 45 --------------- 3 files changed, 43 insertions(+), 101 deletions(-) delete mode 100755 cdist/conf/type/__cron/manifest diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry index 9b52d6e4..c3bf02d2 100755 --- a/cdist/conf/type/__cron/explorer/entry +++ b/cdist/conf/type/__cron/explorer/entry @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) +# 2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,22 +19,7 @@ # along with cdist. If not, see . # -name="$__object_id" +name="$__object_name" user="$(cat "$__object/parameter/user")" -prefix="#cdist:__cron/$name" -suffix="#/cdist:__cron/$name" - -crontab -u $user -l 2>/dev/null | awk -v prefix="$prefix" -v suffix="$suffix" ' -{ - if (index($0,prefix)) { - triggered=1 - } - if (triggered) { - if (index($0,suffix)) { - triggered=0 - } - print - } -} -' +crontab -u $user -l 2>/dev/null | grep "# $name\$" || true diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index af06edb3..e1ac5ef9 100755 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,45 +19,45 @@ # along with cdist. If not, see . # +name="$__object_name" user="$(cat "$__object/parameter/user")" -state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" -state_is=$(diff -q "$__object/parameter/entry" "$__object/explorer/entry" \ - && echo present \ - || echo absent -) +command="$(cat "$__object/parameter/command")" -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - cat << DONE -( -crontab -u $user -l || true -cat << EOC -$(cat "$__object/parameter/entry") -EOC -) | crontab -u $user - -DONE - ;; - absent) - # NOTE: keep variables in sync in manifest/explorer/gencode-* - prefix="#cdist:__cron/$name" - suffix="#/cdist:__cron/$name" - cat << DONE -crontab -u $user -l | awk -v prefix="$prefix" -v suffix="$suffix" ' -{ - if (index(\$0,prefix)) { - triggered=1 - } - if (triggered) { - if (index(\$0,suffix)) { - triggered=0 - } - } else { - print - } -} -' | crontab -u $user - -DONE - ;; - esac +if [ -f "$__object/parameter/raw" ]; then + raw="$(cat "$__object/parameter/raw")" + entry="$raw $command" +else + minute="$(cat "$__object/parameter/minute" 2>/dev/null || echo "*")" + hour="$(cat "$__object/parameter/hour" 2>/dev/null || echo "*")" + 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" fi + +entry="$entry # $name" +mkdir "$__object/files" +echo "$entry" > "$__object/files/entry" + +if diff -q "$__object/files/entry" "$__object/explorer/entry" >/dev/null; then + state_is=present +else + state_is=absent +fi + +state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" + +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + echo "(" + echo "crontab -u $user -l 2>/dev/null || true" + echo "echo '$entry'" + echo ") | crontab -u $user -" + ;; + absent) + echo "( crontab -u $user -l 2>/dev/null || true ) | \\" + echo "grep -v \"# $name\\$\" | crontab -u $user -" + ;; +esac diff --git a/cdist/conf/type/__cron/manifest b/cdist/conf/type/__cron/manifest deleted file mode 100755 index 71910bf5..00000000 --- a/cdist/conf/type/__cron/manifest +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# -# 2011-2013 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" -user="$(cat "$__object/parameter/user")" -command="$(cat "$__object/parameter/command")" -state="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" - -if [ -f "$__object/parameter/raw" ]; then - raw="$(cat "$__object/parameter/raw")" - entry="$raw $command" -else - minute="$(cat "$__object/parameter/minute" 2>/dev/null || echo "*")" - hour="$(cat "$__object/parameter/hour" 2>/dev/null || echo "*")" - 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" -fi - -# NOTE: keep variables in sync in manifest/explorer/gencode-* -prefix="#cdist:__cron/$name" -suffix="#/cdist:__cron/$name" -cat >> "$__object/parameter/entry" << DONE -"$prefix" -"$entry" -"$suffix" -DONE From 135499f120f8e4b538381c56732486815fa3904c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Jun 2013 11:19:45 +0200 Subject: [PATCH 097/548] __process: make --state optional Signed-off-by: Nico Schottelius --- cdist/conf/type/__process/gencode-remote | 7 ++++++- cdist/conf/type/__process/man.text | 5 +---- cdist/conf/type/__process/parameter/optional | 1 + cdist/conf/type/__process/parameter/required | 1 - 4 files changed, 8 insertions(+), 6 deletions(-) delete mode 100644 cdist/conf/type/__process/parameter/required diff --git a/cdist/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote index fdb6033a..f178f706 100755 --- a/cdist/conf/type/__process/gencode-remote +++ b/cdist/conf/type/__process/gencode-remote @@ -25,7 +25,12 @@ else name="$__object_id" fi -state_should="$(cat "$__object/parameter/state")" +parameter_state="$__object/parameter/state" +if [ -f "$_parameter_state" ]; then + state_should=(cat "$__object/parameter/state") +else + state_should="present" +fi runs="$(cat "$__object/explorer/runs")" if [ "$runs" ]; then diff --git a/cdist/conf/type/__process/man.text b/cdist/conf/type/__process/man.text index 0d457ead..2fdd27aa 100644 --- a/cdist/conf/type/__process/man.text +++ b/cdist/conf/type/__process/man.text @@ -13,14 +13,11 @@ DESCRIPTION This cdist type allows you to define the state of a process. -REQUIRED PARAMETERS +OPTIONAL PARAMETERS ------------------- state:: Either "present" or "absent", defaults to "present" - -OPTIONAL PARAMETERS -------------------- name:: Process name to match on when using pgrep -f -x. diff --git a/cdist/conf/type/__process/parameter/optional b/cdist/conf/type/__process/parameter/optional index 3411afb4..85fe8805 100644 --- a/cdist/conf/type/__process/parameter/optional +++ b/cdist/conf/type/__process/parameter/optional @@ -1,3 +1,4 @@ name stop start +state diff --git a/cdist/conf/type/__process/parameter/required b/cdist/conf/type/__process/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/cdist/conf/type/__process/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state From a1b946abc44d6914f8ad45a2a1eaacac75b94d12 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Jun 2013 11:20:18 +0200 Subject: [PATCH 098/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index b97d3ace..3f9defee 100644 --- a/docs/changelog +++ b/docs/changelog @@ -14,6 +14,7 @@ next: * Type __git: Missing quotes added (Chase James) * Type __postgres_database: Make state parameter optional (Chase James) * Type __postgres_role: Make state parameter optional, fix password bug (Chase James) + * Type __process: Make state parameter optional 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From 4ecffa7d5999e63a40256b0a515eb82ca198ceef Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Jun 2013 11:31:21 +0200 Subject: [PATCH 099/548] fix typo in __process Signed-off-by: Nico Schottelius --- cdist/conf/type/__process/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote index f178f706..41bc5381 100755 --- a/cdist/conf/type/__process/gencode-remote +++ b/cdist/conf/type/__process/gencode-remote @@ -27,7 +27,7 @@ fi parameter_state="$__object/parameter/state" if [ -f "$_parameter_state" ]; then - state_should=(cat "$__object/parameter/state") + state_should=$(cat "$__object/parameter/state") else state_should="present" fi From 84f2ca0d1f59f3f2157d4350de65800a0a759459 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Jun 2013 18:49:43 +0200 Subject: [PATCH 100/548] add new type: __update_alternatives Signed-off-by: Nico Schottelius --- .../type/__update_alternatives/gencode-remote | 26 +++++++++++ .../conf/type/__update_alternatives/man.text | 43 +++++++++++++++++++ .../__update_alternatives/parameter/required | 1 + 3 files changed, 70 insertions(+) create mode 100755 cdist/conf/type/__update_alternatives/gencode-remote create mode 100644 cdist/conf/type/__update_alternatives/man.text create mode 100644 cdist/conf/type/__update_alternatives/parameter/required diff --git a/cdist/conf/type/__update_alternatives/gencode-remote b/cdist/conf/type/__update_alternatives/gencode-remote new file mode 100755 index 00000000..51c0a7f4 --- /dev/null +++ b/cdist/conf/type/__update_alternatives/gencode-remote @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 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 . +# +# +# Setup alternative - no standard way to create, always set +# + +path="$(cat "$__object/parameter/path")" +name="$__object_id" +echo "update-alternatives --set '$name' '$path'" diff --git a/cdist/conf/type/__update_alternatives/man.text b/cdist/conf/type/__update_alternatives/man.text new file mode 100644 index 00000000..2bcc1874 --- /dev/null +++ b/cdist/conf/type/__update_alternatives/man.text @@ -0,0 +1,43 @@ +cdist-type__update_alternatives(7) +================================== +Nico Schottelius + + +NAME +---- +cdist-type__update_alternatives - Configure alternatives + + +DESCRIPTION +----------- +On Debian and alike systems update-alternatives(1) can be used +to setup alternatives for various programs. +One of the most common used targets is the "editor". + + +REQUIRED PARAMETERS +------------------- +path:: + Use this path for the given alternative + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# 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) +- update-alternatives(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/__update_alternatives/parameter/required b/cdist/conf/type/__update_alternatives/parameter/required new file mode 100644 index 00000000..e7a8fd4d --- /dev/null +++ b/cdist/conf/type/__update_alternatives/parameter/required @@ -0,0 +1 @@ +path From 622cd398c6d8a0d7cb0e81aebb0997561028ea9e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Jun 2013 18:51:23 +0200 Subject: [PATCH 101/548] use quiet mode by default Signed-off-by: Nico Schottelius --- cdist/conf/type/__update_alternatives/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__update_alternatives/gencode-remote b/cdist/conf/type/__update_alternatives/gencode-remote index 51c0a7f4..19ea9968 100755 --- a/cdist/conf/type/__update_alternatives/gencode-remote +++ b/cdist/conf/type/__update_alternatives/gencode-remote @@ -23,4 +23,4 @@ path="$(cat "$__object/parameter/path")" name="$__object_id" -echo "update-alternatives --set '$name' '$path'" +echo "update-alternatives --quiet --set '$name' '$path'" From af1f7a9241eaacee1df1abb69cb3d4415a78287b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Jun 2013 18:52:12 +0200 Subject: [PATCH 102/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 3f9defee..e44bc50a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -15,6 +15,7 @@ next: * Type __postgres_database: Make state parameter optional (Chase James) * Type __postgres_role: Make state parameter optional, fix password bug (Chase James) * Type __process: Make state parameter optional + * New Type: __update_alternatives 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From e7527802a5e64c08c73ab0d87096a2dc38b9e005 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 19 Jun 2013 18:53:07 +0200 Subject: [PATCH 103/548] more hints for __debconf_set_selections Signed-off-by: Nico Schottelius --- cdist/conf/type/__debconf_set_selections/man.text | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__debconf_set_selections/man.text b/cdist/conf/type/__debconf_set_selections/man.text index b6b2ad18..f1e13a8e 100644 --- a/cdist/conf/type/__debconf_set_selections/man.text +++ b/cdist/conf/type/__debconf_set_selections/man.text @@ -17,7 +17,7 @@ to setup configuration parameters. REQUIRED PARAMETERS ------------------- file:: - If supplied, use the given filename as input for debconf-set-selections(1) + Use the given filename as input for debconf-set-selections(1) EXAMPLES @@ -35,9 +35,11 @@ __debconf_set_selections nslcd --file "$__type/files/preseed/nslcd" SEE ALSO -------- - cdist-type(7) +- cdist-type__update_alternatives(7) +- debconf-set-selections(1) COPYING ------- -Copyright \(C) 2011 Nico Schottelius. Free use of this software is +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). From 4ae241259f620d30bee656fca1f44d67d08e50d0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Jun 2013 09:20:14 +0200 Subject: [PATCH 104/548] remove the old entries on change Signed-off-by: Nico Schottelius --- cdist/conf/type/__cron/gencode-remote | 23 +++++++++++++++++++++++ docs/changelog.2.2 | 10 ++++++++++ 2 files changed, 33 insertions(+) create mode 100644 docs/changelog.2.2 diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index e1ac5ef9..c04a7245 100755 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -49,6 +49,29 @@ state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" [ "$state_is" = "$state_should" ] && exit 0 +# If anything is going to change, ensure the old entries are +# not present anymore + +# These are the old markers +prefix="#cdist:__cron/$__object_id" +suffix="#/cdist:__cron/$__object_id" +cat << DONE +crontab -u $user -l | awk -v prefix="$prefix" -v suffix="$suffix" ' +{ + if (index(\$0,prefix)) { + triggered=1 + } + if (triggered) { + if (index(\$0,suffix)) { + triggered=0 + } + } else { + print + } +} +' | crontab -u $user - +DONE + case "$state_should" in present) echo "(" diff --git a/docs/changelog.2.2 b/docs/changelog.2.2 new file mode 100644 index 00000000..25f926c2 --- /dev/null +++ b/docs/changelog.2.2 @@ -0,0 +1,10 @@ +Changelog +--------- + + * Changes are always commented with their author in (braces) + * Exception: No braces means author == Nico Schottelius + +2.2.0: + * Type __cron: Dropped support for old internal format + Using this version prior to running cdist 2.1.2 will + break add the cron entries twice. From 9b92822b4bb12087c661fc26cf30e55eb3989776 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Jun 2013 09:20:27 +0200 Subject: [PATCH 105/548] record change for __cron in changelog Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e44bc50a..47edeed3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -15,6 +15,7 @@ next: * Type __postgres_database: Make state parameter optional (Chase James) * Type __postgres_role: Make state parameter optional, fix password bug (Chase James) * Type __process: Make state parameter optional + * Type __cron: Simplyfied and syntax change * New Type: __update_alternatives 2.1.1: 2013-04-08 From 5fb66cd3148541dc1990306f030a82c42ce24340 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Jun 2013 09:22:17 +0200 Subject: [PATCH 106/548] move build-helper into bin/ Signed-off-by: Nico Schottelius --- Makefile | 2 +- build-helper => bin/build-helper | 0 bin/cdist | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename build-helper => bin/build-helper (100%) diff --git a/Makefile b/Makefile index cf83a591..dac24394 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ A2XM=a2x -f manpage --no-xmllint -a encoding=UTF-8 A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 -helper=./build-helper +helper=./bin/build-helper MANDIR=docs/man MAN1DSTDIR=$(MANDIR)/man1 diff --git a/build-helper b/bin/build-helper similarity index 100% rename from build-helper rename to bin/build-helper diff --git a/bin/cdist b/bin/cdist index f8fec000..645020a1 100755 --- a/bin/cdist +++ b/bin/cdist @@ -25,7 +25,7 @@ dir=${0%/*} # Ensure version is present - the bundled/shipped version contains a static version, # the git version contains a dynamic version -"$dir/../build-helper" version +"$dir/build-helper" version libdir=$(cd "${dir}/../" && pwd -P) export PYTHONPATH="${libdir}" From e569e0546acd06ae67aad92fa1c7f1a380807508 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Jun 2013 09:24:05 +0200 Subject: [PATCH 107/548] adjust build helper to jump into the right directory Signed-off-by: Nico Schottelius --- bin/build-helper | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index dd0d5d93..c1c65676 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -21,8 +21,11 @@ # This file contains the heavy lifting found usually in the Makefile # -basedir=${0%/*} -version=$(cd "$basedir" && git describe) +basedir=${0%/*}/../ +# Change to checkout directory +cd "$basedir" + +version=$(git describe) # Manpage and HTML A2XM="a2x -f manpage --no-xmllint -a encoding=UTF-8" @@ -42,9 +45,6 @@ MAN1DSTDIR=${MANDIR}/man1 MAN7DSTDIR=${MANDIR}/man7 SPEECHESDIR=docs/speeches -# Change to checkout directory -cd "$basedir" - case "$1" in manbuild) trap abort INT From c5c5e7b89b638f119ed0bc3408e34ffd3479e0a8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Jun 2013 11:17:30 +0200 Subject: [PATCH 108/548] remove requirement-finder tests - no need to test assignments and no wildcard support anymore Signed-off-by: Nico Schottelius --- cdist/test/execution_order/__init__.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/cdist/test/execution_order/__init__.py b/cdist/test/execution_order/__init__.py index d9804833..785b7ba8 100644 --- a/cdist/test/execution_order/__init__.py +++ b/cdist/test/execution_order/__init__.py @@ -31,7 +31,6 @@ from cdist.exec import local from cdist.core import manifest import cdist.context - import os.path as op my_dir = op.abspath(op.dirname(__file__)) fixtures = op.join(my_dir, 'fixtures') @@ -50,25 +49,6 @@ class ResolverTestCase(test.CdistTestCase): for o in self.objects: o.requirements = [] - def test_find_requirements_by_name_string(self): - requirements = ['__first/man', '__second/on-the', '__third/moon'] - required_objects = [self.object_index[name] for name in requirements] - # self.assertEqual(sorted(list(self.dependency_resolver.find_requirements_by_name(requirements))), - # sorted(required_objects)) - self.assertTrue(False) - - def test_find_requirements_by_name_pattern(self): - requirements = ['__first/*', '__second/*-the', '__third/moon'] - requirements_expanded = [ - '__first/child', '__first/dog', '__first/man', '__first/woman', - '__second/on-the', '__second/under-the', - '__third/moon' - ] - required_objects = [self.object_index[name] for name in requirements_expanded] - self.assertEqual(sorted(list(self.dependency_resolver.find_requirements_by_name(requirements))), - sorted(required_objects)) - self.assertTrue(False) - def test_dependency_resolution(self): first_man = self.object_index['__first/man'] second_on_the = self.object_index['__second/on-the'] From b2686f3b131cc7e2f44d3ea081401bc6896b989e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Jun 2013 11:24:47 +0200 Subject: [PATCH 109/548] factor out iterate code to be able to test it for one, two, ... runs Signed-off-by: Nico Schottelius --- cdist/config_install.py | 55 +++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 43bfb7e4..baf76f0a 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -75,32 +75,45 @@ class ConfigInstall(object): self.context.local.type_path): yield cdist_object + def iterate_once(self): + """ + Iterate over the objects once - helper method for + iterate_until_finished + """ + 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_until_finished(self): - # Continue process until no new objects are created anymore + """ + Go through all objects and solve them + one after another + """ objects_changed = True while objects_changed: - 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 + objects_changed = self.iterate_once() # Check whether all objects have been finished unfinished_objects = [] From b1d661f4c03d5475ea418007427e12424c888a5f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 20 Jun 2013 11:30:20 +0200 Subject: [PATCH 110/548] merge ResolverTestCase and AutorequireTestCase into ExecutionOrderTestCase Signed-off-by: Nico Schottelius --- cdist/test/execution_order/__init__.py | 81 +++++++++++++------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/cdist/test/execution_order/__init__.py b/cdist/test/execution_order/__init__.py index 785b7ba8..5457e7dc 100644 --- a/cdist/test/execution_order/__init__.py +++ b/cdist/test/execution_order/__init__.py @@ -39,46 +39,7 @@ type_base_path = op.join(fixtures, 'type') add_conf_dir = op.join(fixtures, 'conf') -class ResolverTestCase(test.CdistTestCase): - - def setUp(self): - self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) - self.object_index = dict((o.name, o) for o in self.objects) - - def tearDown(self): - for o in self.objects: - o.requirements = [] - - def test_dependency_resolution(self): - first_man = self.object_index['__first/man'] - second_on_the = self.object_index['__second/on-the'] - third_moon = self.object_index['__third/moon'] - first_man.requirements = [second_on_the.name] - second_on_the.requirements = [third_moon.name] - self.assertEqual( - self.dependency_resolver.dependencies['__first/man'], - [third_moon, second_on_the, first_man] - ) - self.assertTrue(False) - - def test_circular_reference(self): - first_man = self.object_index['__first/man'] - first_woman = self.object_index['__first/woman'] - first_man.requirements = [first_woman.name] - first_woman.requirements = [first_man.name] - with self.assertRaises(resolver.CircularReferenceError): - self.dependency_resolver.dependencies - self.assertTrue(False) - - def test_requirement_not_found(self): - first_man = self.object_index['__first/man'] - first_man.requirements = ['__does/not/exist'] - with self.assertRaises(cdist.Error): - self.dependency_resolver.dependencies - self.assertTrue(False) - -class AutorequireTestCase(test.CdistTestCase): - +class ExecutionOrderTestCase(test.CdistTestCase): def setUp(self): self.orig_environ = os.environ os.environ = os.environ.copy() @@ -100,10 +61,50 @@ class AutorequireTestCase(test.CdistTestCase): self.config = config.Config(self.context) + self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) + self.object_index = dict((o.name, o) for o in self.objects) + def tearDown(self): os.environ = self.orig_environ shutil.rmtree(self.temp_dir) + for o in self.objects: + o.requirements = [] + + def test_dependency_resolution(self): + """Check that the runtime respects the right order""" + first_man = self.object_index['__first/man'] + second_on_the = self.object_index['__second/on-the'] + third_moon = self.object_index['__third/moon'] + + first_man.requirements = [second_on_the.name] + second_on_the.requirements = [third_moon.name] + + self.config.iterate_once() + + + self.assertEqual( + self.dependency_resolver.dependencies['__first/man'], + [third_moon, second_on_the, first_man] + ) + self.assertTrue(False) + + def test_circular_reference(self): + first_man = self.object_index['__first/man'] + first_woman = self.object_index['__first/woman'] + first_man.requirements = [first_woman.name] + first_woman.requirements = [first_man.name] + with self.assertRaises(resolver.CircularReferenceError): + self.dependency_resolver.dependencies + self.assertTrue(False) + + def test_requirement_not_found(self): + first_man = self.object_index['__first/man'] + first_man.requirements = ['__does/not/exist'] + with self.assertRaises(cdist.Error): + self.dependency_resolver.dependencies + self.assertTrue(False) + def test_implicit_dependencies(self): self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'implicit_dependencies') self.config.stage_prepare() From 347ff8900e769a69638fa2d9d0def85b809046e9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Jun 2013 16:35:19 +0200 Subject: [PATCH 111/548] split directory creating code off of init Signed-off-by: Nico Schottelius --- cdist/config_install.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index baf76f0a..146097d9 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -37,11 +37,6 @@ class ConfigInstall(object): self.context = context self.log = logging.getLogger(self.context.target_host) - # Initialise local directory structure - self.context.local.create_files_dirs() - # Initialise remote directory structure - self.context.remote.create_files_dirs() - self.explorer = core.Explorer(self.context.target_host, self.context.local, self.context.remote) self.manifest = core.Manifest(self.context.target_host, self.context.local) self.code = core.Code(self.context.target_host, self.context.local, self.context.remote) @@ -57,10 +52,17 @@ class ConfigInstall(object): shutil.rmtree(destination) shutil.move(self.context.local.out_path, destination) + def _init_files_dirs(self): + """Prepare files and directories for the run""" + self.context.local.create_files_dirs() + self.context.remote.create_files_dirs() + def run(self): """Do what is most often done: deploy & cleanup""" start_time = time.time() + self._init_files_dirs() + self.explorer.run_global_explorers(self.context.local.global_explorer_out_path) self.manifest.run_initial_manifest(self.context.initial_manifest) self.iterate_until_finished() From 4758daa0377324156e956ab68c97c4061e19c310 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Jun 2013 16:38:50 +0200 Subject: [PATCH 112/548] move types into conf/ dir Signed-off-by: Nico Schottelius --- cdist/test/execution_order/fixtures/{ => conf}/type/__first/.keep | 0 .../test/execution_order/fixtures/{ => conf}/type/__second/.keep | 0 cdist/test/execution_order/fixtures/{ => conf}/type/__third/.keep | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename cdist/test/execution_order/fixtures/{ => conf}/type/__first/.keep (100%) rename cdist/test/execution_order/fixtures/{ => conf}/type/__second/.keep (100%) rename cdist/test/execution_order/fixtures/{ => conf}/type/__third/.keep (100%) diff --git a/cdist/test/execution_order/fixtures/type/__first/.keep b/cdist/test/execution_order/fixtures/conf/type/__first/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/type/__first/.keep rename to cdist/test/execution_order/fixtures/conf/type/__first/.keep diff --git a/cdist/test/execution_order/fixtures/type/__second/.keep b/cdist/test/execution_order/fixtures/conf/type/__second/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/type/__second/.keep rename to cdist/test/execution_order/fixtures/conf/type/__second/.keep diff --git a/cdist/test/execution_order/fixtures/type/__third/.keep b/cdist/test/execution_order/fixtures/conf/type/__third/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/type/__third/.keep rename to cdist/test/execution_order/fixtures/conf/type/__third/.keep From 14a3bf72628485362da4684eb966f2718c442bab Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Jun 2013 16:52:56 +0200 Subject: [PATCH 113/548] move save_cache into local Signed-off-by: Nico Schottelius --- cdist/config_install.py | 5 ++--- cdist/exec/local.py | 8 ++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 146097d9..b34e8a84 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -44,8 +44,7 @@ class ConfigInstall(object): # Add switch to disable code execution self.dry_run = False - def cleanup(self): - # FIXME: move to local? + def save_cache(self): destination = os.path.join(self.context.local.cache_path, self.context.target_host) self.log.debug("Saving " + self.context.local.out_path + " to " + destination) if os.path.exists(destination): @@ -67,7 +66,7 @@ class ConfigInstall(object): self.manifest.run_initial_manifest(self.context.initial_manifest) self.iterate_until_finished() - self.cleanup() + self.context.local.save_cache() 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 7f640411..693830eb 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -160,6 +160,14 @@ class Local(object): self._create_conf_path_and_link_conf_dirs() self._link_types_for_emulator() + def save_cache(self): + destination = os.path.join(self.local.cache_path, self.target_host) + self.log.debug("Saving " + self.out_path + " to " + destination) + if os.path.exists(destination): + shutil.rmtree(destination) + shutil.move(self.out_path, destination) + + def _create_context_dirs(self): self.mkdir(self.out_path) From 4ec1afc47f6a342aca3b2b61ecd3e0bd97e1fe65 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Jun 2013 16:55:54 +0200 Subject: [PATCH 114/548] also remove obsolete save_cache function Signed-off-by: Nico Schottelius --- cdist/config_install.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index b34e8a84..e5d2de87 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -44,13 +44,6 @@ class ConfigInstall(object): # Add switch to disable code execution self.dry_run = False - def save_cache(self): - destination = os.path.join(self.context.local.cache_path, self.context.target_host) - self.log.debug("Saving " + self.context.local.out_path + " to " + destination) - if os.path.exists(destination): - shutil.rmtree(destination) - shutil.move(self.context.local.out_path, destination) - def _init_files_dirs(self): """Prepare files and directories for the run""" self.context.local.create_files_dirs() From e1d8645415b07af778aac1d535d1601694686318 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Jun 2013 21:48:15 +0200 Subject: [PATCH 115/548] fix unit tests for config_install Signed-off-by: Nico Schottelius --- cdist/config_install.py | 10 ++++------ cdist/test/config_install/__init__.py | 18 +++++++----------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index e5d2de87..db7e3792 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -32,17 +32,15 @@ from cdist import core class ConfigInstall(object): """Cdist main class to hold arbitrary data""" - def __init__(self, context): + def __init__(self, context, dry_run=False): self.context = context - self.log = logging.getLogger(self.context.target_host) + self.log = logging.getLogger(self.context.target_host) + self.dry_run = dry_run self.explorer = core.Explorer(self.context.target_host, self.context.local, self.context.remote) self.manifest = core.Manifest(self.context.target_host, self.context.local) - self.code = core.Code(self.context.target_host, self.context.local, self.context.remote) - - # Add switch to disable code execution - self.dry_run = False + self.code = core.Code(self.context.target_host, self.context.local, self.context.remote) def _init_files_dirs(self): """Prepare files and directories for the run""" diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py index 2abf7614..83f65575 100644 --- a/cdist/test/config_install/__init__.py +++ b/cdist/test/config_install/__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-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -59,8 +59,8 @@ class ConfigInstallRunTestCase(test.CdistTestCase): exec_path=test.cdist_exec_path, debug=True) - self.context.local.object_path = object_base_path - self.context.local.type_path = type_base_path + self.context.local.object_path = object_base_path + self.context.local.type_path = type_base_path self.config = cdist.config.Config(self.context) @@ -86,15 +86,15 @@ class ConfigInstallRunTestCase(test.CdistTestCase): # First run: # solves first and maybe second (depending on the order in the set) - self.config.stage_run_iterate() + self.config.iterate_once() self.assertTrue(third.state == third.STATE_DONE) - self.config.stage_run_iterate() + self.config.iterate_once() self.assertTrue(second.state == second.STATE_DONE) try: - self.config.stage_run_iterate() + self.config.iterate_once() except cdist.Error: # Allow failing, because the third run may or may not be unecessary already, # depending on the order of the objects @@ -111,9 +111,5 @@ class ConfigInstallRunTestCase(test.CdistTestCase): first.requirements = [second.name] second.requirements = [first.name] - # First round solves __third/moon - self.config.stage_run_iterate() - - # Second round detects it cannot solve the rest with self.assertRaises(cdist.Error): - self.config.stage_run_iterate() + self.config.iterate_until_finished() From ef24ec4db84e10f6dc3cf7bd86c078ae67e41f30 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Jun 2013 21:50:21 +0200 Subject: [PATCH 116/548] port test_missing_requirements to config_install unit test Signed-off-by: Nico Schottelius --- cdist/test/config_install/__init__.py | 6 ++ cdist/test/execution_order/__init__.py | 95 +++++++++++--------------- 2 files changed, 44 insertions(+), 57 deletions(-) diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py index 83f65575..fab31cc9 100644 --- a/cdist/test/config_install/__init__.py +++ b/cdist/test/config_install/__init__.py @@ -113,3 +113,9 @@ class ConfigInstallRunTestCase(test.CdistTestCase): with self.assertRaises(cdist.Error): self.config.iterate_until_finished() + + def test_missing_requirements(self): + first = self.object_index['__first/man'] + first.requirements = ['__does/not/exist'] + with self.assertRaises(cdist.Error): + self.config.iterate_until_finished() diff --git a/cdist/test/execution_order/__init__.py b/cdist/test/execution_order/__init__.py index 5457e7dc..604000a2 100644 --- a/cdist/test/execution_order/__init__.py +++ b/cdist/test/execution_order/__init__.py @@ -34,77 +34,58 @@ import cdist.context 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') +object_base_path = op.join(fixtures, 'object') +add_conf_dir = op.join(fixtures, 'conf') +type_base_path = op.join(add_conf_dir, 'type') + +class MockContext(object): + """A context object that has the required attributes""" + def __init__(self, target_host): + self.target_host = target_host + self.local = False + +class MockLocal(object): + def __init__(self, temp_dir, type_path): + self.temp_dir = temp_dir + self.object_path = op.join(self.temp_dir, "object") + self.type_path = type_path class ExecutionOrderTestCase(test.CdistTestCase): def setUp(self): - self.orig_environ = os.environ - os.environ = os.environ.copy() + # self.orig_environ = os.environ + # os.environ = os.environ.copy() + # os.environ['__cdist_out_dir'] = self.out_dir + # os.environ['__cdist_remote_out_dir'] = self.remote_out_dir + # self.out_dir = os.path.join(self.temp_dir, "out") + # self.remote_out_dir = os.path.join(self.temp_dir, "remote") + self.temp_dir = self.mkdtemp() - self.out_dir = os.path.join(self.temp_dir, "out") - self.remote_out_dir = os.path.join(self.temp_dir, "remote") - - os.environ['__cdist_out_dir'] = self.out_dir - os.environ['__cdist_remote_out_dir'] = self.remote_out_dir - - self.context = cdist.context.Context( - target_host=self.target_host, - remote_copy=self.remote_copy, - remote_exec=self.remote_exec, - add_conf_dirs=[add_conf_dir], - exec_path=test.cdist_exec_path, - debug=False) - + self.context = MockContext(self.target_host) + self.context.local = MockLocal(self.temp_dir, type_base_path) self.config = config.Config(self.context) - self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) + self._init_objects() + + def _init_objects(self): + """copy base objects to context directory""" + shutil.copytree(object_base_path, self.context.local.object_path) + self.objects = list(core.CdistObject.list_objects(self.context.local.object_path, self.context.local.type_path)) self.object_index = dict((o.name, o) for o in self.objects) + for cdist_object in self.objects: + cdist_object.state = core.CdistObject.STATE_UNDEF + def tearDown(self): - os.environ = self.orig_environ + # os.environ = self.orig_environ shutil.rmtree(self.temp_dir) - for o in self.objects: - o.requirements = [] - - def test_dependency_resolution(self): - """Check that the runtime respects the right order""" - first_man = self.object_index['__first/man'] - second_on_the = self.object_index['__second/on-the'] - third_moon = self.object_index['__third/moon'] - - first_man.requirements = [second_on_the.name] - second_on_the.requirements = [third_moon.name] - - self.config.iterate_once() - - - self.assertEqual( - self.dependency_resolver.dependencies['__first/man'], - [third_moon, second_on_the, first_man] - ) - self.assertTrue(False) - - def test_circular_reference(self): - first_man = self.object_index['__first/man'] - first_woman = self.object_index['__first/woman'] - first_man.requirements = [first_woman.name] - first_woman.requirements = [first_man.name] - with self.assertRaises(resolver.CircularReferenceError): - self.dependency_resolver.dependencies - self.assertTrue(False) - - def test_requirement_not_found(self): - first_man = self.object_index['__first/man'] - first_man.requirements = ['__does/not/exist'] - with self.assertRaises(cdist.Error): - self.dependency_resolver.dependencies - self.assertTrue(False) + def test_objects_changed(self): + pass + # self.assert_True(self.config.iterate_once()) +class NotTheExecutionOrderTestCase(test.CdistTestCase): def test_implicit_dependencies(self): self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'implicit_dependencies') self.config.stage_prepare() From 25bdcb1602070973c958cc0f195510304b3055d0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 21 Jun 2013 22:39:20 +0200 Subject: [PATCH 117/548] cleanup tests and ... - 100% green Signed-off-by: Nico Schottelius --- cdist/__init__.py | 4 + cdist/config_install.py | 2 +- cdist/core/cdist_object.py | 7 -- .../test/{object => cdist_object}/__init__.py | 51 -------- .../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 .../object/__third/moon}/.cdist/.keep | 0 .../object/__third/moon/.cdist/parameter/name | 0 .../__third/moon/.cdist/parameter/planet | 0 .../fixtures/type/__first}/.keep | 0 .../fixtures/type/__second}/.keep | 0 .../fixtures/type/__third}/.keep | 0 cdist/test/{type => cdist_type}/__init__.py | 0 .../fixtures/__install/install | 0 .../fixtures/__name_path}/.keep | 0 .../fixtures/__not_install}/.keep | 0 .../fixtures/__not_singleton}/.keep | 0 .../fixtures/__singleton/singleton | 0 .../parameter/boolean | 0 .../__with_explorers/explorer/whatever | 0 .../parameter/optional | 0 .../parameter/required | 0 .../__without_boolean_parameters}/.keep | 0 .../fixtures/__without_explorers}/.keep | 0 .../__without_optional_parameters}/.keep | 0 .../__without_required_parameters}/.keep | 0 .../fixtures/list_types/__first}/.keep | 0 .../fixtures/list_types/__second}/.keep | 0 .../fixtures/list_types/__third}/.keep | 0 cdist/test/config_install/__init__.py | 34 ++++- .../fixtures/type/__singleton_test/singleton} | 0 cdist/test/execution_order/__init__.py | 116 ------------------ .../conf/manifest/circular_dependency | 2 - .../conf/manifest/implicit_dependencies | 3 - .../fixtures/conf/manifest/recursive_type | 2 - .../fixtures/conf/type/__git/manifest | 1 - .../conf/type/__nfsroot_client/manifest | 3 - .../fixtures/conf/type/__package/manifest | 1 - .../type/__root_ssh_authorized_key/manifest | 4 - .../fixtures/conf/type/__top/manifest | 2 - .../object/__second/on-the/.cdist/.keep | 0 .../object/__second/under-the/.cdist/.keep | 0 .../test/object/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/object/fixtures/type/__first/.keep | 0 .../test/object/fixtures/type/__second/.keep | 0 cdist/test/object/fixtures/type/__third/.keep | 0 cdist/test/type/fixtures/__name_path/.keep | 0 cdist/test/type/fixtures/__not_install/.keep | 0 .../test/type/fixtures/__not_singleton/.keep | 0 .../__without_boolean_parameters/.keep | 0 .../type/fixtures/__without_explorers/.keep | 0 .../__without_optional_parameters/.keep | 0 .../__without_required_parameters/.keep | 0 .../type/fixtures/list_types/__first/.keep | 0 .../type/fixtures/list_types/__second/.keep | 0 .../type/fixtures/list_types/__third/.keep | 0 66 files changed, 36 insertions(+), 198 deletions(-) rename cdist/test/{object => cdist_object}/__init__.py (81%) rename cdist/test/{execution_order/fixtures/conf/explorer => cdist_object/fixtures/object/__first}/.keep (100%) rename cdist/test/{execution_order/fixtures/conf/type/__addifnosuchline => cdist_object/fixtures/object/__first/child/.cdist}/.keep (100%) rename cdist/test/{execution_order/fixtures/conf/type/__directory => cdist_object/fixtures/object/__first/dog/.cdist}/.keep (100%) rename cdist/test/{execution_order/fixtures/conf/type/__first => cdist_object/fixtures/object/__first/man/.cdist}/.keep (100%) rename cdist/test/{execution_order/fixtures/conf/type/__package_special => cdist_object/fixtures/object/__first/woman/.cdist}/.keep (100%) rename cdist/test/{execution_order/fixtures/conf/type => cdist_object/fixtures/object}/__second/.keep (100%) rename cdist/test/{execution_order/fixtures/conf/type/__third => cdist_object/fixtures/object/__second/on-the/.cdist}/.keep (100%) rename cdist/test/{execution_order/fixtures/conf/type/__user => cdist_object/fixtures/object/__second/under-the/.cdist}/.keep (100%) rename cdist/test/{execution_order/fixtures/object/__first => cdist_object/fixtures/object/__third}/.keep (100%) rename cdist/test/{execution_order/fixtures/object/__first/child => cdist_object/fixtures/object/__third/moon}/.cdist/.keep (100%) rename cdist/test/{execution_order => cdist_object}/fixtures/object/__third/moon/.cdist/parameter/name (100%) rename cdist/test/{execution_order => cdist_object}/fixtures/object/__third/moon/.cdist/parameter/planet (100%) rename cdist/test/{execution_order/fixtures/object/__first/dog/.cdist => cdist_object/fixtures/type/__first}/.keep (100%) rename cdist/test/{execution_order/fixtures/object/__first/man/.cdist => cdist_object/fixtures/type/__second}/.keep (100%) rename cdist/test/{execution_order/fixtures/object/__first/woman/.cdist => cdist_object/fixtures/type/__third}/.keep (100%) rename cdist/test/{type => cdist_type}/__init__.py (100%) rename cdist/test/{type => cdist_type}/fixtures/__install/install (100%) rename cdist/test/{execution_order/fixtures/object/__second => cdist_type/fixtures/__name_path}/.keep (100%) rename cdist/test/{execution_order/fixtures/object/__second/on-the/.cdist => cdist_type/fixtures/__not_install}/.keep (100%) rename cdist/test/{execution_order/fixtures/object/__second/under-the/.cdist => cdist_type/fixtures/__not_singleton}/.keep (100%) rename cdist/test/{type => cdist_type}/fixtures/__singleton/singleton (100%) rename cdist/test/{type => cdist_type}/fixtures/__with_boolean_parameters/parameter/boolean (100%) rename cdist/test/{type => cdist_type}/fixtures/__with_explorers/explorer/whatever (100%) rename cdist/test/{type => cdist_type}/fixtures/__with_optional_parameters/parameter/optional (100%) rename cdist/test/{type => cdist_type}/fixtures/__with_required_parameters/parameter/required (100%) rename cdist/test/{execution_order/fixtures/object/__third => cdist_type/fixtures/__without_boolean_parameters}/.keep (100%) rename cdist/test/{execution_order/fixtures/object/__third/moon/.cdist => cdist_type/fixtures/__without_explorers}/.keep (100%) rename cdist/test/{object/fixtures/object/__first => cdist_type/fixtures/__without_optional_parameters}/.keep (100%) rename cdist/test/{object/fixtures/object/__first/child/.cdist => cdist_type/fixtures/__without_required_parameters}/.keep (100%) rename cdist/test/{object/fixtures/object/__first/dog/.cdist => cdist_type/fixtures/list_types/__first}/.keep (100%) rename cdist/test/{object/fixtures/object/__first/man/.cdist => cdist_type/fixtures/list_types/__second}/.keep (100%) rename cdist/test/{object/fixtures/object/__first/woman/.cdist => cdist_type/fixtures/list_types/__third}/.keep (100%) rename cdist/test/{object/fixtures/object/__second/.keep => config_install/fixtures/type/__singleton_test/singleton} (100%) delete mode 100644 cdist/test/execution_order/__init__.py delete mode 100755 cdist/test/execution_order/fixtures/conf/manifest/circular_dependency delete mode 100755 cdist/test/execution_order/fixtures/conf/manifest/implicit_dependencies delete mode 100755 cdist/test/execution_order/fixtures/conf/manifest/recursive_type delete mode 100644 cdist/test/execution_order/fixtures/conf/type/__git/manifest delete mode 100755 cdist/test/execution_order/fixtures/conf/type/__nfsroot_client/manifest delete mode 100755 cdist/test/execution_order/fixtures/conf/type/__package/manifest delete mode 100755 cdist/test/execution_order/fixtures/conf/type/__root_ssh_authorized_key/manifest delete mode 100755 cdist/test/execution_order/fixtures/conf/type/__top/manifest delete mode 100644 cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep delete mode 100644 cdist/test/object/fixtures/object/__second/under-the/.cdist/.keep delete mode 100644 cdist/test/object/fixtures/object/__third/.keep delete mode 100644 cdist/test/object/fixtures/object/__third/moon/.cdist/.keep delete mode 100644 cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name delete mode 100644 cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet delete mode 100644 cdist/test/object/fixtures/type/__first/.keep delete mode 100644 cdist/test/object/fixtures/type/__second/.keep delete mode 100644 cdist/test/object/fixtures/type/__third/.keep delete mode 100644 cdist/test/type/fixtures/__name_path/.keep delete mode 100644 cdist/test/type/fixtures/__not_install/.keep delete mode 100644 cdist/test/type/fixtures/__not_singleton/.keep delete mode 100644 cdist/test/type/fixtures/__without_boolean_parameters/.keep delete mode 100644 cdist/test/type/fixtures/__without_explorers/.keep delete mode 100644 cdist/test/type/fixtures/__without_optional_parameters/.keep delete mode 100644 cdist/test/type/fixtures/__without_required_parameters/.keep delete mode 100644 cdist/test/type/fixtures/list_types/__first/.keep delete mode 100644 cdist/test/type/fixtures/list_types/__second/.keep delete mode 100644 cdist/test/type/fixtures/list_types/__third/.keep diff --git a/cdist/__init__.py b/cdist/__init__.py index 02d708b1..bd45e740 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -47,6 +47,10 @@ 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""" diff --git a/cdist/config_install.py b/cdist/config_install.py index db7e3792..c8c18ce7 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -131,7 +131,7 @@ class ConfigInstall(object): autorequire = ", ".join(autorequire_names) info_string.append("%s requires: %s autorequires: %s" % (cdist_object.name, requirements, autorequire)) - raise cdist.Error("The requirements of the following objects could not be resolved: %s" % + raise cdist.UnresolvableRequirementsError("The requirements of the following objects could not be resolved: %s" % ("; ".join(info_string))) def object_prepare(self, cdist_object): diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 4df85b9f..04fb404c 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -235,10 +235,3 @@ class CdistObject(object): object_list.append(cdist_object) return object_list - -class RequirementNotFoundError(cdist.Error): - def __init__(self, requirement): - self.requirement = requirement - - def __str__(self): - return 'Requirement could not be found: %s' % self.requirement diff --git a/cdist/test/object/__init__.py b/cdist/test/cdist_object/__init__.py similarity index 81% rename from cdist/test/object/__init__.py rename to cdist/test/cdist_object/__init__.py index c4f46cd1..70506da4 100644 --- a/cdist/test/object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -212,54 +212,3 @@ class ObjectTestCase(test.CdistTestCase): self.assertTrue(isinstance(other_object, core.CdistObject)) self.assertEqual(other_object.cdist_type.name, '__first') self.assertEqual(other_object.object_id, 'man') - - - -class ObjectResolveRequirementsTestCase(test.CdistTestCase): - - def setUp(self): - self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) - self.object_index = dict((o.name, o) for o in self.objects) - self.object_names = [o.name for o in self.objects] - - print(self.objects) - - self.cdist_type = core.CdistType(type_base_path, '__third') - self.cdist_object = core.CdistObject(self.cdist_type, object_base_path, 'moon') - - def tearDown(self): - for o in self.objects: - o.requirements = [] - - def test_find_requirements_by_name_string(self): - """Check that resolving requirements by name works (require all objects)""" - requirements = self.object_names - - self.cdist_object.requirements = requirements - - found_requirements = sorted(self.cdist_object.find_requirements_by_name(self.cdist_object.requirements)) - expected_requirements = sorted(self.objects) - - self.assertEqual(found_requirements, expected_requirements) - - def test_find_requirements_by_name_pattern(self): - """Test whether pattern matching on requirements works""" - - # Matches all objects in the end - requirements = ['__first/*', '__second/*-the', '__third/moon'] - - self.cdist_object.requirements = requirements - - expected_requirements = sorted(self.objects) - found_requirements = sorted(self.cdist_object.find_requirements_by_name(self.cdist_object.requirements)) - - self.assertEqual(expected_requirements, found_requirements) - - def test_requirement_not_found(self): - """Ensure an exception is thrown for missing depedencies""" - cdist_object = self.object_index['__first/man'] - cdist_object.requirements = ['__does/not/exist'] - - with self.assertRaises(core.cdist_object.RequirementNotFoundError): - # Use list, as generator does not (yet) raise the error - list(cdist_object.find_requirements_by_name(cdist_object.requirements)) diff --git a/cdist/test/execution_order/fixtures/conf/explorer/.keep b/cdist/test/cdist_object/fixtures/object/__first/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/conf/explorer/.keep rename to cdist/test/cdist_object/fixtures/object/__first/.keep diff --git a/cdist/test/execution_order/fixtures/conf/type/__addifnosuchline/.keep b/cdist/test/cdist_object/fixtures/object/__first/child/.cdist/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/conf/type/__addifnosuchline/.keep rename to cdist/test/cdist_object/fixtures/object/__first/child/.cdist/.keep diff --git a/cdist/test/execution_order/fixtures/conf/type/__directory/.keep b/cdist/test/cdist_object/fixtures/object/__first/dog/.cdist/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/conf/type/__directory/.keep rename to cdist/test/cdist_object/fixtures/object/__first/dog/.cdist/.keep diff --git a/cdist/test/execution_order/fixtures/conf/type/__first/.keep b/cdist/test/cdist_object/fixtures/object/__first/man/.cdist/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/conf/type/__first/.keep rename to cdist/test/cdist_object/fixtures/object/__first/man/.cdist/.keep diff --git a/cdist/test/execution_order/fixtures/conf/type/__package_special/.keep b/cdist/test/cdist_object/fixtures/object/__first/woman/.cdist/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/conf/type/__package_special/.keep rename to cdist/test/cdist_object/fixtures/object/__first/woman/.cdist/.keep diff --git a/cdist/test/execution_order/fixtures/conf/type/__second/.keep b/cdist/test/cdist_object/fixtures/object/__second/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/conf/type/__second/.keep rename to cdist/test/cdist_object/fixtures/object/__second/.keep diff --git a/cdist/test/execution_order/fixtures/conf/type/__third/.keep b/cdist/test/cdist_object/fixtures/object/__second/on-the/.cdist/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/conf/type/__third/.keep rename to cdist/test/cdist_object/fixtures/object/__second/on-the/.cdist/.keep diff --git a/cdist/test/execution_order/fixtures/conf/type/__user/.keep b/cdist/test/cdist_object/fixtures/object/__second/under-the/.cdist/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/conf/type/__user/.keep rename to cdist/test/cdist_object/fixtures/object/__second/under-the/.cdist/.keep diff --git a/cdist/test/execution_order/fixtures/object/__first/.keep b/cdist/test/cdist_object/fixtures/object/__third/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__first/.keep rename to cdist/test/cdist_object/fixtures/object/__third/.keep diff --git a/cdist/test/execution_order/fixtures/object/__first/child/.cdist/.keep b/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__first/child/.cdist/.keep rename to cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/.keep diff --git a/cdist/test/execution_order/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/name similarity index 100% rename from cdist/test/execution_order/fixtures/object/__third/moon/.cdist/parameter/name rename to cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/name diff --git a/cdist/test/execution_order/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/planet similarity index 100% rename from cdist/test/execution_order/fixtures/object/__third/moon/.cdist/parameter/planet rename to cdist/test/cdist_object/fixtures/object/__third/moon/.cdist/parameter/planet diff --git a/cdist/test/execution_order/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/cdist_object/fixtures/type/__first/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__first/dog/.cdist/.keep rename to cdist/test/cdist_object/fixtures/type/__first/.keep diff --git a/cdist/test/execution_order/fixtures/object/__first/man/.cdist/.keep b/cdist/test/cdist_object/fixtures/type/__second/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__first/man/.cdist/.keep rename to cdist/test/cdist_object/fixtures/type/__second/.keep diff --git a/cdist/test/execution_order/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/cdist_object/fixtures/type/__third/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__first/woman/.cdist/.keep rename to cdist/test/cdist_object/fixtures/type/__third/.keep diff --git a/cdist/test/type/__init__.py b/cdist/test/cdist_type/__init__.py similarity index 100% rename from cdist/test/type/__init__.py rename to cdist/test/cdist_type/__init__.py diff --git a/cdist/test/type/fixtures/__install/install b/cdist/test/cdist_type/fixtures/__install/install similarity index 100% rename from cdist/test/type/fixtures/__install/install rename to cdist/test/cdist_type/fixtures/__install/install diff --git a/cdist/test/execution_order/fixtures/object/__second/.keep b/cdist/test/cdist_type/fixtures/__name_path/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__second/.keep rename to cdist/test/cdist_type/fixtures/__name_path/.keep diff --git a/cdist/test/execution_order/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/cdist_type/fixtures/__not_install/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__second/on-the/.cdist/.keep rename to cdist/test/cdist_type/fixtures/__not_install/.keep diff --git a/cdist/test/execution_order/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/cdist_type/fixtures/__not_singleton/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__second/under-the/.cdist/.keep rename to cdist/test/cdist_type/fixtures/__not_singleton/.keep diff --git a/cdist/test/type/fixtures/__singleton/singleton b/cdist/test/cdist_type/fixtures/__singleton/singleton similarity index 100% rename from cdist/test/type/fixtures/__singleton/singleton rename to cdist/test/cdist_type/fixtures/__singleton/singleton diff --git a/cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean b/cdist/test/cdist_type/fixtures/__with_boolean_parameters/parameter/boolean similarity index 100% rename from cdist/test/type/fixtures/__with_boolean_parameters/parameter/boolean rename to cdist/test/cdist_type/fixtures/__with_boolean_parameters/parameter/boolean diff --git a/cdist/test/type/fixtures/__with_explorers/explorer/whatever b/cdist/test/cdist_type/fixtures/__with_explorers/explorer/whatever similarity index 100% rename from cdist/test/type/fixtures/__with_explorers/explorer/whatever rename to cdist/test/cdist_type/fixtures/__with_explorers/explorer/whatever diff --git a/cdist/test/type/fixtures/__with_optional_parameters/parameter/optional b/cdist/test/cdist_type/fixtures/__with_optional_parameters/parameter/optional similarity index 100% rename from cdist/test/type/fixtures/__with_optional_parameters/parameter/optional rename to cdist/test/cdist_type/fixtures/__with_optional_parameters/parameter/optional diff --git a/cdist/test/type/fixtures/__with_required_parameters/parameter/required b/cdist/test/cdist_type/fixtures/__with_required_parameters/parameter/required similarity index 100% rename from cdist/test/type/fixtures/__with_required_parameters/parameter/required rename to cdist/test/cdist_type/fixtures/__with_required_parameters/parameter/required diff --git a/cdist/test/execution_order/fixtures/object/__third/.keep b/cdist/test/cdist_type/fixtures/__without_boolean_parameters/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__third/.keep rename to cdist/test/cdist_type/fixtures/__without_boolean_parameters/.keep diff --git a/cdist/test/execution_order/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/cdist_type/fixtures/__without_explorers/.keep similarity index 100% rename from cdist/test/execution_order/fixtures/object/__third/moon/.cdist/.keep rename to cdist/test/cdist_type/fixtures/__without_explorers/.keep diff --git a/cdist/test/object/fixtures/object/__first/.keep b/cdist/test/cdist_type/fixtures/__without_optional_parameters/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__first/.keep rename to cdist/test/cdist_type/fixtures/__without_optional_parameters/.keep diff --git a/cdist/test/object/fixtures/object/__first/child/.cdist/.keep b/cdist/test/cdist_type/fixtures/__without_required_parameters/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__first/child/.cdist/.keep rename to cdist/test/cdist_type/fixtures/__without_required_parameters/.keep diff --git a/cdist/test/object/fixtures/object/__first/dog/.cdist/.keep b/cdist/test/cdist_type/fixtures/list_types/__first/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__first/dog/.cdist/.keep rename to cdist/test/cdist_type/fixtures/list_types/__first/.keep diff --git a/cdist/test/object/fixtures/object/__first/man/.cdist/.keep b/cdist/test/cdist_type/fixtures/list_types/__second/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__first/man/.cdist/.keep rename to cdist/test/cdist_type/fixtures/list_types/__second/.keep diff --git a/cdist/test/object/fixtures/object/__first/woman/.cdist/.keep b/cdist/test/cdist_type/fixtures/list_types/__third/.keep similarity index 100% rename from cdist/test/object/fixtures/object/__first/woman/.cdist/.keep rename to cdist/test/cdist_type/fixtures/list_types/__third/.keep diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py index fab31cc9..b8daf4f8 100644 --- a/cdist/test/config_install/__init__.py +++ b/cdist/test/config_install/__init__.py @@ -29,6 +29,8 @@ from cdist import core import cdist import cdist.context import cdist.config +import cdist.core.cdist_type +import cdist.core.cdist_object import os.path as op my_dir = op.abspath(op.dirname(__file__)) @@ -111,11 +113,37 @@ class ConfigInstallRunTestCase(test.CdistTestCase): first.requirements = [second.name] second.requirements = [first.name] - with self.assertRaises(cdist.Error): + with self.assertRaises(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 = ['__does/not/exist'] - with self.assertRaises(cdist.Error): + first.requirements = ['__first/not/exist'] + with self.assertRaises(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.NoSuchTypeError): + 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() + +# 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 +# - but maybe only in the emulator - to be discussed. +# +# def test_requirement_no_singleton_where_singleton(self): +# """Missing object id should be detected in the resolving process""" +# first = self.object_index['__first/man'] +# first.requirements = ['__singleton_test/foo'] +# with self.assertRaises(cdist.core.?????): +# self.config.iterate_until_finished() diff --git a/cdist/test/object/fixtures/object/__second/.keep b/cdist/test/config_install/fixtures/type/__singleton_test/singleton similarity index 100% rename from cdist/test/object/fixtures/object/__second/.keep rename to cdist/test/config_install/fixtures/type/__singleton_test/singleton diff --git a/cdist/test/execution_order/__init__.py b/cdist/test/execution_order/__init__.py deleted file mode 100644 index 604000a2..00000000 --- a/cdist/test/execution_order/__init__.py +++ /dev/null @@ -1,116 +0,0 @@ -# -*- coding: utf-8 -*- -# -# 2010-2011 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 test -from cdist import core -from cdist import config -from cdist.exec import local -from cdist.core import manifest -import cdist.context - -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') -add_conf_dir = op.join(fixtures, 'conf') -type_base_path = op.join(add_conf_dir, 'type') - -class MockContext(object): - """A context object that has the required attributes""" - def __init__(self, target_host): - self.target_host = target_host - self.local = False - -class MockLocal(object): - def __init__(self, temp_dir, type_path): - self.temp_dir = temp_dir - self.object_path = op.join(self.temp_dir, "object") - self.type_path = type_path - -class ExecutionOrderTestCase(test.CdistTestCase): - def setUp(self): - # self.orig_environ = os.environ - # os.environ = os.environ.copy() - # os.environ['__cdist_out_dir'] = self.out_dir - # os.environ['__cdist_remote_out_dir'] = self.remote_out_dir - # self.out_dir = os.path.join(self.temp_dir, "out") - # self.remote_out_dir = os.path.join(self.temp_dir, "remote") - - self.temp_dir = self.mkdtemp() - - self.context = MockContext(self.target_host) - self.context.local = MockLocal(self.temp_dir, type_base_path) - self.config = config.Config(self.context) - - self._init_objects() - - def _init_objects(self): - """copy base objects to context directory""" - shutil.copytree(object_base_path, self.context.local.object_path) - self.objects = list(core.CdistObject.list_objects(self.context.local.object_path, self.context.local.type_path)) - self.object_index = dict((o.name, o) for o in self.objects) - - for cdist_object in self.objects: - cdist_object.state = core.CdistObject.STATE_UNDEF - - def tearDown(self): - # os.environ = self.orig_environ - shutil.rmtree(self.temp_dir) - - def test_objects_changed(self): - pass - # self.assert_True(self.config.iterate_once()) - -class NotTheExecutionOrderTestCase(test.CdistTestCase): - def test_implicit_dependencies(self): - self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'implicit_dependencies') - self.config.stage_prepare() - - objects = core.CdistObject.list_objects(self.context.local.object_path, self.context.local.type_path) - dependency_resolver = resolver.DependencyResolver(objects) - expected_dependencies = [ - dependency_resolver.objects['__package_special/b'], - dependency_resolver.objects['__package/b'], - dependency_resolver.objects['__package_special/a'] - ] - resolved_dependencies = dependency_resolver.dependencies['__package_special/a'] - self.assertEqual(resolved_dependencies, expected_dependencies) - self.assertTrue(False) - - def test_circular_dependency(self): - self.context.initial_manifest = os.path.join(self.context.local.manifest_path, 'circular_dependency') - self.config.stage_prepare() - # raises CircularDependecyError - self.config.stage_run() - self.assertTrue(False) - - def test_recursive_type(self): - self.context.initial_manifest = os.path.join(self.config.local.manifest_path, 'recursive_type') - self.config.stage_prepare() - # raises CircularDependecyError - self.config.stage_run() - self.assertTrue(False) diff --git a/cdist/test/execution_order/fixtures/conf/manifest/circular_dependency b/cdist/test/execution_order/fixtures/conf/manifest/circular_dependency deleted file mode 100755 index 6ea308d1..00000000 --- a/cdist/test/execution_order/fixtures/conf/manifest/circular_dependency +++ /dev/null @@ -1,2 +0,0 @@ -# this has triggered CircularReferenceError -__nfsroot_client test diff --git a/cdist/test/execution_order/fixtures/conf/manifest/implicit_dependencies b/cdist/test/execution_order/fixtures/conf/manifest/implicit_dependencies deleted file mode 100755 index 7d68aed2..00000000 --- a/cdist/test/execution_order/fixtures/conf/manifest/implicit_dependencies +++ /dev/null @@ -1,3 +0,0 @@ -# this creates implicit dependencies through autorequire. -# this failed because autorequired dependencies where not aware of their anchestors dependencies -__top test diff --git a/cdist/test/execution_order/fixtures/conf/manifest/recursive_type b/cdist/test/execution_order/fixtures/conf/manifest/recursive_type deleted file mode 100755 index c32b7710..00000000 --- a/cdist/test/execution_order/fixtures/conf/manifest/recursive_type +++ /dev/null @@ -1,2 +0,0 @@ -__git foo -require="__git/foo" __git bar diff --git a/cdist/test/execution_order/fixtures/conf/type/__git/manifest b/cdist/test/execution_order/fixtures/conf/type/__git/manifest deleted file mode 100644 index 616ecca9..00000000 --- a/cdist/test/execution_order/fixtures/conf/type/__git/manifest +++ /dev/null @@ -1 +0,0 @@ -__package git diff --git a/cdist/test/execution_order/fixtures/conf/type/__nfsroot_client/manifest b/cdist/test/execution_order/fixtures/conf/type/__nfsroot_client/manifest deleted file mode 100755 index f6cb7833..00000000 --- a/cdist/test/execution_order/fixtures/conf/type/__nfsroot_client/manifest +++ /dev/null @@ -1,3 +0,0 @@ -__user root -__root_ssh_authorized_key john -__root_ssh_authorized_key frank diff --git a/cdist/test/execution_order/fixtures/conf/type/__package/manifest b/cdist/test/execution_order/fixtures/conf/type/__package/manifest deleted file mode 100755 index 6f70e627..00000000 --- a/cdist/test/execution_order/fixtures/conf/type/__package/manifest +++ /dev/null @@ -1 +0,0 @@ -__package_special "$__object_id" diff --git a/cdist/test/execution_order/fixtures/conf/type/__root_ssh_authorized_key/manifest b/cdist/test/execution_order/fixtures/conf/type/__root_ssh_authorized_key/manifest deleted file mode 100755 index 6224629f..00000000 --- a/cdist/test/execution_order/fixtures/conf/type/__root_ssh_authorized_key/manifest +++ /dev/null @@ -1,4 +0,0 @@ -user="$__object_id" -__directory /root/.ssh -require="__directory/root/.ssh" \ - __addifnosuchline "ssh-root-$user" diff --git a/cdist/test/execution_order/fixtures/conf/type/__top/manifest b/cdist/test/execution_order/fixtures/conf/type/__top/manifest deleted file mode 100755 index d6968c25..00000000 --- a/cdist/test/execution_order/fixtures/conf/type/__top/manifest +++ /dev/null @@ -1,2 +0,0 @@ -__package b -require="__package/b" __package a diff --git a/cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/object/fixtures/object/__second/on-the/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/object/fixtures/object/__second/under-the/.cdist/.keep b/cdist/test/object/fixtures/object/__second/under-the/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/object/fixtures/object/__third/.keep b/cdist/test/object/fixtures/object/__third/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/object/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/object/fixtures/object/__third/moon/.cdist/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name deleted file mode 100644 index 4129a761..00000000 --- a/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/name +++ /dev/null @@ -1 +0,0 @@ -Prometheus diff --git a/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet deleted file mode 100644 index 8e6ee422..00000000 --- a/cdist/test/object/fixtures/object/__third/moon/.cdist/parameter/planet +++ /dev/null @@ -1 +0,0 @@ -Saturn diff --git a/cdist/test/object/fixtures/type/__first/.keep b/cdist/test/object/fixtures/type/__first/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/object/fixtures/type/__second/.keep b/cdist/test/object/fixtures/type/__second/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/object/fixtures/type/__third/.keep b/cdist/test/object/fixtures/type/__third/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__name_path/.keep b/cdist/test/type/fixtures/__name_path/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__not_install/.keep b/cdist/test/type/fixtures/__not_install/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__not_singleton/.keep b/cdist/test/type/fixtures/__not_singleton/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__without_boolean_parameters/.keep b/cdist/test/type/fixtures/__without_boolean_parameters/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__without_explorers/.keep b/cdist/test/type/fixtures/__without_explorers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__without_optional_parameters/.keep b/cdist/test/type/fixtures/__without_optional_parameters/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/__without_required_parameters/.keep b/cdist/test/type/fixtures/__without_required_parameters/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/list_types/__first/.keep b/cdist/test/type/fixtures/list_types/__first/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/list_types/__second/.keep b/cdist/test/type/fixtures/list_types/__second/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cdist/test/type/fixtures/list_types/__third/.keep b/cdist/test/type/fixtures/list_types/__third/.keep deleted file mode 100644 index e69de29b..00000000 From 9326adf34baa80cae2f2f998d8fc7cff50fb8534 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 24 Jun 2013 13:23:31 +0200 Subject: [PATCH 118/548] fix refactor error Signed-off-by: Nico Schottelius --- 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 693830eb..da7f69c1 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -161,7 +161,7 @@ class Local(object): self._link_types_for_emulator() def save_cache(self): - destination = os.path.join(self.local.cache_path, self.target_host) + destination = os.path.join(self.cache_path, self.target_host) self.log.debug("Saving " + self.out_path + " to " + destination) if os.path.exists(destination): shutil.rmtree(destination) From 9cde0d9d94276eefcb2e80a8a965b8cd7d8775aa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 3 Jul 2013 22:33:48 +0200 Subject: [PATCH 119/548] continue rewrite of build-helper Signed-off-by: Nico Schottelius --- Makefile | 13 ++++++++++++- bin/build-helper | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index dac24394..8929f91d 100644 --- a/Makefile +++ b/Makefile @@ -61,9 +61,20 @@ $(MANREF): $(MANREFSH) $(MANREFSH) ################################################################################ -# generic code +# manpage +# generate links from types +# build manpages # +mantypedocuments=cdist/conf/type/*/man.text + +mantypelist: $(mantypedocuments) + echo $^ >> $@ + +link-type-manpages: + $(helper) $@ + + ################################################################################ # dist code diff --git a/bin/build-helper b/bin/build-helper index c1c65676..94b52f66 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -67,7 +67,7 @@ case "$1" in done ;; - mantype) + link-type-manpages) for mansrc in cdist/conf/type/*/man.text; do dst="$(echo $mansrc | sed -e 's;cdist/conf/;cdist-;' -e 's;/;;' -e 's;/man;;' -e 's;^;docs/man/man7/;')" ln -sf "../../../$mansrc" "$dst" @@ -121,7 +121,7 @@ case "$1" in cat << eof > "$blogfile" [[!meta title="Cdist $version released"]] -Here's a short overview about the changes found in this release: +Here's a short overview about the changes found in version ${version}: eof From ab50d8561b27be00733dff0a8597e45fc65f91aa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 4 Jul 2013 14:34:17 +0200 Subject: [PATCH 120/548] add new type: __cdist Signed-off-by: Nico Schottelius --- cdist/conf/type/__cdist/man.text | 63 ++++++++++++++++++++++ cdist/conf/type/__cdist/manifest | 46 ++++++++++++++++ cdist/conf/type/__cdist/parameter/optional | 3 ++ 3 files changed, 112 insertions(+) create mode 100644 cdist/conf/type/__cdist/man.text create mode 100755 cdist/conf/type/__cdist/manifest create mode 100644 cdist/conf/type/__cdist/parameter/optional diff --git a/cdist/conf/type/__cdist/man.text b/cdist/conf/type/__cdist/man.text new file mode 100644 index 00000000..0805598e --- /dev/null +++ b/cdist/conf/type/__cdist/man.text @@ -0,0 +1,63 @@ +cdist-type__cdist(7) +==================== +Nico Schottelius + + +NAME +---- +cdist-type__cdist - Manage cdist installations + + +DESCRIPTION +----------- +This cdist type allows you to easily setup cdist +on another box, to allow the other box to configure +systems. + +This type is *NOT* required by target hosts. +It is only helpful to build FROM which you configure +other hosts. + +This type will use git to clone + + +REQUIRED PARAMETERS +------------------- + +OPTIONAL PARAMETERS +------------------- +username:: + Select the user to create for the cdist installation. + Defaults to "cdist". + +source:: + Select the source from which to clone cdist from. + Defaults to "git://github.com/telmich/cdist.git". + + +branch:: + Select the branch to checkout from. + Defaults to "master". + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# 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) + + +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/__cdist/manifest b/cdist/conf/type/__cdist/manifest new file mode 100755 index 00000000..16498c95 --- /dev/null +++ b/cdist/conf/type/__cdist/manifest @@ -0,0 +1,46 @@ +#!/bin/sh +# +# 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 . +# +# + +directory="$__object_id" + +if [ -f "$__object/parameter/username" ]; then + username="$(cat "$__object/parameter/username")" +else + username="cdist" +fi + +if [ -f "$__object/parameter/branch" ]; then + branch="$(cat "$__object/parameter/branch")" +else + branch="master" +fi + +if [ -f "$__object/parameter/source" ]; then + source="$(cat "$__object/parameter/source")" +else + source="git://github.com/telmich/cdist.git" +fi + +__user "$username" + +require="__user/$username" __git "$directory" \ + --source "$source" \ + --owner "$username" --branch "$branch" diff --git a/cdist/conf/type/__cdist/parameter/optional b/cdist/conf/type/__cdist/parameter/optional new file mode 100644 index 00000000..d6582730 --- /dev/null +++ b/cdist/conf/type/__cdist/parameter/optional @@ -0,0 +1,3 @@ +branch +source +username From fe5c99b14379dc55dacbda60893ebb45c2413752 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 4 Jul 2013 14:49:25 +0200 Subject: [PATCH 121/548] new type: __cdist Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 47edeed3..ca41ce0d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -17,6 +17,7 @@ next: * Type __process: Make state parameter optional * Type __cron: Simplyfied and syntax change * New Type: __update_alternatives + * New Type: __cdist 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From 3c14f7e2f5dbb416c729828b4dbc2c83a26cb92e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 5 Jul 2013 15:00:23 +0200 Subject: [PATCH 122/548] add dry run hint Signed-off-by: Nico Schottelius --- cdist/config_install.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index c8c18ce7..55c6bb3f 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -143,7 +143,13 @@ class ConfigInstall(object): def object_run(self, cdist_object, dry_run=False): """Run gencode and code for an object""" - self.log.debug("Trying to run object " + cdist_object.name) + + if self.dry_run: + dry_run = "" + else: + dry_run = "(dry run)" + + self.log.debug("Trying to run object %s%s" % (cdist_object.name, dry_run)) if cdist_object.state == core.CdistObject.STATE_DONE: raise cdist.Error("Attempting to run an already finished object: %s", cdist_object) From 5bad25cd6d73b337c3886f92de1f62f682f58d5c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 5 Jul 2013 15:02:36 +0200 Subject: [PATCH 123/548] add dry_run hint to verbose messages, not debug Signed-off-by: Nico Schottelius --- cdist/config_install.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 55c6bb3f..9b732d23 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -147,16 +147,16 @@ class ConfigInstall(object): if self.dry_run: dry_run = "" else: - dry_run = "(dry run)" + dry_run = " (dry run)" - self.log.debug("Trying to run object %s%s" % (cdist_object.name, dry_run)) + 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) cdist_type = cdist_object.cdist_type # Generate - self.log.info("Generating and executing code for " + cdist_object.name) + self.log.info("Generating and executing code for %s%s" % (cdist_object.name, dry_run)) 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: From 5f318d5de307a5bb36fd036514c1e88209277146 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 5 Jul 2013 15:12:49 +0200 Subject: [PATCH 124/548] print warning in case dry run is activated Signed-off-by: Nico Schottelius --- cdist/config_install.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 9b732d23..21b01a84 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -144,11 +144,6 @@ class ConfigInstall(object): def object_run(self, cdist_object, dry_run=False): """Run gencode and code for an object""" - if self.dry_run: - dry_run = "" - else: - dry_run = " (dry run)" - 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) @@ -156,19 +151,22 @@ class ConfigInstall(object): cdist_type = cdist_object.cdist_type # Generate - self.log.info("Generating and executing code for %s%s" % (cdist_object.name, dry_run)) + self.log.info("Generating and executing 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 not dry_run: + if not self.dry_run: if cdist_object.code_local: self.code.run_code_local(cdist_object) if cdist_object.code_remote: 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") + # Mark this object as done self.log.debug("Finishing run of " + cdist_object.name) From dbe65795f5f32b3776be60457db8bac116c4cc4c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 5 Jul 2013 15:27:34 +0200 Subject: [PATCH 125/548] remove dry_run from object_run Signed-off-by: Nico Schottelius --- cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 21b01a84..72061ca2 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -141,7 +141,7 @@ class ConfigInstall(object): self.manifest.run_type_manifest(cdist_object) cdist_object.state = core.CdistObject.STATE_PREPARED - def object_run(self, cdist_object, dry_run=False): + def object_run(self, cdist_object): """Run gencode and code for an object""" self.log.debug("Trying to run object %s" % (cdist_object.name)) From fb3cad7bb6e4a8097dc5d8a1e2e1b60ec84b06fb Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Sun, 7 Jul 2013 12:25:46 +0200 Subject: [PATCH 126/548] improve docu wording --- docs/man/man7/cdist-bootstrap.text | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/man/man7/cdist-bootstrap.text b/docs/man/man7/cdist-bootstrap.text index 7e1bff0f..985d0f53 100644 --- a/docs/man/man7/cdist-bootstrap.text +++ b/docs/man/man7/cdist-bootstrap.text @@ -64,11 +64,11 @@ 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 other and won't break your configuration when updating. -It's up to you decide on which branch you want to base your own work: +It's up to you to decide which branch you want to base your own work on: master contains more recent changes, newer types, but may also break. -The versions branches are stable, but thus may miss the latest features. +The version branches are stable, but may lack the latest features. Your decision can be changed later on, but may result in merge conflicts, -which you'd have to solve. +which you will need to solve. Let's assume you want latest stuff and select the master branch as base for your own work. Now it's time to create your branch, which contains your From 47d0b30739b5cd126d0548c40786497c5dbf7835 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Sun, 7 Jul 2013 12:44:42 +0200 Subject: [PATCH 127/548] improve docu wording --- docs/man/man7/cdist-manifest.text | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 2c6ec5c1..ade2eef1 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -11,7 +11,7 @@ cdist-manifest - (Re-)Use types DESCRIPTION ----------- Manifests are used to define which objects to create. -Objects are instances of **types**, like in object orientated programming languages. +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***. @@ -57,9 +57,9 @@ 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. -Cdist searches for the initial manifest at **cdist/conf/manifest/init**. +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**. Let's have a look at a simple example: From 88d430cd988a637a15af6a7559c037fac26841a1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 7 Jul 2013 12:58:48 +0200 Subject: [PATCH 128/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ca41ce0d..104f6864 100644 --- a/docs/changelog +++ b/docs/changelog @@ -18,6 +18,7 @@ next: * Type __cron: Simplyfied and syntax change * New Type: __update_alternatives * New Type: __cdist + * Improved documenattion (Tomáš Pospíšek) 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From 243106f513950f3fdc660d50c358c5cd6c0edd41 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Sun, 7 Jul 2013 13:11:09 +0200 Subject: [PATCH 129/548] improve docu wording --- docs/man/man7/cdist-type.text | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text index 18deda9a..71495797 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.text @@ -67,18 +67,18 @@ A type consists of Types are stored below cdist/conf/type/. Their name should always be prefixed with two underscores (__) to prevent collisions with other executables in $PATH. -To begin a new type, just create the directory **cdist/conf/type/__NAME**. +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 -be created in a newline separated file in ***parameter/required***, +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. For all other parameters -the standard unix behaviour of the last given wins is applied. +required_multiple or optional_multiple respectively. All other parameters +follow the standard unix behaviour "the last given wins". If either is missing, the type will have no required, no optional, no boolean or no parameters at all. @@ -125,7 +125,7 @@ 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. From 0162436ab700417d2b3a47ffddf41cfa95eb8663 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Sun, 7 Jul 2013 13:11:20 +0200 Subject: [PATCH 130/548] fix asciidoc misinterpretation asciidoc was misinterpreting the '-----' (see patch) as underlining the previous text instead of as starting the next source code section. Inserting a newline in between to help asciidoc. --- docs/man/man7/cdist-type.text | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text index 71495797..7d941281 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.text @@ -141,6 +141,7 @@ 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: + -------------------------------------------------------------------------------- if [ -f "$__object/parameter/source" ]; then source="$(cat "$__object/parameter/source")" From 995a02360b2ef85bd3bc43fb421774ab8d51ace7 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Sun, 7 Jul 2013 13:18:32 +0200 Subject: [PATCH 131/548] improve docu wording --- docs/man/man7/cdist-type.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text index 7d941281..cfb50414 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.text @@ -230,7 +230,7 @@ the output of gencode-remote is executed on the target. The gencode scripts can make use of the parameters, the global explorers and the type specific explorers. -If the gencode scripts encounter an error, it should print diagnostic +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: From 89ecc85fb2aad8fc3655274f8260f53bea602cb6 Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Mon, 8 Jul 2013 07:29:55 +0200 Subject: [PATCH 132/548] improve documentation ;-) --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 104f6864..1c48818e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -18,7 +18,7 @@ next: * Type __cron: Simplyfied and syntax change * New Type: __update_alternatives * New Type: __cdist - * Improved documenattion (Tomáš Pospíšek) + * Improved documentation (Tomáš Pospíšek) 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From 78d057bc5222d9810e39ed3e3c225d9d1c9c24fa Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Mon, 8 Jul 2013 07:34:41 +0200 Subject: [PATCH 133/548] building manpages has changed --- docs/web/cdist/install.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index ad97cd2b..de913ea2 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -139,7 +139,7 @@ To install cdist, execute the following commands: If you want to build and use the manpages, run: - ./build man + ./bin/build-helper manbuild export MANPATH=$MANPATH:$(pwd -P)/doc/man #### Available versions in git From 93cf32d899a4b55741ce2f3cf25986e575f40a1d Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Mon, 8 Jul 2013 07:36:36 +0200 Subject: [PATCH 134/548] proper mdwn style code indentation --- docs/web/cdist/install.mdwn | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index de913ea2..c5aff6ff 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -45,18 +45,18 @@ For Debian **wheezy** or newer: On **squeeze** you can add following line in **/etc/apt/sources.list** - deb http://ftp.debian.org/debian wheezy main + 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 + 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 + apt-get install -t wheezy openssh-server openssh-client For older Debian versions, installing python 3.2 from source is required. From 067af56cd8ad2d0768befd9970cc0d0519ff573f Mon Sep 17 00:00:00 2001 From: Tomas Pospisek Date: Mon, 8 Jul 2013 07:49:30 +0200 Subject: [PATCH 135/548] expand manbuild dependency documentation --- docs/web/cdist/install.mdwn | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index c5aff6ff..654c4c8a 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -10,7 +10,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 - * Asciidoc (for building the manpages) + * Asciidoc and xsltproc (for building the manpages) ### Target Hosts @@ -60,6 +60,10 @@ removed on **python3.2** installation. You surely want to reinstall them: 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. From 5712df850b395510f447de1ca11d0ffadbfa9839 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 14:00:42 +0200 Subject: [PATCH 136/548] build type manpages using the Makefile Signed-off-by: Nico Schottelius --- Makefile | 80 +++++++++- bin/build-helper | 62 +------- docs/man/man7/cdist-type.text | 280 ---------------------------------- 3 files changed, 77 insertions(+), 345 deletions(-) delete mode 100644 docs/man/man7/cdist-type.text diff --git a/Makefile b/Makefile index 8929f91d..3c62e8c8 100644 --- a/Makefile +++ b/Makefile @@ -23,11 +23,60 @@ A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 helper=./bin/build-helper MANDIR=docs/man + MAN1DSTDIR=$(MANDIR)/man1 MAN7DSTDIR=$(MANDIR)/man7 MANREF=$(MAN7DSTDIR)/cdist-reference.text MANREFSH=$(MANDIR)/cdist-reference.text.sh +SPEECHDIR=docs/speeches + +TYPEDIR=cdist/conf/type + +################################################################################ +# Manpages for types +# +# Use shell / ls to get complete list - $(TYPEDIR)/*/man.text does not work +TYPEMANSRC=$(shell ls $(TYPEDIR)/*/man.text) + +# replace first path component +TYPEMANPREFIX=$(subst cdist/conf/type/,docs/man/man7/cdist-type,$(TYPEMANSRC)) + +# replace man.text with .7 or .html +TYPEMANPAGES=$(subst /man.text,.7,$(TYPEMANPREFIX)) +TYPEMANHTML=$(subst /man.text,.html,$(TYPEMANPREFIX)) + + +# Link manpage so A2XH does not create man.html but correct named file +$(MAN7DSTDIR)/cdist-type%.text: $(TYPEDIR)/%/man.text + ln -sf "../../../$^" $@ + +# Creating the type manpage +$(MAN7DSTDIR)/cdist-type%.7: $(MAN7DSTDIR)/cdist-type%.text + $(A2XM) $^ + +# Creating the type html page +$(MAN7DSTDIR)/cdist-type%.html: $(MAN7DSTDIR)/cdist-type%.text + $(A2XH) $^ + +typemanpage: $(TYPEMANPAGES) +typemanhtml: $(TYPEMANHTML) + +################################################################################ +# Speeches +# +SPEECHESOURCES=$(SPEECHDIR)/*.tex +SPEECHES=$(SPEECHESOURCES:.tex=.pdf) + +# Create speeches and ensure Toc is up-to-date +$(SPEECHDIR)/%.pdf: $(SPEECHDIR)/%.tex + pdflatex -output-directory $(SPEECHDIR) $^ + pdflatex -output-directory $(SPEECHDIR) $^ + pdflatex -output-directory $(SPEECHDIR) $^ + +speeches: $(SPEECHES) + +################################################################################ CHECKS=check-version check-date DIST=dist-tag dist-branch-merge @@ -51,12 +100,6 @@ $(RELEASE): $(DIST) $(CHECKS) man: $(MANREF) mantype manbuild -$(MAN7DSTDIR)/cdist-type__motd.7: $(MAN7DSTDIR)/cdist-type__motd.text - $(A2XM) $^ - -$(MAN7DSTDIR)/cdist-type__motd.text: cdist/conf/type/__motd/man.text - echo ln -sf $@ $^ - $(MANREF): $(MANREFSH) $(MANREFSH) @@ -75,7 +118,6 @@ link-type-manpages: $(helper) $@ - ################################################################################ # dist code # @@ -109,6 +151,30 @@ release-web: web-doc PKGBUILD: PKGBUILD.in ./PKGBUILD.in +################################################################################ +# Cleanup + +clean: + rm -f $(MAN7DSTDIR)/cdist-reference.text + + find "$(MANDIR)" -mindepth 2 -type l \ + -o -name "*.1" \ + -o -name "*.7" \ + -o -name "*.html" \ + -o -name "*.xml" \ + | xargs rm -f + + find * -name __pycache__ | xargs rm -rf + +distclean: + rm -f cdist/version.py MANIFEST PKGBUILD + rm -rf cache/ dist/ + + # Archlinux + rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz + rm -rf pkg/ src/ + + ################################################################################ # generic call %: diff --git a/bin/build-helper b/bin/build-helper index 94b52f66..39c535df 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -46,34 +46,6 @@ MAN7DSTDIR=${MANDIR}/man7 SPEECHESDIR=docs/speeches case "$1" in - manbuild) - trap abort INT - abort() { - kill 0 - } - for section in 1 7; do - for src in ${MANDIR}/man${section}/*.text; do - manpage="${src%.text}.$section" - if [ ! -f "$manpage" -o "$manpage" -ot "$src" ]; then - echo "Compiling man page for $src" - $A2XM "$src" - fi - htmlpage="${src%.text}.html" - if [ ! -f "$htmlpage" -o "$htmlpage" -ot "$src" ]; then - echo "Compiling html page for $src" - $A2XH "$src" - fi - done - done - ;; - - link-type-manpages) - for mansrc in cdist/conf/type/*/man.text; do - dst="$(echo $mansrc | sed -e 's;cdist/conf/;cdist-;' -e 's;/;;' -e 's;/man;;' -e 's;^;docs/man/man7/;')" - ln -sf "../../../$mansrc" "$dst" - done - ;; - release-man) version=$($0 changelog-version) @@ -236,15 +208,6 @@ eof ;; - dist-speeches) - cd "$SPEECHESDIR" - for speech in *tex; do - pdflatex "$speech" - pdflatex "$speech" - pdflatex "$speech" - done - ;; - web-doc) rsync -av "${basedir}/docs/web/" "${WEBTOPDIR}" @@ -268,27 +231,6 @@ eof done ;; - clean) - rm -f ${MAN7DSTDIR}/cdist-reference.text - - find "${MANDIR}" -mindepth 2 -type l \ - -o -name "*.1" \ - -o -name "*.7" \ - -o -name "*.html" \ - -o -name "*.xml" \ - | xargs rm -f - - find * -name __pycache__ | xargs rm -rf - ;; - distclean) - rm -f cdist/version.py MANIFEST PKGBUILD - rm -rf cache/ dist/ - - # Archlinux - rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz - rm -rf pkg/ src/ - ;; - test) shift # skip t export PYTHONPATH="$(pwd -P)" @@ -303,6 +245,10 @@ eof echo "VERSION = \"$(git describe)\"" > cdist/version.py ;; + # Targets handled in the makefile + speeches|clean|dist-clean) + ;; + *) echo "Unknown target $@ - aborting" exit 1 diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text deleted file mode 100644 index cfb50414..00000000 --- a/docs/man/man7/cdist-type.text +++ /dev/null @@ -1,280 +0,0 @@ -cdist-type(7) -============= -Nico Schottelius - - -NAME ----- -cdist-type - Functionality bundled - - -SYNOPSIS --------- -__TYPE ID --parameter value [--parameter value ...] - -__TYPE --parameter value [--parameter value ...] (for singletons) - - -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. - - -HOW TO USE A TYPE ------------------ -You can use types from the initial manifest or the type manifest like a -normal command: - --------------------------------------------------------------------------------- -# 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. - - -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 -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 --------------------------------------------------------------------------------- - - -HOW TO WRITE A NEW TYPE ------------------------ -A type consists of - -- parameter (optional) -- manifest (optional) -- singleton (optional) -- explorer (optional) -- gencode (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. - -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***. -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". -If either is missing, the type will have no required, no optional, no boolean -or no parameters at all. - -Example: --------------------------------------------------------------------------------- -echo servername >> cdist/conf/type/__nginx_vhost/parameter/required -echo logdirectory >> cdist/conf/type/__nginx_vhost/parameter/optional -echo server_alias >> cdist/conf/type/__nginx_vhost/parameter/optional_multiple -echo use_ssl >> cdist/conf/type/__nginx_vhost/parameter/boolean --------------------------------------------------------------------------------- - - -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 -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 - -# 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. - -Example use of a type: (e.g. in cdist/conf/type/__archlinux_hostname) --------------------------------------------------------------------------------- -__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: - --------------------------------------------------------------------------------- - if [ -f "$__object/parameter/source" ]; then - source="$(cat "$__object/parameter/source")" - if [ "$source" = "-" ]; then - source="$__object/stdin" - fi - .... --------------------------------------------------------------------------------- - - -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 -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 - -__package_$type "$@" --------------------------------------------------------------------------------- - -As you can see, the type can reference different environment variables, -which are documented in cdist-reference(7). - -Always ensure the manifest is executable, otherwise cdist will not be able -to execute it. For more information about manifests see cdist-manifest(7). - - -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 -directory: - --------------------------------------------------------------------------------- -touch cdist/conf/type/__NAME/singleton --------------------------------------------------------------------------------- - -This will also change the way your type must be called: - --------------------------------------------------------------------------------- -__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. - - -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. - -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 - -if [ -e "$destination" ]; then - md5sum < "$destination" -fi --------------------------------------------------------------------------------- - - -WRITING THE GENCODE SCRIPT --------------------------- -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 -and the type specific explorers. - -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 - -# Output to be saved by cdist for execution on the target -echo "touch /etc/cdist-configured" --------------------------------------------------------------------------------- - - -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 -on the target, there must be another type that provides this tool and the first -type should create an object of the specific type. - -If your type wants to save temporary data, that may be used by other types -later on (for instance __file), you can save them in the subdirectory -"files" below $__object (but you must create it yourself). -cdist will not touch this directory. - -If your type contains static files, it's also recommended to place them in -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 ------------------------------------------ -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 -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). From 13e7c98469ea893514456e16ebf848fdbbbaff65 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 14:02:03 +0200 Subject: [PATCH 137/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 1c48818e..830d0207 100644 --- a/docs/changelog +++ b/docs/changelog @@ -19,6 +19,7 @@ next: * New Type: __update_alternatives * New Type: __cdist * Improved documentation (Tomáš Pospíšek) + * Moved a lot of build logic into Makefile for dependency resolution 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From 04b81f2a5111ac37e461840f12c0c439d195d3cf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 14:36:20 +0200 Subject: [PATCH 138/548] use make man to build manpages Signed-off-by: Nico Schottelius --- docs/web/cdist/install.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web/cdist/install.mdwn b/docs/web/cdist/install.mdwn index 654c4c8a..c81354f0 100644 --- a/docs/web/cdist/install.mdwn +++ b/docs/web/cdist/install.mdwn @@ -143,7 +143,7 @@ To install cdist, execute the following commands: If you want to build and use the manpages, run: - ./bin/build-helper manbuild + make man export MANPATH=$MANPATH:$(pwd -P)/doc/man #### Available versions in git From 5bdc2e1ba9c5f8d416d1d2bbf0d3bc393dec63d0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 14:53:00 +0200 Subject: [PATCH 139/548] add link to cdist speeches Signed-off-by: Nico Schottelius --- Makefile | 104 +++++++++++++++++------------- bin/build-helper | 16 +---- docs/changelog | 2 +- docs/web/cdist/documentation.mdwn | 2 + 4 files changed, 63 insertions(+), 61 deletions(-) diff --git a/Makefile b/Makefile index 3c62e8c8..d43360e7 100644 --- a/Makefile +++ b/Makefile @@ -23,50 +23,83 @@ A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 helper=./bin/build-helper MANDIR=docs/man - -MAN1DSTDIR=$(MANDIR)/man1 -MAN7DSTDIR=$(MANDIR)/man7 -MANREF=$(MAN7DSTDIR)/cdist-reference.text -MANREFSH=$(MANDIR)/cdist-reference.text.sh - SPEECHDIR=docs/speeches - TYPEDIR=cdist/conf/type +WEBDIR=$$HOME/www.nico.schottelius.org +WEBBLOG=$(WEBDIR)/blog +WEBTOPDIR=$(WEBDIR)/software +WEBBASE=$(WEBTOPDIR)/cdist +WEBPAGE=$(WEBBASE).mdwn + +CHANGELOG_VERSION=$(shell $(helper) changelog-version) ################################################################################ -# Manpages for types +# Manpages # +MAN1DSTDIR=$(MANDIR)/man1 +MAN7DSTDIR=$(MANDIR)/man7 + +# Manpages #1: Types # Use shell / ls to get complete list - $(TYPEDIR)/*/man.text does not work -TYPEMANSRC=$(shell ls $(TYPEDIR)/*/man.text) +MANTYPESRC=$(shell ls $(TYPEDIR)/*/man.text) # replace first path component -TYPEMANPREFIX=$(subst cdist/conf/type/,docs/man/man7/cdist-type,$(TYPEMANSRC)) +MANTYPEPREFIX=$(subst $(TYPEDIR),$(MAN7DSTDIR)/cdist-type,$(MANTYPESRC)) # replace man.text with .7 or .html -TYPEMANPAGES=$(subst /man.text,.7,$(TYPEMANPREFIX)) -TYPEMANHTML=$(subst /man.text,.html,$(TYPEMANPREFIX)) - +MANTYPEMAN=$(subst /man.text,.7,$(MANTYPEPREFIX)) +MANTYPEHTML=$(subst /man.text,.html,$(MANTYPEPREFIX)) +MANTYPEALL=$(TYPEMANPAGES) $(TYPEMANHTML) # Link manpage so A2XH does not create man.html but correct named file $(MAN7DSTDIR)/cdist-type%.text: $(TYPEDIR)/%/man.text 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): $(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 #4: generic part + # Creating the type manpage -$(MAN7DSTDIR)/cdist-type%.7: $(MAN7DSTDIR)/cdist-type%.text +%.1 %.7: %.text $(A2XM) $^ # Creating the type html page -$(MAN7DSTDIR)/cdist-type%.html: $(MAN7DSTDIR)/cdist-type%.text +%.html: %.text $(A2XH) $^ -typemanpage: $(TYPEMANPAGES) -typemanhtml: $(TYPEMANHTML) +man: $(MANTYPEALL) $(MANREFALL) $(MANSTATICALL) + +# Manpages #5: release part +MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) + +release-man: man + rm -rf "${MANWEBDIR}" + mkdir -p "${MANWEBDIR}/man1" "${MANWEBDIR}/man7" + cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${MANWEBDIR}/man1 + cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${MANWEBDIR}/man7 + cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" ################################################################################ # Speeches # SPEECHESOURCES=$(SPEECHDIR)/*.tex SPEECHES=$(SPEECHESOURCES:.tex=.pdf) +SPEECHESWEBDIR=$(WEBBASE)/speeches # Create speeches and ensure Toc is up-to-date $(SPEECHDIR)/%.pdf: $(SPEECHDIR)/%.tex @@ -76,6 +109,12 @@ $(SPEECHDIR)/%.pdf: $(SPEECHDIR)/%.tex speeches: $(SPEECHES) +release-speeches: speeches + rm -rf "${SPEECHESWEBDIR}" + mkdir -p "${SPEECHESWEBDIR}" + cp ${SPEECHES} "${SPEECHESWEBDIR}" + cd ${SPEECHESWEBDIR} && git add . && git commit -m "cdist speeches updated" + ################################################################################ CHECKS=check-version check-date @@ -98,26 +137,6 @@ $(versionfile): $(DIST): dist-check $(RELEASE): $(DIST) $(CHECKS) -man: $(MANREF) mantype manbuild - -$(MANREF): $(MANREFSH) - $(MANREFSH) - -################################################################################ -# manpage -# generate links from types -# build manpages -# - -mantypedocuments=cdist/conf/type/*/man.text - -mantypelist: $(mantypedocuments) - echo $^ >> $@ - -link-type-manpages: - $(helper) $@ - - ################################################################################ # dist code # @@ -135,7 +154,8 @@ $(archlinuxtar): PKGBUILD dist-pypi ################################################################################ # release code # -release: pub $(RELEASE) +#release: pub $(RELEASE) +release: release-man echo "Don't forget...: linkedin" @@ -157,7 +177,7 @@ PKGBUILD: PKGBUILD.in clean: rm -f $(MAN7DSTDIR)/cdist-reference.text - find "$(MANDIR)" -mindepth 2 -type l \ + find "$(MANDIR)" -mindepth 2 -type l \ -o -name "*.1" \ -o -name "*.7" \ -o -name "*.html" \ @@ -173,9 +193,3 @@ distclean: # Archlinux rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz rm -rf pkg/ src/ - - -################################################################################ -# generic call -%: - $(helper) $@ diff --git a/bin/build-helper b/bin/build-helper index 39c535df..cb12cc7c 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -46,16 +46,6 @@ MAN7DSTDIR=${MANDIR}/man7 SPEECHESDIR=docs/speeches case "$1" in - release-man) - version=$($0 changelog-version) - - rm -rf "${WEBMAN}" - mkdir -p "${WEBMAN}/man1" "${WEBMAN}/man7" - cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${WEBMAN}/man1 - cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${WEBMAN}/man7 - cd ${WEBMAN} && git add . && git commit -m "Cdist Manpage update: $version" - ;; - changelog-changes) awk -F: 'BEGIN { start=0 } { if ($0 ~ /^[[:digit:]]/) { if(start == 0) {start = 1 } else { exit } } else { if(start==1) {print $0 }} }' "$basedir/docs/changelog" ;; @@ -245,12 +235,8 @@ eof echo "VERSION = \"$(git describe)\"" > cdist/version.py ;; - # Targets handled in the makefile - speeches|clean|dist-clean) - ;; - *) - echo "Unknown target $@ - aborting" + echo "Unknown helper target $@ - aborting" exit 1 ;; diff --git a/docs/changelog b/docs/changelog index 830d0207..a3ea62ab 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -next: +2.1.2: 2013-07-09 * Build: Change clean-dist target to "distclean" * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) * Core: Change execution order to run object as one unit diff --git a/docs/web/cdist/documentation.mdwn b/docs/web/cdist/documentation.mdwn index e5fd9bc9..db25b566 100644 --- a/docs/web/cdist/documentation.mdwn +++ b/docs/web/cdist/documentation.mdwn @@ -4,4 +4,6 @@ You can browse the latest [latest version of the manpages](/software/cdist/man/latest) or have a look at [all versions](/software/cdist/man). +You can also view [speeches about cdist](/software/cdist/speeches). + [[!tag cdist unix]] From 9b9f34eb00974275d0c29353b51c64376a6bc019 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 15:32:10 +0200 Subject: [PATCH 140/548] allow changelog-changes to print changes from any version Signed-off-by: Nico Schottelius --- bin/build-helper | 109 ++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 63 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index cb12cc7c..47a51db5 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -27,46 +27,41 @@ cd "$basedir" version=$(git describe) -# Manpage and HTML -A2XM="a2x -f manpage --no-xmllint -a encoding=UTF-8" -A2XH="a2x -f xhtml --no-xmllint -a encoding=UTF-8" +option=$1; shift -# Developer webbase -WEBDIR=$HOME/www.nico.schottelius.org -WEBBLOG=$WEBDIR/blog -WEBTOPDIR=$WEBDIR/software -WEBBASE=$WEBTOPDIR/cdist -WEBMAN=$WEBBASE/man/$version -WEBPAGE=${WEBBASE}.mdwn - -# Documentation -MANDIR=docs/man -MAN1DSTDIR=${MANDIR}/man1 -MAN7DSTDIR=${MANDIR}/man7 -SPEECHESDIR=docs/speeches - -case "$1" in +case "$option" in changelog-changes) - awk -F: 'BEGIN { start=0 } { if ($0 ~ /^[[:digit:]]/) { if(start == 0) {start = 1 } else { exit } } else { if(start==1) {print $0 }} }' "$basedir/docs/changelog" + 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 and ensure it's not already present + # get version from changelog grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/:.*//' ;; - check-version) - changelog_version=$($0 changelog-version) - echo "Target version from changelog: $changelog_version" - - if git show --quiet $changelog_version >/dev/null 2>&1; then - echo "Version $changelog_version already exists, aborting." - exit 1 - fi - ;; - check-date) - # verify date in changelog + # verify date in changelog is today date_today="$(date +%Y-%m-%d)" date_changelog=$(grep '^[[:digit:]]' "$basedir/docs/changelog" | head -n1 | sed 's/.*: //') @@ -77,9 +72,24 @@ case "$1" in fi ;; + check-unittest) + "$0" test + ;; + + check-version) + changelog_version=$($0 changelog-version) + + if git show --quiet $changelog_version >/dev/null 2>&1; then + echo "Version $changelog_version already exists, aborting." + exit 1 + fi + ;; + + blog) - version=$($0 changelog-version) - blogfile=$WEBBLOG/cdist-${version}-released.mdwn + version=$1; shift + blogfile=$1; shift + cat << eof > "$blogfile" [[!meta title="Cdist $version released"]] @@ -94,17 +104,13 @@ For more information visit the [[cdist homepage|software/cdist]]. [[!tag cdist config unix]] eof - ;; - - release-blog) - version=$($0 changelog-version) - file=cdist-${version}-released.mdwn cd "$WEBBLOG" git add "$file" - git commit -m "New cdist version (blogentry): $version" "$file" + git commit -m "New cdist version (blogentry): $version" "$blogfile" git push ;; + release-ml) version=$($0 changelog-version) to_a=cdist @@ -198,31 +204,7 @@ eof ;; - web-doc) - rsync -av "${basedir}/docs/web/" "${WEBTOPDIR}" - - cd "${WEBDIR}" && git add "${WEBBASE}" - cd "${WEBDIR}" && git commit -m "cdist update" "${WEBBASE}" "${WEBPAGE}" - cd "${WEBDIR}" && make pub - ;; - - release-web) - set -e - # Fix ikiwiki, which does not like symlinks for pseudo security - ssh tee.schottelius.org \ - "cd /home/services/www/nico/www.nico.schottelius.org/www/software/cdist/man && - rm -f latest && ln -sf "$version" latest" - ;; - - pub) - for remote in "" github sf; do - echo "Pushing to $remote" - git push --mirror $remote - done - ;; - test) - shift # skip t export PYTHONPATH="$(pwd -P)" if [ $# -lt 1 ]; then @@ -231,6 +213,7 @@ eof python3 -m unittest "$@" fi ;; + version) echo "VERSION = \"$(git describe)\"" > cdist/version.py ;; From 24bb4aa4816c1d6ba5f67824d4ddb1d9bf240dc9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 15:46:57 +0200 Subject: [PATCH 141/548] migrate web publishing to makefile Signed-off-by: Nico Schottelius --- Makefile | 59 +++++++++++++++++++++++++++++++++++++++++------- bin/build-helper | 11 +++++---- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index d43360e7..7d9f14b8 100644 --- a/Makefile +++ b/Makefile @@ -26,13 +26,16 @@ MANDIR=docs/man SPEECHDIR=docs/speeches TYPEDIR=cdist/conf/type +WEBSRCDIR=docs/web + WEBDIR=$$HOME/www.nico.schottelius.org WEBBLOG=$(WEBDIR)/blog -WEBTOPDIR=$(WEBDIR)/software -WEBBASE=$(WEBTOPDIR)/cdist +WEBBASE=$(WEBDIR)/software/cdist WEBPAGE=$(WEBBASE).mdwn CHANGELOG_VERSION=$(shell $(helper) changelog-version) +CHANGELOG_FILE=docs/changelog + ################################################################################ # Manpages # @@ -87,13 +90,20 @@ man: $(MANTYPEALL) $(MANREFALL) $(MANSTATICALL) # Manpages #5: release part MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) -release-man: man +man-git: man rm -rf "${MANWEBDIR}" mkdir -p "${MANWEBDIR}/man1" "${MANWEBDIR}/man7" cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${MANWEBDIR}/man1 cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${MANWEBDIR}/man7 cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" +man-fix-link: + # Fix ikiwiki, which does not like symlinks for pseudo security + ssh tee.schottelius.org \ + "cd /home/services/www/nico/www.nico.schottelius.org/www/software/cdist/man && rm -f latest && ln -sf "$(CHANGELOG_VERSION)" latest" + +man-release: man web-release + ################################################################################ # Speeches # @@ -109,18 +119,42 @@ $(SPEECHDIR)/%.pdf: $(SPEECHDIR)/%.tex speeches: $(SPEECHES) -release-speeches: speeches +speeches-release: speeches rm -rf "${SPEECHESWEBDIR}" mkdir -p "${SPEECHESWEBDIR}" cp ${SPEECHES} "${SPEECHESWEBDIR}" cd ${SPEECHESWEBDIR} && git add . && git commit -m "cdist speeches updated" ################################################################################ -CHECKS=check-version check-date +# 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-pub: web + cd "${WEBDIR}" && make pub + +web-release: web-blog web-doc + cd "${WEBDIR}" && make pub + +################################################################################ +# Release && release check +# +CHECKS=check-version check-date check-unittest DIST=dist-tag dist-branch-merge -RELEASE=release-web release-man release-pypi release-archlinux-makepkg +RELEASE=web-release release-man release-pypi release-archlinux-makepkg RELEASE+=release-blog release-ml RELEASE+=release-freecode release-archlinux-aur-upload @@ -137,6 +171,17 @@ $(versionfile): $(DIST): dist-check $(RELEASE): $(DIST) $(CHECKS) +# Code that is better handled in a shell script +check-%: + $(helper) $@ + +# Pub is Nico's "push to all git remotes" thing +pub: + for remote in "" github sf; do \ + echo "Pushing to $$remote" \ + git push --mirror $$remote \ + done + ################################################################################ # dist code # @@ -166,8 +211,6 @@ release-blog: blog release-ml: release-blog release-pub: man -release-web: web-doc - PKGBUILD: PKGBUILD.in ./PKGBUILD.in diff --git a/bin/build-helper b/bin/build-helper index 47a51db5..e31ff1b5 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -89,6 +89,9 @@ case "$option" in blog) version=$1; shift blogfile=$1; shift + dir=${blogfile%/*} + file=${blogfile##*/} + cat << eof > "$blogfile" [[!meta title="Cdist $version released"]] @@ -97,17 +100,17 @@ Here's a short overview about the changes found in version ${version}: eof - $0 changelog-changes >> "$blogfile" + $0 changelog-changes "$version" >> "$blogfile" cat << eof >> "$blogfile" For more information visit the [[cdist homepage|software/cdist]]. [[!tag cdist config unix]] eof - cd "$WEBBLOG" + cd "$dir" git add "$file" - git commit -m "New cdist version (blogentry): $version" "$blogfile" - git push + # Allow git commit to fail if there are no changes + git commit -m "cdist blog update: $version" "$blogfile" || true ;; From fc9dd61fe0c2902bbf1cc6cc07083889bd1bcc8f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 17:22:56 +0200 Subject: [PATCH 142/548] many release related cleanups Signed-off-by: Nico Schottelius --- .gitignore | 1 + Makefile | 159 +++++++++++++++++++++++++++++------------------ bin/build-helper | 45 ++------------ 3 files changed, 106 insertions(+), 99 deletions(-) diff --git a/.gitignore b/.gitignore index 27455cd9..2c94b56f 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ cdist/version.py /pkg /src build +.lock-* diff --git a/Makefile b/Makefile index 7d9f14b8..b0b57903 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,9 @@ # # +# dist = local +# release = remote + A2XM=a2x -f manpage --no-xmllint -a encoding=UTF-8 A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 helper=./bin/build-helper @@ -36,6 +39,8 @@ WEBPAGE=$(WEBBASE).mdwn CHANGELOG_VERSION=$(shell $(helper) changelog-version) CHANGELOG_FILE=docs/changelog +VERSION_FILE=cdist/version.py + ################################################################################ # Manpages # @@ -90,20 +95,18 @@ man: $(MANTYPEALL) $(MANREFALL) $(MANSTATICALL) # Manpages #5: release part MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) -man-git: man +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 cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" -man-fix-link: +man-release: web-release # Fix ikiwiki, which does not like symlinks for pseudo security ssh tee.schottelius.org \ "cd /home/services/www/nico/www.nico.schottelius.org/www/software/cdist/man && rm -f latest && ln -sf "$(CHANGELOG_VERSION)" latest" -man-release: man web-release - ################################################################################ # Speeches # @@ -119,11 +122,11 @@ $(SPEECHDIR)/%.pdf: $(SPEECHDIR)/%.tex speeches: $(SPEECHES) -speeches-release: speeches +speeches-dist: speeches rm -rf "${SPEECHESWEBDIR}" mkdir -p "${SPEECHESWEBDIR}" cp ${SPEECHES} "${SPEECHESWEBDIR}" - cd ${SPEECHESWEBDIR} && git add . && git commit -m "cdist speeches updated" + cd ${SPEECHESWEBDIR} && git add . && git commit -m "cdist speeches updated" || true ################################################################################ # Website @@ -141,31 +144,105 @@ web-doc: rsync -av "$(WEBSRCDIR)/" "${WEBBASE}/.." cd "${WEBBASE}/.." && git add cdist* && git commit -m "cdist doc update" cdist* || true -web-pub: web - cd "${WEBDIR}" && make pub +web-dist: web-blog web-doc -web-release: web-blog web-doc +web-release: web-dist man-dist speeches-dist cd "${WEBDIR}" && make pub ################################################################################ -# Release && release check +# Release: Mailinglist # -CHECKS=check-version check-date check-unittest +ML_FILE=.lock-ml -DIST=dist-tag dist-branch-merge +# Only send mail once - lock until new changelog things happened +$(ML_FILE): $(CHANGELOG_FILE) + $(helper) ml-release $(CHANGELOG_VERSION) + touch $@ -RELEASE=web-release release-man release-pypi release-archlinux-makepkg -RELEASE+=release-blog release-ml -RELEASE+=release-freecode release-archlinux-aur-upload +ml-release: $(ML_FILE) -version=`git describe` -versionchangelog=`$(helper) changelog-version` -versionfile=cdist/version.py -archlinuxtar=cdist-${versionchangelog}-1.src.tar.gz +################################################################################ +# Release: Freecode +# +FREECODE_FILE=.lock-freecode -$(versionfile): - $(helper) version +$(FREECODE_FILE): $(CHANGELOG_FILE) + $(helper) freecode-release $(CHANGELOG_VERSION) + touch $@ + +freecode-release: $(FREECODE_FILE) + +################################################################################ +# git and git dependent stuff +# + +GIT_TAG_FILE=.git/refs/tags/$(CHANGELOG_VERSION) +GIT_SRC_BRANCH=master +GIT_DST_BRANCH=$(shell echo $(CHANGELOG_VERSION) | cut -d. -f '1,2') + +git-tag: $(GIT_TAG_FILE) + +$(GIT_TAG_FILE): + @printf "Enter tag description for $(CHANGELOG_VERSION)> " + @read tagmessage; git tag "$(CHANGELOG_VERSION)" -m "$$tagmessage" + +#git-branch-merge: git-tag +git-branch-merge: + echo $(GIT_DST_BRANCH) + current=$$(git rev-parse --abbrev-ref HEAD) \ + git checkout "$(GIT_DST_BRANCH)" \ + git merge "$(GIT_SRC_BRANCH)" + git checkout "$$current" + + +$(VERSION_FILE): .git/refs/heads/* + echo "VERSION = \"$$(git describe)\"" > $@ + +# Pub is Nico's "push to all git remotes" thing +# git-release is the better term +git-release pub: + for remote in "" github sf; do \ + echo "Pushing to $$remote" \ + git push --mirror $$remote \ + done + +################################################################################ +# pypi +# +pypi-release: man $(VERSION_FILE) git-tag + python3 setup.py sdist upload + +################################################################################ +# archlinux +# +ARCHLINUXTAR=cdist-$(CHANGELOG_VERSION)-1.src.tar.gz +$(ARCHLINUXTAR): PKGBUILD pypi-release + makepkg -c --source + +PKGBUILD: PKGBUILD.in + ./PKGBUILD.in + +archlinux-release: $(ARCHLINUXTAR) + burp -c system $^ + +################################################################################ +# Release +# + +CHECKS=check-date check-unittest + +RELEASE=speeches-dist web-release +RELEASE+=ml-release freecode-release +RELEASE+=man-dist pypi-release git-release +RELEASE+=archlinux-release + +release: $(RELEASE) + echo "Don't forget...: linkedin" + +release-blog: blog +release-ml: release-blog +release-pub: man $(DIST): dist-check @@ -175,47 +252,9 @@ $(RELEASE): $(DIST) $(CHECKS) check-%: $(helper) $@ -# Pub is Nico's "push to all git remotes" thing -pub: - for remote in "" github sf; do \ - echo "Pushing to $$remote" \ - git push --mirror $$remote \ - done - -################################################################################ -# dist code -# -dist-check: man - -dist: $(DIST) - echo "Run \"make release\" to release to the public" - -dist-pypi: man version - python3 setup.py sdist upload - -$(archlinuxtar): PKGBUILD dist-pypi - makepkg -c --source - -################################################################################ -# release code -# -#release: pub $(RELEASE) -release: release-man - echo "Don't forget...: linkedin" - - -release-archlinux: $(archlinuxtar) - burp -c system $^ - -release-blog: blog -release-ml: release-blog -release-pub: man - -PKGBUILD: PKGBUILD.in - ./PKGBUILD.in - ################################################################################ # Cleanup +# clean: rm -f $(MAN7DSTDIR)/cdist-reference.text diff --git a/bin/build-helper b/bin/build-helper index e31ff1b5..adcb384d 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -76,16 +76,6 @@ case "$option" in "$0" test ;; - check-version) - changelog_version=$($0 changelog-version) - - if git show --quiet $changelog_version >/dev/null 2>&1; then - echo "Version $changelog_version already exists, aborting." - exit 1 - fi - ;; - - blog) version=$1; shift blogfile=$1; shift @@ -113,12 +103,13 @@ eof git commit -m "cdist blog update: $version" "$blogfile" || true ;; + ml-release) + version=$1; shift - release-ml) - version=$($0 changelog-version) to_a=cdist to_d=l.schottelius.org to=${to_a}@${to_d} + to=n@schottelius.org from_a=nico-cdist from_d=schottelius.org @@ -136,7 +127,7 @@ cdist $version has been released with the following changes: eof - "$0" changelog-changes + "$0" changelog-changes "$version" cat << eof Cheers, @@ -150,32 +141,8 @@ eof ;; - dist-tag) - version=$($0 changelog-version) - # add tag - printf "Enter tag description for %s> " "$version" - read tagmessage - git tag "$version" -m "$tagmessage" - ;; - - dist-branch-merge) - version=$($0 changelog-version) - target_branch=${version%\.*} - current_branch=$(git rev-parse --abbrev-ref HEAD) - - if [ "$target_branch" = "$current_branch" ]; then - echo "Skipping merge, already on destination branch" - else - printf "Press enter to git merge $current_branch into \"$target_branch\" > " - read prompt - git checkout "$target_branch" - git merge "$current_branch" - git checkout "$current_branch" - fi - ;; - - release-freecode) - version=$($0 changelog-version) + freecode-release) + version=$1; shift api_token=$(awk '/machine freecode login/ { print $8 }' ~/.netrc) printf "Enter tag list for freecode release %s> " "$version" From ce27012d623bef939e84ebf881e0a6a37de9c671 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 17:24:22 +0200 Subject: [PATCH 143/548] ++ && Signed-off-by: Nico Schottelius --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b0b57903..c10b92bb 100644 --- a/Makefile +++ b/Makefile @@ -189,10 +189,9 @@ $(GIT_TAG_FILE): #git-branch-merge: git-tag git-branch-merge: - echo $(GIT_DST_BRANCH) current=$$(git rev-parse --abbrev-ref HEAD) \ - git checkout "$(GIT_DST_BRANCH)" \ - git merge "$(GIT_SRC_BRANCH)" + git checkout "$(GIT_DST_BRANCH)" && \ + git merge "$(GIT_SRC_BRANCH)" && \ git checkout "$$current" From d6d56043cea5fde47c46a62fa7555117af376f0b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 17:28:24 +0200 Subject: [PATCH 144/548] fix git-branch-merge Signed-off-by: Nico Schottelius --- Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index c10b92bb..7064b364 100644 --- a/Makefile +++ b/Makefile @@ -187,9 +187,8 @@ $(GIT_TAG_FILE): @printf "Enter tag description for $(CHANGELOG_VERSION)> " @read tagmessage; git tag "$(CHANGELOG_VERSION)" -m "$$tagmessage" -#git-branch-merge: git-tag git-branch-merge: - current=$$(git rev-parse --abbrev-ref HEAD) \ + current=$$(git rev-parse --abbrev-ref HEAD); \ git checkout "$(GIT_DST_BRANCH)" && \ git merge "$(GIT_SRC_BRANCH)" && \ git checkout "$$current" @@ -199,13 +198,15 @@ $(VERSION_FILE): .git/refs/heads/* echo "VERSION = \"$$(git describe)\"" > $@ # Pub is Nico's "push to all git remotes" thing -# git-release is the better term -git-release pub: +pub: for remote in "" github sf; do \ echo "Pushing to $$remote" \ git push --mirror $$remote \ done +git-release: git-tag git-branch-merge + make pub + ################################################################################ # pypi # From 40acd273195d65a21581906b913069418d34a3f7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 17:30:00 +0200 Subject: [PATCH 145/548] remove wrong mail address Signed-off-by: Nico Schottelius --- bin/build-helper | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/build-helper b/bin/build-helper index adcb384d..54940ab2 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -109,7 +109,6 @@ eof to_a=cdist to_d=l.schottelius.org to=${to_a}@${to_d} - to=n@schottelius.org from_a=nico-cdist from_d=schottelius.org From bf9ad8b25c47c74e19aed7bb9f07a397f7e3810c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 17:47:34 +0200 Subject: [PATCH 146/548] cleanup more release related stuff Signed-off-by: Nico Schottelius --- Makefile | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 7064b364..26273258 100644 --- a/Makefile +++ b/Makefile @@ -194,7 +194,7 @@ git-branch-merge: git checkout "$$current" -$(VERSION_FILE): .git/refs/heads/* +$(VERSION_FILE): .git/refs/heads/* .git/refs/tags/* echo "VERSION = \"$$(git describe)\"" > $@ # Pub is Nico's "push to all git remotes" thing @@ -220,7 +220,7 @@ ARCHLINUXTAR=cdist-$(CHANGELOG_VERSION)-1.src.tar.gz $(ARCHLINUXTAR): PKGBUILD pypi-release makepkg -c --source -PKGBUILD: PKGBUILD.in +PKGBUILD: PKGBUILD.in $(VERSION_FILE) ./PKGBUILD.in archlinux-release: $(ARCHLINUXTAR) @@ -237,16 +237,8 @@ RELEASE+=ml-release freecode-release RELEASE+=man-dist pypi-release git-release RELEASE+=archlinux-release -release: $(RELEASE) - echo "Don't forget...: linkedin" - -release-blog: blog -release-ml: release-blog -release-pub: man - - -$(DIST): dist-check -$(RELEASE): $(DIST) $(CHECKS) +release: $(CHECKS) $(RELEASE) + echo "Manual steps: linkedin, twitter" # Code that is better handled in a shell script check-%: From a66bc8c343a9f1c45cfe9f9719e539c3b5d27658 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 17:48:58 +0200 Subject: [PATCH 147/548] always merge tag based, not branch based, for releases Signed-off-by: Nico Schottelius --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 26273258..5d5e8157 100644 --- a/Makefile +++ b/Makefile @@ -187,10 +187,10 @@ $(GIT_TAG_FILE): @printf "Enter tag description for $(CHANGELOG_VERSION)> " @read tagmessage; git tag "$(CHANGELOG_VERSION)" -m "$$tagmessage" -git-branch-merge: +git-branch-merge: git-tag current=$$(git rev-parse --abbrev-ref HEAD); \ git checkout "$(GIT_DST_BRANCH)" && \ - git merge "$(GIT_SRC_BRANCH)" && \ + git merge "$(CHANGELOG_VERSION)" && \ git checkout "$$current" From 511e7951c83c32b244a392784913a89b396e00f4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 17:56:11 +0200 Subject: [PATCH 148/548] do pypi release only once Signed-off-by: Nico Schottelius --- Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5d5e8157..e6a9547e 100644 --- a/Makefile +++ b/Makefile @@ -210,8 +210,13 @@ git-release: git-tag git-branch-merge ################################################################################ # pypi # -pypi-release: man $(VERSION_FILE) git-tag +PYPI_FILE=.lock-pypi + +pypi-release: $(PYPI_FILE) + +$(PYPI_FILE): man $(VERSION_FILE) git-tag python3 setup.py sdist upload + touch $@ ################################################################################ # archlinux From 02c8079fef55183bee2fb83cd219974752df866d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 18:02:32 +0200 Subject: [PATCH 149/548] move pypi releases to go from the stable branch only Signed-off-by: Nico Schottelius --- Makefile | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index e6a9547e..3660a3c2 100644 --- a/Makefile +++ b/Makefile @@ -180,6 +180,7 @@ freecode-release: $(FREECODE_FILE) GIT_TAG_FILE=.git/refs/tags/$(CHANGELOG_VERSION) GIT_SRC_BRANCH=master GIT_DST_BRANCH=$(shell echo $(CHANGELOG_VERSION) | cut -d. -f '1,2') +GIT_CURRENT=.git-current-branch git-tag: $(GIT_TAG_FILE) @@ -187,14 +188,18 @@ $(GIT_TAG_FILE): @printf "Enter tag description for $(CHANGELOG_VERSION)> " @read tagmessage; git tag "$(CHANGELOG_VERSION)" -m "$$tagmessage" -git-branch-merge: git-tag - current=$$(git rev-parse --abbrev-ref HEAD); \ - git checkout "$(GIT_DST_BRANCH)" && \ - git merge "$(CHANGELOG_VERSION)" && \ - git checkout "$$current" +git-branch-merge: git-checkout-stable + git merge "$(CHANGELOG_VERSION)" +git-checkout-stable: git-tag + @git rev-parse --abbrev-ref HEAD > $(GIT_CURRENT) + @git checkout "$(GIT_DST_BRANCH)" + make git-checkout-current -$(VERSION_FILE): .git/refs/heads/* .git/refs/tags/* +git-checkout-current: + git checkout "$$(cat $(GIT_CURRENT))" + +$(VERSION_FILE): .git/refs/heads/* .git/refs/tags/* .git/HEAD echo "VERSION = \"$$(git describe)\"" > $@ # Pub is Nico's "push to all git remotes" thing @@ -214,9 +219,11 @@ PYPI_FILE=.lock-pypi pypi-release: $(PYPI_FILE) -$(PYPI_FILE): man $(VERSION_FILE) git-tag +$(PYPI_FILE): man $(VERSION_FILE) + make git-checkout-stable python3 setup.py sdist upload touch $@ + make git-checkout-current ################################################################################ # archlinux From db717ab660b1ae855d80d67dcc040f5a346e6249 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 18:11:27 +0200 Subject: [PATCH 150/548] begin minimal protection against double upload Signed-off-by: Nico Schottelius --- .gitignore | 1 + Makefile | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 2c94b56f..76ed1fcb 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ cdist/version.py /src build .lock-* +.git-current-branch diff --git a/Makefile b/Makefile index 3660a3c2..937d70c7 100644 --- a/Makefile +++ b/Makefile @@ -194,7 +194,6 @@ git-branch-merge: git-checkout-stable git-checkout-stable: git-tag @git rev-parse --abbrev-ref HEAD > $(GIT_CURRENT) @git checkout "$(GIT_DST_BRANCH)" - make git-checkout-current git-checkout-current: git checkout "$$(cat $(GIT_CURRENT))" @@ -228,15 +227,20 @@ $(PYPI_FILE): man $(VERSION_FILE) ################################################################################ # archlinux # +ARCHLINUX_FILE=.lock-archlinux ARCHLINUXTAR=cdist-$(CHANGELOG_VERSION)-1.src.tar.gz + $(ARCHLINUXTAR): PKGBUILD pypi-release makepkg -c --source PKGBUILD: PKGBUILD.in $(VERSION_FILE) ./PKGBUILD.in -archlinux-release: $(ARCHLINUXTAR) - burp -c system $^ +$(ARCHLINUX_FILE): $(ARCHLINUXTAR) $(VERSION_FILE) + burp -c system $(ARCHLINUXTAR) + touch $@ + +archlinux-release: $(ARCHLINUX_FILE) ################################################################################ # Release From 6c2ee6346f4a0bd4ec1fd180f96c133096361a6e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 18:15:29 +0200 Subject: [PATCH 151/548] fix target pub: Signed-off-by: Nico Schottelius --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 937d70c7..684675d3 100644 --- a/Makefile +++ b/Makefile @@ -204,8 +204,8 @@ $(VERSION_FILE): .git/refs/heads/* .git/refs/tags/* .git/HEAD # Pub is Nico's "push to all git remotes" thing pub: for remote in "" github sf; do \ - echo "Pushing to $$remote" \ - git push --mirror $$remote \ + echo "Pushing to $$remote"; \ + git push --mirror $$remote; \ done git-release: git-tag git-branch-merge From ddaece5b5785856658408697ce63221d8f476e80 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 18:40:27 +0200 Subject: [PATCH 152/548] fix mantype dependency Signed-off-by: Nico Schottelius --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3660a3c2..b1ee1725 100644 --- a/Makefile +++ b/Makefile @@ -52,12 +52,12 @@ MAN7DSTDIR=$(MANDIR)/man7 MANTYPESRC=$(shell ls $(TYPEDIR)/*/man.text) # replace first path component -MANTYPEPREFIX=$(subst $(TYPEDIR),$(MAN7DSTDIR)/cdist-type,$(MANTYPESRC)) +MANTYPEPREFIX=$(subst $(TYPEDIR)/,$(MAN7DSTDIR)/cdist-type,$(MANTYPESRC)) # replace man.text with .7 or .html MANTYPEMAN=$(subst /man.text,.7,$(MANTYPEPREFIX)) MANTYPEHTML=$(subst /man.text,.html,$(MANTYPEPREFIX)) -MANTYPEALL=$(TYPEMANPAGES) $(TYPEMANHTML) +MANTYPEALL=$(MANTYPEMAN) $(MANTYPEHTML) # Link manpage so A2XH does not create man.html but correct named file $(MAN7DSTDIR)/cdist-type%.text: $(TYPEDIR)/%/man.text From 68dc9d5d4b4e2d8f5c779ef50c52a871dc4653a1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 9 Jul 2013 18:41:27 +0200 Subject: [PATCH 153/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/changelog b/docs/changelog index a3ea62ab..e07f861c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,11 +4,19 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +next: + * Build: Fixed several small issues in the Makefile + + 2.1.2: 2013-07-09 * Build: Change clean-dist target to "distclean" + * Build: Moved a lot of build logic into Makefile for dependency resolution * Core: Make global explorers available to initial manifest (Arkaitz Jimenez) * Core: Change execution order to run object as one unit + * Documentation: Improved documentation (Tomáš Pospíšek) * New Remote Example: Add support for sudo operations (Chase James) + * New Type: __update_alternatives + * New Type: __cdist * Type __apt_ppa: Fix comparison operator (Tyler Akins) * Type __start_on_boot: Archlinux changed to use systemd - adapt type * Type __git: Missing quotes added (Chase James) @@ -16,10 +24,6 @@ Changelog * Type __postgres_role: Make state parameter optional, fix password bug (Chase James) * Type __process: Make state parameter optional * Type __cron: Simplyfied and syntax change - * New Type: __update_alternatives - * New Type: __cdist - * Improved documentation (Tomáš Pospíšek) - * Moved a lot of build logic into Makefile for dependency resolution 2.1.1: 2013-04-08 * Core: Use dynamic dependency resolver to allow indirect self dependencies From ff50a61344f2382d53bb4ea0c926c3872ffb870f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Jul 2013 14:16:56 +0200 Subject: [PATCH 154/548] use shortcut version in __package_opkg Signed-off-by: Nico Schottelius --- cdist/conf/type/__package_opkg/gencode-remote | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/cdist/conf/type/__package_opkg/gencode-remote b/cdist/conf/type/__package_opkg/gencode-remote index 43f1ad8a..1fb78fbe 100755 --- a/cdist/conf/type/__package_opkg/gencode-remote +++ b/cdist/conf/type/__package_opkg/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011,2013 Nico Schottelius (nico-cdist at schottelius.org) # 2012 Giel van Schijndel (giel plus cdist at mortis dot eu) # # This file is part of cdist. @@ -42,20 +42,20 @@ case "$state_is" in ;; esac -if [ "$state_is" != "$state_should" ]; then - case "$state_should" in - present) - if [ "$present" = "notpresent" ]; then +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + if [ "$present" = "notpresent" ]; then echo opkg --verbosity=0 update - fi - echo opkg --verbosity=0 install \"$name\" - ;; - absent) - echo opkg --verbosity=0 remove \"$name\" - ;; - *) - echo "Unknown state: $state" >&2 - exit 1 - ;; - esac -fi + fi + echo opkg --verbosity=0 install \"$name\" + ;; + absent) + echo opkg --verbosity=0 remove \"$name\" + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; +esac From f85a110efc6fdda0129ecaad00f3b9b8664255bf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Jul 2013 14:17:34 +0200 Subject: [PATCH 155/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index e07f861c..552ba56b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,7 +6,7 @@ Changelog next: * Build: Fixed several small issues in the Makefile - + * Type __package_opkg: Use shortcut version 2.1.2: 2013-07-09 * Build: Change clean-dist target to "distclean" From 7205cd5ecf927f02aa6ec4883e81c603b6102b5b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 10 Jul 2013 16:31:58 +0200 Subject: [PATCH 156/548] remove that crappy old singleton object_id thingy Signed-off-by: Steven Armstrong --- cdist/core/cdist_object.py | 3 +-- cdist/emulator.py | 14 ++++++-------- cdist/test/emulator/__init__.py | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 04fb404c..e3c1c532 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -65,7 +65,7 @@ class CdistObject(object): STATE_RUNNING = "running" STATE_DONE = "done" - def __init__(self, cdist_type, base_path, object_id=None): + def __init__(self, cdist_type, base_path, object_id=''): self.cdist_type = cdist_type # instance of Type self.base_path = base_path self.object_id = object_id @@ -107,7 +107,6 @@ class CdistObject(object): """ type_name = object_name.split(os.sep)[0] - # FIXME: allow object without object_id? e.g. for singleton object_id = os.sep.join(object_name.split(os.sep)[1:]) return type_name, object_id diff --git a/cdist/emulator.py b/cdist/emulator.py index 5a23fca5..add20e70 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -34,7 +34,7 @@ class Emulator(object): self.stdin = stdin self.env = env - self.object_id = False + self.object_id = '' self.global_path = self.env['__global'] self.target_host = self.env['__target_host'] @@ -54,10 +54,10 @@ class Emulator(object): """Add hostname and object to logs via logging Filter""" prefix = self.target_host + ": (emulator)" - - if self.object_id: - prefix = prefix + " " + self.type_name + "/" + self.object_id - + prefix = '{0}: emulator {1}'.format( + self.target_host, + core.CdistObject.join_name(self.type_name, self.object_id) + ) record.msg = prefix + ": " + record.msg return True @@ -122,9 +122,7 @@ class Emulator(object): def setup_object(self): # Setup object_id - FIXME: unset / do not setup anymore! - if self.cdist_type.is_singleton: - self.object_id = "singleton" - else: + if not self.cdist_type.is_singleton: self.object_id = self.args.object_id[0] del self.args.object_id diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index a9746f99..b3661bd7 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -118,7 +118,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, 'singleton') + cdist_object = core.CdistObject(cdist_type, self.local.object_path) self.manifest.run_type_manifest(cdist_object) expected = ['__planet/Saturn', '__moon/Prometheus'] self.assertEqual(sorted(cdist_object.autorequire), sorted(expected)) From edaae74d47b968ebe66407655d270a182c0e914f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Jul 2013 17:01:35 +0200 Subject: [PATCH 157/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 552ba56b..97589d70 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog next: * Build: Fixed several small issues in the Makefile * Type __package_opkg: Use shortcut version + * Core: Remove old pseudo object id "singleton" (Steven Armstrong) 2.1.2: 2013-07-09 * Build: Change clean-dist target to "distclean" From 55402fa3cffc33179885f831c11c1ac626225706 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Jul 2013 17:02:11 +0200 Subject: [PATCH 158/548] remove whitespace Signed-off-by: Nico Schottelius --- Makefile | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 63a61d5f..cb00afe1 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ MANTYPESRC=$(shell ls $(TYPEDIR)/*/man.text) MANTYPEPREFIX=$(subst $(TYPEDIR)/,$(MAN7DSTDIR)/cdist-type,$(MANTYPESRC)) # replace man.text with .7 or .html -MANTYPEMAN=$(subst /man.text,.7,$(MANTYPEPREFIX)) +MANTYPEMAN=$(subst /man.text,.7,$(MANTYPEPREFIX)) MANTYPEHTML=$(subst /man.text,.html,$(MANTYPEPREFIX)) MANTYPEALL=$(MANTYPEMAN) $(MANTYPEHTML) @@ -76,8 +76,8 @@ $(MANREF): $(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) +MANSTATICMAN=$(MAN1STATIC:.text=.1) $(MAN7STATIC:.text=.7) +MANSTATICHTML=$(MAN1STATIC:.text=.html) $(MAN7STATIC:.text=.html) MANSTATICALL=$(MANSTATICMAN) $(MANSTATICHTML) # Manpages #4: generic part @@ -201,13 +201,6 @@ git-checkout-current: $(VERSION_FILE): .git/refs/heads/* .git/refs/tags/* .git/HEAD echo "VERSION = \"$$(git describe)\"" > $@ -# Pub is Nico's "push to all git remotes" thing -pub: - for remote in "" github sf; do \ - echo "Pushing to $$remote"; \ - git push --mirror $$remote; \ - done - git-release: git-tag git-branch-merge make pub @@ -248,7 +241,7 @@ archlinux-release: $(ARCHLINUX_FILE) CHECKS=check-date check-unittest -RELEASE=speeches-dist web-release +RELEASE=speeches-dist web-release RELEASE+=ml-release freecode-release RELEASE+=man-dist pypi-release git-release RELEASE+=archlinux-release @@ -274,7 +267,7 @@ clean: -o -name "*.xml" \ | xargs rm -f - find * -name __pycache__ | xargs rm -rf + find * -name __pycache__ | xargs rm -rf distclean: rm -f cdist/version.py MANIFEST PKGBUILD @@ -283,3 +276,17 @@ distclean: # Archlinux rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz rm -rf pkg/ src/ + +################################################################################ +# Misc +# + +# The pub is Nico's "push to all git remotes" way ("make pub") +pub: + for remote in "" github sf; do \ + echo "Pushing to $$remote"; \ + git push --mirror $$remote; \ + done + +test: + $(helper) $@ From 8ab760ad908a93300d790b078856cf471f5bd448 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Jul 2013 17:02:19 +0200 Subject: [PATCH 159/548] document unit test Signed-off-by: Nico Schottelius --- cdist/test/emulator/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index b3661bd7..5645e73c 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -170,7 +170,8 @@ class ArgumentsTestCase(test.CdistTestCase): # empty file -> True self.assertTrue(cdist_object.parameters['boolean1'] == '') - def test_required(self): + def test_required_arguments(self): + """check whether assigning required parameter works""" type_name = '__arguments_required' object_id = 'some-id' value = 'some value' From c1441fc676aed82aee69322ea0d7fafbf027c68b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 10 Jul 2013 17:21:38 +0200 Subject: [PATCH 160/548] enhance singleton testing Signed-off-by: Nico Schottelius --- cdist/test/cdist_object/__init__.py | 10 ++++++++++ .../fixtures/type/__test_singleton/singleton | 0 cdist/test/emulator/__init__.py | 7 +++++++ .../fixtures/conf/type/__test_singleton/singleton | 0 4 files changed, 17 insertions(+) create mode 100644 cdist/test/cdist_object/fixtures/type/__test_singleton/singleton create mode 100644 cdist/test/emulator/fixtures/conf/type/__test_singleton/singleton diff --git a/cdist/test/cdist_object/__init__.py b/cdist/test/cdist_object/__init__.py index 70506da4..ffb2ba79 100644 --- a/cdist/test/cdist_object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -64,6 +64,16 @@ class ObjectClassTestCase(test.CdistTestCase): found_objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) 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") + # came here - everything fine + + def test_create_singleton_not_singleton_type(self): + """try to create an object of a type that is not a singleton + without an object id""" + with self.assertRaises(cdist.core.cdist_object.MissingObjectIdError): + self.expected_objects[0].object_from_name("__first") class ObjectIdTestCase(test.CdistTestCase): def test_object_id_contains_double_slash(self): diff --git a/cdist/test/cdist_object/fixtures/type/__test_singleton/singleton b/cdist/test/cdist_object/fixtures/type/__test_singleton/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 5645e73c..ec0d7ae4 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -83,6 +83,13 @@ class EmulatorTestCase(test.CdistTestCase): emu = emulator.Emulator(argv, env=self.env) self.assertRaises(core.cdist_object.MissingObjectIdError, emu.run) + def test_no_singleton_no_requirement(self): + argv = ['__file', '/tmp/foobar'] + self.env['require'] = '__test_singleton' + emu = emulator.Emulator(argv, env=self.env) + emu.run() + # If reached here, everything is fine + def test_singleton_object_requirement(self): argv = ['__file', '/tmp/foobar'] self.env['require'] = '__issue' diff --git a/cdist/test/emulator/fixtures/conf/type/__test_singleton/singleton b/cdist/test/emulator/fixtures/conf/type/__test_singleton/singleton new file mode 100644 index 00000000..e69de29b From ff9b2fe6f4b068f23011fa261fa29aae1ca86879 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 11 Jul 2013 11:46:14 +0200 Subject: [PATCH 161/548] singleton change -> requires new minor version Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- docs/{changelog.2.2 => changelog.2.3} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/{changelog.2.2 => changelog.2.3} (100%) diff --git a/docs/changelog b/docs/changelog index 97589d70..98e021f9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -next: +2.2.0: 2013-07-11 * Build: Fixed several small issues in the Makefile * Type __package_opkg: Use shortcut version * Core: Remove old pseudo object id "singleton" (Steven Armstrong) diff --git a/docs/changelog.2.2 b/docs/changelog.2.3 similarity index 100% rename from docs/changelog.2.2 rename to docs/changelog.2.3 From c7811fb056a5d77fbab18b3afd2bcf939d2adfa0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 12 Jul 2013 19:36:49 +0200 Subject: [PATCH 162/548] restore cdist-type.text Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-type.text | 280 ++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 docs/man/man7/cdist-type.text diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text new file mode 100644 index 00000000..cfb50414 --- /dev/null +++ b/docs/man/man7/cdist-type.text @@ -0,0 +1,280 @@ +cdist-type(7) +============= +Nico Schottelius + + +NAME +---- +cdist-type - Functionality bundled + + +SYNOPSIS +-------- +__TYPE ID --parameter value [--parameter value ...] + +__TYPE --parameter value [--parameter value ...] (for singletons) + + +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. + + +HOW TO USE A TYPE +----------------- +You can use types from the initial manifest or the type manifest like a +normal command: + +-------------------------------------------------------------------------------- +# 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. + + +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 +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 +-------------------------------------------------------------------------------- + + +HOW TO WRITE A NEW TYPE +----------------------- +A type consists of + +- parameter (optional) +- manifest (optional) +- singleton (optional) +- explorer (optional) +- gencode (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. + +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***. +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". +If either is missing, the type will have no required, no optional, no boolean +or no parameters at all. + +Example: +-------------------------------------------------------------------------------- +echo servername >> cdist/conf/type/__nginx_vhost/parameter/required +echo logdirectory >> cdist/conf/type/__nginx_vhost/parameter/optional +echo server_alias >> cdist/conf/type/__nginx_vhost/parameter/optional_multiple +echo use_ssl >> cdist/conf/type/__nginx_vhost/parameter/boolean +-------------------------------------------------------------------------------- + + +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 +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 + +# 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. + +Example use of a type: (e.g. in cdist/conf/type/__archlinux_hostname) +-------------------------------------------------------------------------------- +__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: + +-------------------------------------------------------------------------------- + if [ -f "$__object/parameter/source" ]; then + source="$(cat "$__object/parameter/source")" + if [ "$source" = "-" ]; then + source="$__object/stdin" + fi + .... +-------------------------------------------------------------------------------- + + +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 +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 + +__package_$type "$@" +-------------------------------------------------------------------------------- + +As you can see, the type can reference different environment variables, +which are documented in cdist-reference(7). + +Always ensure the manifest is executable, otherwise cdist will not be able +to execute it. For more information about manifests see cdist-manifest(7). + + +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 +directory: + +-------------------------------------------------------------------------------- +touch cdist/conf/type/__NAME/singleton +-------------------------------------------------------------------------------- + +This will also change the way your type must be called: + +-------------------------------------------------------------------------------- +__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. + + +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. + +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 + +if [ -e "$destination" ]; then + md5sum < "$destination" +fi +-------------------------------------------------------------------------------- + + +WRITING THE GENCODE SCRIPT +-------------------------- +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 +and the type specific explorers. + +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 + +# Output to be saved by cdist for execution on the target +echo "touch /etc/cdist-configured" +-------------------------------------------------------------------------------- + + +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 +on the target, there must be another type that provides this tool and the first +type should create an object of the specific type. + +If your type wants to save temporary data, that may be used by other types +later on (for instance __file), you can save them in the subdirectory +"files" below $__object (but you must create it yourself). +cdist will not touch this directory. + +If your type contains static files, it's also recommended to place them in +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 +----------------------------------------- +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 +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). From 24019a71750699c77d934154b9ea71662f0f19fa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 12 Jul 2013 19:40:31 +0200 Subject: [PATCH 163/548] add update instructions for 2.2 Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index e486dff9..f3def316 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -22,6 +22,23 @@ To upgrade to the lastet version do ## Update Instructions +### 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]]. From c3e6eaffcdc13bf6c4532747bf9b5e1c01f5fa15 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 12 Jul 2013 19:41:38 +0200 Subject: [PATCH 164/548] cleanup the cleanup targets Signed-off-by: Nico Schottelius --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cb00afe1..0fa6965d 100644 --- a/Makefile +++ b/Makefile @@ -269,9 +269,9 @@ clean: find * -name __pycache__ | xargs rm -rf -distclean: +distclean: clean rm -f cdist/version.py MANIFEST PKGBUILD - rm -rf cache/ dist/ + rm -rf dist/ # Archlinux rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz From b2e46e342939b9f0db5dbfcbd537242497aeb045 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 12 Jul 2013 20:40:02 +0200 Subject: [PATCH 165/548] have pkgbuild.in depend on $@ Signed-off-by: Nico Schottelius --- PKGBUILD.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PKGBUILD.in b/PKGBUILD.in index 68bd6add..e3ae4619 100755 --- a/PKGBUILD.in +++ b/PKGBUILD.in @@ -1,6 +1,6 @@ #!/bin/sh -version=$(git describe) +version="$1" outfile=${0%.in} cat << eof > "${outfile}" From c0c97a1207b52029fde798858c20fba33b63bf19 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 12 Jul 2013 20:42:47 +0200 Subject: [PATCH 166/548] add schedule for releases Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-07-12.release | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/dev/logs/2013-07-12.release diff --git a/docs/dev/logs/2013-07-12.release b/docs/dev/logs/2013-07-12.release new file mode 100644 index 00000000..f3f1d8d3 --- /dev/null +++ b/docs/dev/logs/2013-07-12.release @@ -0,0 +1,36 @@ +- setup release date in docs/changelog to today manually + +- checkout master branch + [ + - check if date is correct in docs/changelog + - ensure all unittests work + - compile manpages + - compile speeches + ] + [ + - add manpages to website repo + - add speeches to website repo + - rsync cdist docs to website repo & add to website repo + - create blog entry & add to website repo + ] + - upload website + - fix latest link for manpages + - send mail to mailinglist + + - create PKGBUILD for archlinux release + + - create git tag / read description + - if necessary create version branch + - change to version branch and merge master branch + - update git repos + - update website from repo + - create release on freecode + + - create versionfile + - make pypi release + - make archlinux release + +manual last steps: + +- announce on linkedin +- announce on twitter From 8209009ddc8a15360d508d70a078abbd97eb27ee Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 12 Jul 2013 21:07:13 +0200 Subject: [PATCH 167/548] some notes for a release Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-07-12.release | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/dev/logs/2013-07-12.release b/docs/dev/logs/2013-07-12.release index f3f1d8d3..1616505e 100644 --- a/docs/dev/logs/2013-07-12.release +++ b/docs/dev/logs/2013-07-12.release @@ -2,16 +2,17 @@ - checkout master branch [ - - check if date is correct in docs/changelog - - ensure all unittests work - - compile manpages - - compile speeches + x check if date is correct in docs/changelog + x ensure all unittests work + - requires (wrong/outdated) versionfile! + x compile manpages + x compile speeches ] [ - - add manpages to website repo - - add speeches to website repo - - rsync cdist docs to website repo & add to website repo - - create blog entry & add to website repo + x add manpages to website repo + x add speeches to website repo + x rsync cdist docs to website repo & add to website repo + x create blog entry & add to website repo ] - upload website - fix latest link for manpages @@ -26,9 +27,9 @@ - update website from repo - create release on freecode - - create versionfile - - make pypi release - - make archlinux release + x create versionfile + x make pypi release + x make archlinux release manual last steps: From 71f01ca735866e709d0426189616b84bdcd9a4e7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 12 Jul 2013 21:26:14 +0200 Subject: [PATCH 168/548] improve release process (not yet perfect) Signed-off-by: Nico Schottelius --- Makefile | 19 +++++++++++-------- docs/changelog | 4 ++-- docs/dev/logs/2013-07-12.release | 19 ++++++++++--------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 0fa6965d..e09d9609 100644 --- a/Makefile +++ b/Makefile @@ -95,12 +95,12 @@ man: $(MANTYPEALL) $(MANREFALL) $(MANSTATICALL) # Manpages #5: release part MANWEBDIR=$(WEBBASE)/man/$(CHANGELOG_VERSION) -man-dist: man +man-dist: man check-date rm -rf "${MANWEBDIR}" mkdir -p "${MANWEBDIR}/man1" "${MANWEBDIR}/man7" cp ${MAN1DSTDIR}/*.html ${MAN1DSTDIR}/*.css ${MANWEBDIR}/man1 cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${MANWEBDIR}/man7 - cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" + cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" || true man-release: web-release # Fix ikiwiki, which does not like symlinks for pseudo security @@ -155,7 +155,7 @@ web-release: web-dist man-dist speeches-dist ML_FILE=.lock-ml # Only send mail once - lock until new changelog things happened -$(ML_FILE): $(CHANGELOG_FILE) +$(ML_FILE): $(CHANGELOG_FILE) git-release web-release $(helper) ml-release $(CHANGELOG_VERSION) touch $@ @@ -201,7 +201,9 @@ git-checkout-current: $(VERSION_FILE): .git/refs/heads/* .git/refs/tags/* .git/HEAD echo "VERSION = \"$$(git describe)\"" > $@ -git-release: git-tag git-branch-merge +git-release: git-tag + make git-branch-merge + make git-checkout-current make pub ################################################################################ @@ -212,10 +214,8 @@ PYPI_FILE=.lock-pypi pypi-release: $(PYPI_FILE) $(PYPI_FILE): man $(VERSION_FILE) - make git-checkout-stable python3 setup.py sdist upload touch $@ - make git-checkout-current ################################################################################ # archlinux @@ -227,7 +227,7 @@ $(ARCHLINUXTAR): PKGBUILD pypi-release makepkg -c --source PKGBUILD: PKGBUILD.in $(VERSION_FILE) - ./PKGBUILD.in + ./PKGBUILD.in $(CHANGELOG_VERSION) $(ARCHLINUX_FILE): $(ARCHLINUXTAR) $(VERSION_FILE) burp -c system $(ARCHLINUXTAR) @@ -241,12 +241,15 @@ archlinux-release: $(ARCHLINUX_FILE) CHECKS=check-date check-unittest +check-unittest: $(VERSION_FILE) + RELEASE=speeches-dist web-release RELEASE+=ml-release freecode-release RELEASE+=man-dist pypi-release git-release RELEASE+=archlinux-release -release: $(CHECKS) $(RELEASE) +#release: $(CHECKS) $(RELEASE) +release: | $(CHECKS) man speeches echo "Manual steps: linkedin, twitter" # Code that is better handled in a shell script diff --git a/docs/changelog b/docs/changelog index 98e021f9..9e1279ba 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,8 +4,8 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.2.0: 2013-07-11 - * Build: Fixed several small issues in the Makefile +2.2.0: 2013-07-12 + * Build: Cleanup the Makefile * Type __package_opkg: Use shortcut version * Core: Remove old pseudo object id "singleton" (Steven Armstrong) diff --git a/docs/dev/logs/2013-07-12.release b/docs/dev/logs/2013-07-12.release index 1616505e..da4b296c 100644 --- a/docs/dev/logs/2013-07-12.release +++ b/docs/dev/logs/2013-07-12.release @@ -14,18 +14,19 @@ x rsync cdist docs to website repo & add to website repo x create blog entry & add to website repo ] - - upload website - - fix latest link for manpages - - send mail to mailinglist + x upload website + x fix latest link for manpages + x send mail to mailinglist -> also requires git tag & git release + x should also require web-release including blog! - create PKGBUILD for archlinux release - - create git tag / read description - - if necessary create version branch - - change to version branch and merge master branch - - update git repos - - update website from repo - - create release on freecode + x create git tag / read description + t if necessary create version branch + x change to version branch and merge tag! + x update git repos + x update website from repo + x create release on freecode x create versionfile x make pypi release From 3de17b2aa2a37fd7e7f88addc6c0685b311403a1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 16 Jul 2013 17:11:24 +0200 Subject: [PATCH 169/548] add detailled upgrade instructions Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index f3def316..1f8d03b4 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -14,6 +14,39 @@ 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 From 76c46d88fc726db426da5a08b477467df06b0443 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 16 Jul 2013 17:32:24 +0200 Subject: [PATCH 170/548] there is no --after and --before Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 1f8d03b4..9957730f 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -53,7 +53,7 @@ To upgrade to the lastet version do pip install --upgrade cdist -## Update Instructions +## General Update Instructions ### Updating from 2.1 to 2.2 @@ -96,7 +96,6 @@ Have a look at the update guide for [[2.0 to 2.1|2.0-to-2.1]]. * 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** - * require="" is deprecated: Use --after and --before as parameters instead ### Updating from 1.7 to 2.0 From 4d47467944d1a3834f4844dbe0a0cf0c58a6c448 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Aug 2013 08:59:12 +0200 Subject: [PATCH 171/548] +shell-idee Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-08-07.shell | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/dev/logs/2013-08-07.shell diff --git a/docs/dev/logs/2013-08-07.shell b/docs/dev/logs/2013-08-07.shell new file mode 100644 index 00000000..3fa9f139 --- /dev/null +++ b/docs/dev/logs/2013-08-07.shell @@ -0,0 +1,2 @@ +What about having a cdist shell to have a shell with all available types? +Let's give it a try! From 2403fc59ee0cf7f81cff1aa17954ad8ca05579df Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Aug 2013 09:24:10 +0200 Subject: [PATCH 172/548] refactor commandline: merge into its own class (and add first shell code) Signed-off-by: Nico Schottelius --- cdist/config.py | 2 +- cdist/config_install.py | 95 ++++++++++++++++++++++++++++++++++++ cdist/shell.py | 40 +++++++++++++++ scripts/cdist | 105 +++++----------------------------------- 4 files changed, 147 insertions(+), 95 deletions(-) create mode 100644 cdist/shell.py diff --git a/cdist/config.py b/cdist/config.py index 9af25b75..2c6c2e6d 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # diff --git a/cdist/config_install.py b/cdist/config_install.py index 72061ca2..f179972f 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -23,6 +23,7 @@ import logging import os import shutil +import sys import time import pprint @@ -47,6 +48,100 @@ class ConfigInstall(object): self.context.local.create_files_dirs() self.context.remote.create_files_dirs() + @classmethod + def commandline(cls, args): + """Configure or install remote system""" + import multiprocessing + + # FIXME: Refactor relict - remove later + log = logging.getLogger("cdist") + + 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.') + 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) + + args.manifest = initial_manifest_temp_path + import atexit + atexit.register(lambda: os.remove(initial_manifest_temp_path)) + + process = {} + failed_hosts = [] + time_start = time.time() + + for host in args.host: + if args.parallel: + log.debug("Creating child process for %s", host) + 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", len(args.host), + (time_end - time_start)) + + if len(failed_hosts) > 0: + raise cdist.Error("Failed to configure the following hosts: " + + " ".join(failed_hosts)) + + @classmethod + def onehost(cls, host, args, parallel): + """Configure or install ONE system""" + + # FIXME: Refactor relict - remove later + log = logging.getLogger("cdist") + + try: + import cdist.context + + context = cdist.context.Context( + target_host=host, + remote_copy=args.remote_copy, + remote_exec=args.remote_exec, + initial_manifest=args.manifest, + add_conf_dirs=args.conf_dir, + exec_path=sys.argv[0], + debug=args.debug) + + c = cls(context) + c.run() + context.cleanup() + + except cdist.Error as e: + context.log.error(e) + if parallel: + # We are running in our own process here, need to sys.exit! + sys.exit(1) + 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 + def run(self): """Do what is most often done: deploy & cleanup""" start_time = time.time() diff --git a/cdist/shell.py b/cdist/shell.py new file mode 100644 index 00000000..f68a47ed --- /dev/null +++ b/cdist/shell.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# +# 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 logging +import sys + +import cdist + +log = logging.getLogger(__name__) + +class Shell(object): + + def __init__(self): + pass + + @classmethod + def commandline(cls): + pass + # initialise cdist + # Startup Shell + + diff --git a/scripts/cdist b/scripts/cdist index 3c94b38b..79a89a7c 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -26,7 +26,8 @@ def commandline(): import cdist.banner import cdist.config - import cdist.install + # import cdist.install + import cdist.shell # Construct parser others can reuse parser = {} @@ -83,7 +84,13 @@ def commandline(): # Config parser['config'] = parser['sub'].add_parser('config', parents=[parser['loglevel'], parser['configinstall']]) - parser['config'].set_defaults(func=config) + parser['config'].set_defaults(func=cdist.config.Config.commandline) + + # Shell + parser['shell'] = parser['sub'].add_parser('shell', + parents=[parser['loglevel']]) + parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) + # Install # 20120525/sar: commented until it actually does something @@ -112,98 +119,8 @@ def commandline(): except AttributeError: parser['main'].print_help() -def config(args): - configinstall(args, mode=cdist.config.Config) - -def install(args): - configinstall(args, mode=cdist.install.Install) - -def configinstall(args, mode): - """Configure or install remote system""" - import multiprocessing - import time - - 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.') - 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) - - args.manifest = initial_manifest_temp_path - import atexit - atexit.register(lambda: os.remove(initial_manifest_temp_path)) - - process = {} - failed_hosts = [] - time_start = time.time() - - for host in args.host: - if args.parallel: - log.debug("Creating child process for %s", host) - process[host] = multiprocessing.Process(target=configinstall_onehost, args=(host, args, mode, True)) - process[host].start() - else: - try: - configinstall_onehost(host, args, mode, 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", len(args.host), - (time_end - time_start)) - - if len(failed_hosts) > 0: - raise cdist.Error("Failed to configure the following hosts: " + - " ".join(failed_hosts)) - -def configinstall_onehost(host, args, mode, parallel): - """Configure or install ONE remote system""" - - try: - import cdist.context - - context = cdist.context.Context( - target_host=host, - remote_copy=args.remote_copy, - remote_exec=args.remote_exec, - initial_manifest=args.manifest, - add_conf_dirs=args.conf_dir, - exec_path=sys.argv[0], - debug=args.debug) - - c = mode(context) - c.run() - context.cleanup() - - except cdist.Error as e: - context.log.error(e) - # We are running in our own process here, need to sys.exit! - if parallel: - sys.exit(1) - 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 +#def install(args): +# configinstall(args, mode=cdist.install.Install) def emulator(): """Prepare and run emulator""" From c793825edb03f83e2bd9c43c4fcee9032e6adef0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Aug 2013 17:52:34 +0200 Subject: [PATCH 173/548] re-arrange REMOTE_COPY/EXEC for Shell use Signed-off-by: Nico Schottelius --- cdist/__init__.py | 3 +++ cdist/shell.py | 28 ++++++++++++++++++++++++---- scripts/cdist | 6 ++++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/cdist/__init__.py b/cdist/__init__.py index bd45e740..20c76b31 100644 --- a/cdist/__init__.py +++ b/cdist/__init__.py @@ -40,8 +40,11 @@ BANNER = """ "8888P' `"888*"" R888" ` ^"F 'Y" "P' "" "" """ + DOT_CDIST = ".cdist" +REMOTE_COPY = "scp -o User=root -q" +REMOTE_EXEC = "ssh -o User=root -q" class Error(Exception): """Base exception class for this project""" diff --git a/cdist/shell.py b/cdist/shell.py index f68a47ed..bc2c1ee9 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -20,9 +20,13 @@ # import logging -import sys +import os +import subprocess -import cdist +# FIXME: only considering config here - enable +# command line switch for using install object +# when it is available +import cdist.config log = logging.getLogger(__name__) @@ -32,9 +36,25 @@ class Shell(object): pass @classmethod - def commandline(cls): + def commandline(cls, args): pass # initialise cdist + import cdist.context + + context = cdist.context.Context( + target_host="cdist-shell-no-target-host", + remote_copy=cdist.REMOTE_COPY, + remote_exec=cdist.REMOTE_EXEC) + + config = cdist.config.Config(context) + # Startup Shell + if args.shell: + shell = [args.shell] + elif 'SHELL' in os.environ: + shell = [os.environ['SHELL']] + else: + shell = ["/bin/sh"] - + log.info("Starting shell...") + subprocess.call(shell) diff --git a/scripts/cdist b/scripts/cdist index 79a89a7c..935e9096 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -75,11 +75,11 @@ def commandline(): parser['configinstall'].add_argument('--remote-copy', help='Command to use for remote copy (should behave like scp)', action='store', dest='remote_copy', - default="scp -o User=root -q") + default=cdist.REMOTE_COPY) parser['configinstall'].add_argument('--remote-exec', help='Command to use for remote execution (should behave like ssh)', action='store', dest='remote_exec', - default="ssh -o User=root -q") + default=cdist.REMOTE_EXEC) # Config parser['config'] = parser['sub'].add_parser('config', @@ -89,6 +89,8 @@ def 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'].set_defaults(func=cdist.shell.Shell.commandline) From 0eb67a00f566fed9cd4a6f2b3611758906a80eae Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Aug 2013 18:49:47 +0200 Subject: [PATCH 174/548] exit = 2 if ctrl-c is pressed, cleanup Signed-off-by: Nico Schottelius --- scripts/cdist | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 935e9096..83035f5d 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -116,10 +116,19 @@ def commandline(): # Work around python 3.3 bug: # http://bugs.python.org/issue16308 # http://bugs.python.org/issue9253 + + # FIXME: catching AttributeError also hides + # real problems.. try a different way + + # FIXME: we always print main help, not + # the help of the actual parser being used! try: - args.func(args) + getattr(args, "func") except AttributeError: parser['main'].print_help() + sys.exit(0) + + args.func(args) #def install(args): # configinstall(args, mode=cdist.install.Install) @@ -158,12 +167,10 @@ if __name__ == "__main__": commandline() except KeyboardInterrupt: - pass + exit_code = 2 except cdist.Error as e: log.error(e) exit_code = 1 - # Determine exit code by return value of function - sys.exit(exit_code) From 79fea569b9af60dfc42bfd2d37609075ce68fee4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Aug 2013 20:58:45 +0200 Subject: [PATCH 175/548] some shell related cleanups Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 2 +- cdist/shell.py | 65 ++++++++++++++++++++++++++++++++------------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index da7f69c1..d80386c5 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -127,8 +127,8 @@ class Local(object): Return the output as a string. """ - assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command self.log.debug("Local run: %s", command) + assert isinstance(command, (list, tuple)), "list or tuple argument expected, got: %s" % command if env is None: env = os.environ.copy() diff --git a/cdist/shell.py b/cdist/shell.py index bc2c1ee9..d45b50e0 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -23,6 +23,10 @@ import logging import os import subprocess +# initialise cdist +import cdist.context + + # FIXME: only considering config here - enable # command line switch for using install object # when it is available @@ -32,29 +36,54 @@ log = logging.getLogger(__name__) class Shell(object): - def __init__(self): - pass + def __init__(self, shell=None): - @classmethod - def commandline(cls, args): - pass - # initialise cdist - import cdist.context + self.shell = shell - context = cdist.context.Context( - target_host="cdist-shell-no-target-host", + self.target_host = "cdist-shell-no-target-host" + self.context = cdist.context.Context( + target_host=self.target_host, remote_copy=cdist.REMOTE_COPY, remote_exec=cdist.REMOTE_EXEC) - config = cdist.config.Config(context) - # Startup Shell - if args.shell: - shell = [args.shell] - elif 'SHELL' in os.environ: - shell = [os.environ['SHELL']] - else: - shell = ["/bin/sh"] + def _init_shell(self): + """Select shell to execute, if not specified by user""" + + if not self.shell: + if 'SHELL' in os.environ: + self.shell = os.environ['SHELL'] + else: + self.shell = "/bin/sh" + + def _init_files_dirs(self): + self.context.local.create_files_dirs() + + def _init_environment(self): + self.env = os.environ.copy() + additional_env = { + 'PATH': "%s:%s" % (self.context.local.bin_path, os.environ['PATH']), + '__cdist_type_base_path': self.context.local.type_path, # for use in type emulator + '__cdist_manifest': "cdist shell", + '__global': self.context.local.out_path, + '__target_host': self.target_host, + '__manifest': self.context.local.manifest_path, + '__explorer': self.context.local.global_explorer_path, + } + + self.env.update(additional_env) + + def run(self): + self._init_shell() + self._init_files_dirs() + self._init_environment() log.info("Starting shell...") - subprocess.call(shell) + self.context.local.run([self.shell], self.env) + log.info("Finished shell.") + + @classmethod + def commandline(cls, args): + print(os.environ['PYTHONPATH']) + shell = cls(args.shell) + shell.run() From 4e46cf8ce41b3bc2b4b9c414de344cdd7d39bab1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 7 Aug 2013 21:12:21 +0200 Subject: [PATCH 176/548] begin to document shell changes Signed-off-by: Nico Schottelius --- cdist/shell.py | 1 - docs/changelog | 3 +++ docs/man/cdist-reference.text.sh | 10 +++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cdist/shell.py b/cdist/shell.py index d45b50e0..f4abbdd3 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -84,6 +84,5 @@ class Shell(object): @classmethod def commandline(cls, args): - print(os.environ['PYTHONPATH']) shell = cls(args.shell) shell.run() diff --git a/docs/changelog b/docs/changelog index 9e1279ba..0d37e011 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.3.0: + * Core: Added support for cdist shell + 2.2.0: 2013-07-12 * Build: Cleanup the Makefile * Type __package_opkg: Use shortcut version diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 7ee2224a..b0a9d32c 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -179,13 +179,13 @@ ENVIRONMENT VARIABLES --------------------- __explorer:: Directory that contains all global explorers. - Available for: initial manifest, explorer, type explorer + Available for: initial manifest, explorer, type explorer, shell __manifest:: Directory that contains the initial manifest. - Available for: initial manifest, type manifest + Available for: initial manifest, type manifest, shell __global:: Directory that contains generic output like explorer. - Available for: initial manifest, type manifest, type gencode + Available for: initial manifest, type manifest, type gencode, shell __object:: Directory that contains the current object. Available for: type manifest, type explorer, type gencode @@ -200,7 +200,7 @@ __object_name:: 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 + Available for: explorer, initial manifest, type explorer, type manifest, type gencode, shell __type:: Path to the current type. Available for: type manifest, type gencode @@ -216,6 +216,6 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +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). eof From 8fddb1692fa994689e0c94a86c5b7fee38a7e18f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 8 Aug 2013 19:09:53 +0200 Subject: [PATCH 177/548] changelog updates Signed-off-by: Nico Schottelius --- docs/changelog | 1 + docs/{changelog.2.3 => changelog.future} | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename docs/{changelog.2.3 => changelog.future} (93%) diff --git a/docs/changelog b/docs/changelog index 0d37e011..9ece3a57 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 2.3.0: * Core: Added support for cdist shell + * Documentation: Improved some manpages 2.2.0: 2013-07-12 * Build: Cleanup the Makefile diff --git a/docs/changelog.2.3 b/docs/changelog.future similarity index 93% rename from docs/changelog.2.3 rename to docs/changelog.future index 25f926c2..12adf8c3 100644 --- a/docs/changelog.2.3 +++ b/docs/changelog.future @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.2.0: +future (maybe 3.x?): * Type __cron: Dropped support for old internal format Using this version prior to running cdist 2.1.2 will break add the cron entries twice. From 32f878ad00fc36716b5cbaa6f17a47f0e70ae774 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Aug 2013 11:42:00 +0200 Subject: [PATCH 178/548] update docs, document exit code bug Signed-off-by: Nico Schottelius --- cdist/config_install.py | 5 +-- docs/man/man1/cdist.text | 57 ++++++++++++++++++-------- docs/man/man7/cdist-best-practice.text | 39 ++++++++++++++---- scripts/cdist | 8 +++- 4 files changed, 79 insertions(+), 30 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index f179972f..045c8a43 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -28,6 +28,7 @@ import time import pprint import cdist +import cdist.context from cdist import core class ConfigInstall(object): @@ -107,11 +108,7 @@ class ConfigInstall(object): def onehost(cls, host, args, parallel): """Configure or install ONE system""" - # FIXME: Refactor relict - remove later - log = logging.getLogger("cdist") - try: - import cdist.context context = cdist.context.Context( target_host=host, diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index 113454a7..8faff66c 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -5,40 +5,51 @@ Nico Schottelius NAME ---- -cdist - Configuration management +cdist - Usable Configuration Management SYNOPSIS -------- -cdist [-h] [-V] +cdist [-h] [-d] [-v] [-V] {banner,config,shell} ... -cdist banner +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 ----------- cdist is the frontend executable to the cdist configuration management. -cdist supports different as explained below. The options to the main -program are: +cdist supports different subcommands as explained below. + +GENERAL +------- +All commands except the following options: + +-d, --debug:: + Set log level to debug -h, --help:: Show the help screen +-v, --verbose: + Set log level to info, be more verbose + -V, --version:: Show version and exit BANNER -------- -Displays the cdist banner. +------ +Displays the cdist banner. Useful for printing +cdist posters - a must have for every office. CONFIG ------ -Configure a system +Configure one or more hosts -h, --help:: Show the help screen @@ -52,9 +63,6 @@ Configure a system --conf-dir argument have higher precedence over those set through the environment variable. --d, --debug:: - Enable debug output - -i MANIFEST, --initial-manifest MANIFEST:: Path to a cdist manifest or - to read from stdin @@ -70,20 +78,27 @@ Configure a system --remote-exec REMOTE_EXEC: Command to use for remote execution (should behave like ssh) +SHELL +----- +This command allows you to + +-s/--shell:: + Select shell to use, defaults to current shell + EXAMPLES -------- -------------------------------------------------------------------------------- # Configure ikq05.ethz.ch with debug enabled -cdist config -d ikq05.ethz.ch +% cdist config -d ikq05.ethz.ch # Configure hosts in parallel and use a different configuration directory -cdist config -c ~/p/cdist-nutzung \ +% cdist config -c ~/p/cdist-nutzung \ -p ikq02.ethz.ch ikq03.ethz.ch ikq04.ethz.ch # Use custom remote exec / copy commands -cdist config --remote-exec /path/to/my/remote/exec \ +% 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 @@ -91,10 +106,18 @@ cdist config --remote-exec /path/to/my/remote/exec \ cdist banner # Show help -cdist --help +% cdist --help # Show Version -cdist --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 + + -------------------------------------------------------------------------------- @@ -125,5 +148,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +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 index 818c423a..a254d10b 100644 --- a/docs/man/man7/cdist-best-practice.text +++ b/docs/man/man7/cdist-best-practice.text @@ -118,7 +118,7 @@ The following **.git/config** is taken from a a real world scenario: url = git://git.schottelius.org/cdist fetch = +refs/heads/*:refs/remotes/upstream/* -# Same as upstream, but works when being offline +# Same as upstream, but works when being offline [remote "local"] fetch = +refs/heads/*:refs/remotes/local/* url = /home/users/nico/p/cdist @@ -167,7 +167,7 @@ TEMPLATING * create directory templates/ in your type (convention) * create the template as an executable file like templates/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 @@ -182,19 +182,42 @@ server { 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/templates/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" --------------------------------------------------------------------------------------- +# 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 +-------------------------------------------------------------------------------- SEE ALSO -------- @@ -204,5 +227,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +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/scripts/cdist b/scripts/cdist index 83035f5d..6a61faf4 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -167,10 +167,16 @@ if __name__ == "__main__": commandline() except KeyboardInterrupt: - exit_code = 2 + pass + + # FIXME: We always get exit code = 130 + # exit_code = 2 + # does not make a difference except cdist.Error as e: log.error(e) exit_code = 1 + #sys.exit(20) + #print("ok2 %s" % exit_code) sys.exit(exit_code) From 263a8a73a7ec5df08b965488e71ecf2d81703140 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Aug 2013 12:11:43 +0200 Subject: [PATCH 179/548] minor cleanups Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index d80386c5..854a1832 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -85,9 +85,7 @@ class Local(object): def _init_conf_dirs(self): self.conf_dirs = [] - # Comes with the distribution - system_conf_dir = os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")) - self.conf_dirs.append(system_conf_dir) + self.conf_dirs.append(self.dist_conf_dir) # Is the default place for user created explorer, type and manifest if self.home_dir: @@ -99,7 +97,7 @@ class Local(object): cdist_path_dirs.reverse() self.conf_dirs.extend(cdist_path_dirs) - # Add user supplied directories + # Add command line supplied directories if self._add_conf_dirs: self.conf_dirs.extend(self._add_conf_dirs) From 37fa9b3743546fc10243810ae8b10ec2a1cb6bbc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Aug 2013 12:32:58 +0200 Subject: [PATCH 180/548] ++doc / shell Signed-off-by: Nico Schottelius --- docs/man/man1/cdist.text | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index 8faff66c..de50a4ce 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -80,7 +80,10 @@ Configure one or more hosts SHELL ----- -This command allows you to +This command allows you to spawn a shell that enables access +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:: Select shell to use, defaults to current shell From 1eb7eb8fe9677fd63a789355c29cc901b2590a4f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Aug 2013 12:33:32 +0200 Subject: [PATCH 181/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 9ece3a57..12c4221e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.3.0: +2.3.0: 2013-08-12 * Core: Added support for cdist shell * Documentation: Improved some manpages From 8192c2cbfc9b772731e937177ba883d73671cfef Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Aug 2013 12:37:05 +0200 Subject: [PATCH 182/548] back to old release process Signed-off-by: Nico Schottelius --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e09d9609..c61a6daf 100644 --- a/Makefile +++ b/Makefile @@ -248,8 +248,8 @@ RELEASE+=ml-release freecode-release RELEASE+=man-dist pypi-release git-release RELEASE+=archlinux-release -#release: $(CHECKS) $(RELEASE) -release: | $(CHECKS) man speeches +release: $(CHECKS) $(RELEASE) +#release: | $(CHECKS) man speeches echo "Manual steps: linkedin, twitter" # Code that is better handled in a shell script From 093cafa992acda2620e851bbda4c0378fdbef32d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Aug 2013 12:42:26 +0200 Subject: [PATCH 183/548] add hint for 2.2 to 2.3 migration Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 9957730f..9e47fccc 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -55,6 +55,10 @@ To upgrade to the lastet version do ## General Update Instructions +### 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: From 70698aa16716c7bdf19b04f85bf7114a748e1d19 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Aug 2013 12:46:23 +0200 Subject: [PATCH 184/548] document known problem during release Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-08-12.release | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs/dev/logs/2013-08-12.release diff --git a/docs/dev/logs/2013-08-12.release b/docs/dev/logs/2013-08-12.release new file mode 100644 index 00000000..e3f0a75b --- /dev/null +++ b/docs/dev/logs/2013-08-12.release @@ -0,0 +1,28 @@ +- already on 2.3.0-1 during release + - user bug + +hard linking docs/man/man7/cdist-type__user.7 -> cdist-2.3.0-1-g8192c2c/docs/man/man7 +hard linking docs/man/man7/cdist-type__user.html -> cdist-2.3.0-1-g8192c2c/docs/man/man7 +hard linking docs/man/man7/cdist-type__user_groups.7 -> cdist-2.3.0-1-g8192c2c/docs/man/man7 +hard linking docs/man/man7/cdist-type__user_groups.html -> cdist-2.3.0-1-g8192c2c/docs/man/man7 +hard linking scripts/cdist -> cdist-2.3.0-1-g8192c2c/scripts +creating dist +Creating tar archive +removing 'cdist-2.3.0-1-g8192c2c' (and everything under it) +running upload +Submitting dist/cdist-2.3.0-1-g8192c2c.tar.gz to http://pypi.python.org/pypi +Server response (200): OK +touch .lock-pypi +./PKGBUILD.in 2.3.0 +==> Retrieving sources... + -> Downloading cdist-2.3.0.tar.gz... + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed + 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 + 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 +curl: (22) The requested URL returned error: 404 Not Found +==> ERROR: Failure while downloading cdist-2.3.0.tar.gz + Aborting... +make: *** [PKGBUILD] Error 1 +[12:38] bento:cdist% + From 90c66966e76dce423c2ecf45296236627f632ab0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Aug 2013 12:46:50 +0200 Subject: [PATCH 185/548] ++notes Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-08-12.release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/logs/2013-08-12.release b/docs/dev/logs/2013-08-12.release index e3f0a75b..1db05681 100644 --- a/docs/dev/logs/2013-08-12.release +++ b/docs/dev/logs/2013-08-12.release @@ -1,5 +1,5 @@ - already on 2.3.0-1 during release - - user bug + - user bug: there should be no changes / commits during a release process hard linking docs/man/man7/cdist-type__user.7 -> cdist-2.3.0-1-g8192c2c/docs/man/man7 hard linking docs/man/man7/cdist-type__user.html -> cdist-2.3.0-1-g8192c2c/docs/man/man7 From 49d9f1f475ab1909c9923e91bb2d4b6717650631 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 12 Aug 2013 12:56:54 +0200 Subject: [PATCH 186/548] support relative paths in -c argument Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 2 +- docs/changelog | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 854a1832..2f09ecbc 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -190,7 +190,7 @@ class Local(object): for entry in os.listdir(current_dir): rel_entry_path = os.path.join(sub_dir, entry) - src = 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 diff --git a/docs/changelog b/docs/changelog index 12c4221e..3227caa9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.3.1: + * Core: Support relative paths for configuration directories + 2.3.0: 2013-08-12 * Core: Added support for cdist shell * Documentation: Improved some manpages From b80b548f14396554303005d140cc9912adc781fc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 18 Aug 2013 23:59:47 +0200 Subject: [PATCH 187/548] add logfile that describes how the cache is going to be enhaced Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-08-18.cache-enhancement | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/dev/logs/2013-08-18.cache-enhancement diff --git a/docs/dev/logs/2013-08-18.cache-enhancement b/docs/dev/logs/2013-08-18.cache-enhancement new file mode 100644 index 00000000..1ea6d775 --- /dev/null +++ b/docs/dev/logs/2013-08-18.cache-enhancement @@ -0,0 +1,5 @@ +- always save cache = outdir + - even if run aborts (for debugging) + - add a state flag +- save cache in a date based directory +- also add support for a per-host pidfile From 83c981f4778185c3bec1f464066bbaa225e64841 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 00:03:57 +0200 Subject: [PATCH 188/548] begin to implement -C --cache-dir Signed-off-by: Nico Schottelius --- cdist/context.py | 8 ++++++-- scripts/cdist | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cdist/context.py b/cdist/context.py index e0391be8..866e43f6 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -40,11 +40,13 @@ class Context(object): initial_manifest=False, add_conf_dirs=None, exec_path=sys.argv[0], - debug=False): + debug=False, + cache_dir=None): self.debug = debug self.target_host = target_host self.exec_path = exec_path + self.cache_dir = cache_dir # Context logging self.log = logging.getLogger(self.target_host) @@ -59,7 +61,9 @@ class Context(object): self.temp_dir = tempfile.mkdtemp() self.out_path = os.path.join(self.temp_dir, "out") - self.local = local.Local(self.target_host, self.out_path, self.exec_path, add_conf_dirs=add_conf_dirs) + self.local = local.Local(self.target_host, self.out_path, + self.exec_path, add_conf_dirs=add_conf_dirs, + cache_dir=self.cache_dir) self.initial_manifest = (initial_manifest or os.path.join(self.local.manifest_path, "init")) diff --git a/scripts/cdist b/scripts/cdist index 6a61faf4..66735f4b 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -60,6 +60,8 @@ def commandline(): parser['configinstall'].add_argument('-c', '--conf-dir', help='Add configuration directory (can be repeated, last one wins)', action='append') + parser['configinstall'].add_argument('-C', '--cache-dir', + help='Directory to save cache in (usually derived from target host name)') parser['configinstall'].add_argument('-i', '--initial-manifest', help='Path to a cdist manifest or \'-\' to read from stdin.', dest='manifest', required=False) From 58bd230a615a640c7beb2dbf5ae6dcfe1cf2e999 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 00:04:27 +0200 Subject: [PATCH 189/548] ++freedom Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-08-18.cache-enhancement | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/dev/logs/2013-08-18.cache-enhancement b/docs/dev/logs/2013-08-18.cache-enhancement index 1ea6d775..31e3cdc7 100644 --- a/docs/dev/logs/2013-08-18.cache-enhancement +++ b/docs/dev/logs/2013-08-18.cache-enhancement @@ -3,3 +3,5 @@ - add a state flag - save cache in a date based directory - also add support for a per-host pidfile +- allow user to specify cache dir - to give + full flexibility From f79727559a732fb61e5a051b030bd4a9fbe05ec2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 00:33:58 +0200 Subject: [PATCH 190/548] ++logs and migrate context -> local Signed-off-by: Nico Schottelius --- cdist/config_install.py | 47 +++++++++++++--------- cdist/context.py | 24 ----------- cdist/exec/local.py | 24 ++++++----- cdist/exec/remote.py | 4 +- docs/dev/logs/2013-08-18.cache-enhancement | 10 +++++ 5 files changed, 55 insertions(+), 54 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 045c8a43..70f15c74 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -28,26 +28,30 @@ import time import pprint import cdist -import cdist.context + +import cdist.exec.local +import cdist.exec.remote + from cdist import core class ConfigInstall(object): """Cdist main class to hold arbitrary data""" - def __init__(self, context, dry_run=False): + def __init__(self, local, remote, dry_run=False): - self.context = context - self.log = logging.getLogger(self.context.target_host) - self.dry_run = dry_run + self.local = local + self.remote = remote + self.log = logging.getLogger(self.context.target_host) + self.dry_run = dry_run - self.explorer = core.Explorer(self.context.target_host, self.context.local, self.context.remote) - self.manifest = core.Manifest(self.context.target_host, self.context.local) - self.code = core.Code(self.context.target_host, self.context.local, self.context.remote) + self.explorer = core.Explorer(self.target_host, self.local, self.remote) + self.manifest = core.Manifest(self.target_host, self.local) + self.code = core.Code(self.target_host, self.local, self.remote) def _init_files_dirs(self): """Prepare files and directories for the run""" - self.context.local.create_files_dirs() - self.context.remote.create_files_dirs() + self.local.create_files_dirs() + self.remote.create_files_dirs() @classmethod def commandline(cls, args): @@ -110,16 +114,23 @@ class ConfigInstall(object): try: - context = cdist.context.Context( + local = cdist.local.Local( target_host=host, - remote_copy=args.remote_copy, - remote_exec=args.remote_exec, - initial_manifest=args.manifest, - add_conf_dirs=args.conf_dir, + out_path=FIXME-OUT_PATH, exec_path=sys.argv[0], - debug=args.debug) + add_conf_dirs=args.conf_dir, + cache_dir=args.cache_dir) + + remote = cdist.remote.Remote( + target_host=host, + remote_exec=args.remote_exec, + remote_copy=args.remote_copy) + + + #initial_manifest=args.manifest, + #debug=args.debug) - c = cls(context) + c = cls(local, remote) c.run() context.cleanup() @@ -149,7 +160,7 @@ class ConfigInstall(object): self.manifest.run_initial_manifest(self.context.initial_manifest) self.iterate_until_finished() - self.context.local.save_cache() + self.local.save_cache() self.log.info("Finished successful run in %s seconds", time.time() - start_time) diff --git a/cdist/context.py b/cdist/context.py index 866e43f6..4115c0d6 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -23,12 +23,6 @@ import logging import os import sys -import tempfile -import shutil - -from cdist.exec import local -from cdist.exec import remote - class Context(object): """Hold information about current context""" @@ -52,19 +46,6 @@ class Context(object): self.log = logging.getLogger(self.target_host) self.log.addFilter(self) - # Local temp directory - # FIXME: if __cdist_out_dir can be given from the outside, the same directory will be used for all hosts - if '__cdist_out_dir' in os.environ: - self.out_path = os.environ['__cdist_out_dir'] - self.temp_dir = None - else: - self.temp_dir = tempfile.mkdtemp() - self.out_path = os.path.join(self.temp_dir, "out") - - self.local = local.Local(self.target_host, self.out_path, - self.exec_path, add_conf_dirs=add_conf_dirs, - cache_dir=self.cache_dir) - self.initial_manifest = (initial_manifest or os.path.join(self.local.manifest_path, "init")) @@ -83,11 +64,6 @@ class Context(object): self.remote = remote.Remote(self.target_host, self.remote_base_path, self.remote_exec, self.remote_copy) - def cleanup(self): - """Remove temp stuff""" - if self.temp_dir: - shutil.rmtree(self.temp_dir) - def filter(self, record): """Add hostname to logs via logging Filter""" diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 2f09ecbc..76c090cc 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -38,10 +38,10 @@ class Local(object): Directly accessing the local side from python code is a bug. """ - def __init__(self, target_host, out_path, exec_path, add_conf_dirs=None, cache_dir=None): + def __init__(self, target_host, exec_path, out_base_path=None, add_conf_dirs=None, cache_dir=None): self.target_host = target_host - self.out_path = out_path + self.out_base_path = out_base_path self.exec_path = exec_path self._add_conf_dirs = add_conf_dirs @@ -71,11 +71,17 @@ class Local(object): os.umask(0o077) def _init_paths(self): + + # FIXME: inherited behaviour from old context + if not self.out_base_path: + self.out_base_path = tempfile.mkdtemp() + + # Depending on out_path - self.bin_path = os.path.join(self.out_path, "bin") - self.conf_path = os.path.join(self.out_path, "conf") - self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_path = os.path.join(self.out_path, "object") + self.bin_path = os.path.join(self.out_base_path, "bin") + self.conf_path = os.path.join(self.out_base_path, "conf") + self.global_explorer_out_path = os.path.join(self.out_base_path, "explorer") + self.object_path = os.path.join(self.out_base_path, "object") # Depending on conf_path self.global_explorer_path = os.path.join(self.conf_path, "explorer") @@ -160,15 +166,13 @@ class Local(object): def save_cache(self): destination = os.path.join(self.cache_path, self.target_host) - self.log.debug("Saving " + self.out_path + " to " + destination) + self.log.debug("Saving " + self.out_base_path + " to " + destination) if os.path.exists(destination): shutil.rmtree(destination) - shutil.move(self.out_path, destination) + shutil.move(self.out_base_path, destination) def _create_context_dirs(self): - self.mkdir(self.out_path) - self.mkdir(self.conf_path) self.mkdir(self.global_explorer_out_path) self.mkdir(self.bin_path) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index bcb5fc4b..4e336e79 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -43,9 +43,9 @@ class Remote(object): Directly accessing the remote side from python code is a bug. """ - def __init__(self, target_host, remote_base_path, remote_exec, remote_copy): + def __init__(self, target_host, remote_exec, remote_copy): self.target_host = target_host - self.base_path = remote_base_path + self.base_path = os.environ.get('__cdist_remote_out_dir', "/var/lib/cdist") self._exec = remote_exec self._copy = remote_copy diff --git a/docs/dev/logs/2013-08-18.cache-enhancement b/docs/dev/logs/2013-08-18.cache-enhancement index 31e3cdc7..95052dfe 100644 --- a/docs/dev/logs/2013-08-18.cache-enhancement +++ b/docs/dev/logs/2013-08-18.cache-enhancement @@ -5,3 +5,13 @@ - also add support for a per-host pidfile - allow user to specify cache dir - to give full flexibility +- drop context - it is a very small unecessary wrapper + - maye introduce cdist.log instead! +- replace out_path with out_base + - directory under which all the subdirectories are + created + -> by default ~/.cdist/run + -> out_base_path +- drop support for deprecated environment variables + __cdist_out_dir + __cdist_remote_out_dir From a7fe8b4ed2da2c9b2dbf3bb7e5813ea8e58142cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 00:36:25 +0200 Subject: [PATCH 191/548] port context -> remote Signed-off-by: Nico Schottelius --- cdist/context.py | 20 -------------------- cdist/exec/remote.py | 7 +++++++ 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/cdist/context.py b/cdist/context.py index 4115c0d6..9e20f969 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -37,11 +37,6 @@ class Context(object): debug=False, cache_dir=None): - self.debug = debug - self.target_host = target_host - self.exec_path = exec_path - self.cache_dir = cache_dir - # Context logging self.log = logging.getLogger(self.target_host) self.log.addFilter(self) @@ -49,21 +44,6 @@ class Context(object): self.initial_manifest = (initial_manifest or os.path.join(self.local.manifest_path, "init")) - self._init_remote(remote_copy, remote_exec) - - # Remote stuff - def _init_remote(self, remote_copy, remote_exec): - - self.remote_base_path = os.environ.get('__cdist_remote_out_dir', "/var/lib/cdist") - self.remote_copy = remote_copy - self.remote_exec = remote_exec - - os.environ['__remote_copy'] = self.remote_copy - os.environ['__remote_exec'] = self.remote_exec - - self.remote = remote.Remote(self.target_host, self.remote_base_path, - self.remote_exec, self.remote_copy) - def filter(self, record): """Add hostname to logs via logging Filter""" diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 4e336e79..6d89324b 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -57,6 +57,13 @@ class Remote(object): self.log = logging.getLogger(self.target_host) + self._init_env() + + def _init_env(self): + os.environ['__remote_copy'] = self.remote_copy + os.environ['__remote_exec'] = self.remote_exec + + def create_files_dirs(self): self.rmdir(self.base_path) self.mkdir(self.base_path) From b9a6cf7c6a689b16782829ffb37a7806b51cb33b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 00:38:19 +0200 Subject: [PATCH 192/548] remove context from shell Signed-off-by: Nico Schottelius --- cdist/shell.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cdist/shell.py b/cdist/shell.py index f4abbdd3..4b8edbe8 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -24,7 +24,7 @@ import os import subprocess # initialise cdist -import cdist.context +import cdist.exec.local # FIXME: only considering config here - enable @@ -41,7 +41,7 @@ class Shell(object): self.shell = shell self.target_host = "cdist-shell-no-target-host" - self.context = cdist.context.Context( + self.local = cdist.local.Local( target_host=self.target_host, remote_copy=cdist.REMOTE_COPY, remote_exec=cdist.REMOTE_EXEC) @@ -57,18 +57,18 @@ class Shell(object): self.shell = "/bin/sh" def _init_files_dirs(self): - self.context.local.create_files_dirs() + self.local.create_files_dirs() def _init_environment(self): self.env = os.environ.copy() additional_env = { - 'PATH': "%s:%s" % (self.context.local.bin_path, os.environ['PATH']), - '__cdist_type_base_path': self.context.local.type_path, # for use in type emulator + 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), + '__cdist_type_base_path': self.local.type_path, # for use in type emulator '__cdist_manifest': "cdist shell", - '__global': self.context.local.out_path, + '__global': self.local.out_path, '__target_host': self.target_host, - '__manifest': self.context.local.manifest_path, - '__explorer': self.context.local.global_explorer_path, + '__manifest': self.local.manifest_path, + '__explorer': self.local.global_explorer_path, } self.env.update(additional_env) @@ -79,7 +79,7 @@ class Shell(object): self._init_environment() log.info("Starting shell...") - self.context.local.run([self.shell], self.env) + self.local.run([self.shell], self.env) log.info("Finished shell.") @classmethod From eaf1721212ba779449b8e5f85c2cab00f7263761 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 00:52:15 +0200 Subject: [PATCH 193/548] begin to migrate to '--output-base-path', shrink context Signed-off-by: Nico Schottelius --- cdist/config_install.py | 22 ++++++++-------------- cdist/context.py | 12 +----------- cdist/exec/local.py | 12 +++++++++++- scripts/cdist | 4 ++-- 4 files changed, 22 insertions(+), 28 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 70f15c74..7b38ae97 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -41,7 +41,7 @@ class ConfigInstall(object): self.local = local self.remote = remote - self.log = logging.getLogger(self.context.target_host) + self.log = logging.getLogger(self.local.target_host) self.dry_run = dry_run self.explorer = core.Explorer(self.target_host, self.local, self.remote) @@ -113,26 +113,20 @@ class ConfigInstall(object): """Configure or install ONE system""" try: - local = cdist.local.Local( target_host=host, - out_path=FIXME-OUT_PATH, exec_path=sys.argv[0], - add_conf_dirs=args.conf_dir, - cache_dir=args.cache_dir) + initial_manifest=args.manifest, + out_base_path=args.out_base_path, + add_conf_dirs=args.conf_dir) remote = cdist.remote.Remote( target_host=host, remote_exec=args.remote_exec, remote_copy=args.remote_copy) - - - #initial_manifest=args.manifest, - #debug=args.debug) c = cls(local, remote) c.run() - context.cleanup() except cdist.Error as e: context.log.error(e) @@ -156,8 +150,8 @@ class ConfigInstall(object): self._init_files_dirs() - self.explorer.run_global_explorers(self.context.local.global_explorer_out_path) - self.manifest.run_initial_manifest(self.context.initial_manifest) + 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.local.save_cache() @@ -166,8 +160,8 @@ class ConfigInstall(object): def object_list(self): """Short name for object list retrieval""" - for cdist_object in core.CdistObject.list_objects(self.context.local.object_path, - self.context.local.type_path): + for cdist_object in core.CdistObject.list_objects(self.local.object_path, + self.local.type_path): yield cdist_object def iterate_once(self): diff --git a/cdist/context.py b/cdist/context.py index 9e20f969..0c11502e 100644 --- a/cdist/context.py +++ b/cdist/context.py @@ -27,22 +27,12 @@ import sys class Context(object): """Hold information about current context""" - def __init__(self, - target_host, - remote_copy, - remote_exec, - initial_manifest=False, - add_conf_dirs=None, - exec_path=sys.argv[0], - debug=False, - cache_dir=None): + def __init__(self, target_host) # Context logging self.log = logging.getLogger(self.target_host) self.log.addFilter(self) - self.initial_manifest = (initial_manifest or - os.path.join(self.local.manifest_path, "init")) def filter(self, record): """Add hostname to logs via logging Filter""" diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 76c090cc..e74c8a4f 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -38,11 +38,17 @@ class Local(object): Directly accessing the local side from python code is a bug. """ - def __init__(self, target_host, exec_path, out_base_path=None, add_conf_dirs=None, cache_dir=None): + def __init__(self, + target_host, + exec_path, + initial_manifest=None, + out_base_path=None, + add_conf_dirs=None) self.target_host = target_host self.out_base_path = out_base_path self.exec_path = exec_path + self.custom_initial_manifest = initial_manifest self._add_conf_dirs = add_conf_dirs @@ -52,6 +58,7 @@ class Local(object): self._init_cache_dir(cache_dir) self._init_conf_dirs() + @property def dist_conf_dir(self): return os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")) @@ -86,6 +93,9 @@ class Local(object): # Depending on conf_path 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")) + self.type_path = os.path.join(self.conf_path, "type") def _init_conf_dirs(self): diff --git a/scripts/cdist b/scripts/cdist index 66735f4b..e9a5833e 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -60,13 +60,13 @@ def commandline(): parser['configinstall'].add_argument('-c', '--conf-dir', help='Add configuration directory (can be repeated, last one wins)', action='append') - parser['configinstall'].add_argument('-C', '--cache-dir', - help='Directory to save cache in (usually derived from target host name)') parser['configinstall'].add_argument('-i', '--initial-manifest', help='Path to a cdist manifest or \'-\' to read from stdin.', dest='manifest', required=False) parser['configinstall'].add_argument('-n', '--dry-run', help='Do not execute code', action='store_true') + parser['configinstall'].add_argument('-o', '--output-base-path', + help='Directory prefix to save cdist output in') parser['configinstall'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', action='store_true', dest='parallel') From d1708c78b63054963550ea4d525e07d90a02ff35 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 01:38:28 +0200 Subject: [PATCH 194/548] refactoring Signed-off-by: Nico Schottelius --- cdist/config_install.py | 16 ++++++------ cdist/exec/local.py | 48 +++++++++++++++++++----------------- cdist/exec/remote.py | 6 +++-- cdist/{context.py => log.py} | 18 ++++++++------ scripts/cdist | 6 +++-- 5 files changed, 52 insertions(+), 42 deletions(-) rename cdist/{context.py => log.py} (73%) diff --git a/cdist/config_install.py b/cdist/config_install.py index 7b38ae97..c7f141dd 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -44,9 +44,9 @@ class ConfigInstall(object): self.log = logging.getLogger(self.local.target_host) self.dry_run = dry_run - self.explorer = core.Explorer(self.target_host, self.local, self.remote) - self.manifest = core.Manifest(self.target_host, self.local) - self.code = core.Code(self.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) def _init_files_dirs(self): """Prepare files and directories for the run""" @@ -111,16 +111,18 @@ class ConfigInstall(object): @classmethod def onehost(cls, host, args, parallel): """Configure or install ONE system""" + + log = logging.getLogger(host) try: - local = cdist.local.Local( + local = cdist.exec.local.Local( target_host=host, exec_path=sys.argv[0], initial_manifest=args.manifest, - out_base_path=args.out_base_path, + out_path=args.out_path, add_conf_dirs=args.conf_dir) - remote = cdist.remote.Remote( + remote = cdist.exec.remote.Remote( target_host=host, remote_exec=args.remote_exec, remote_copy=args.remote_copy) @@ -129,7 +131,7 @@ class ConfigInstall(object): c.run() except cdist.Error as e: - context.log.error(e) + log.error(e) if parallel: # We are running in our own process here, need to sys.exit! sys.exit(1) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index e74c8a4f..c7a1c28c 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -27,6 +27,7 @@ import re import subprocess import shutil import logging +import tempfile import cdist from cdist import core @@ -42,11 +43,20 @@ class Local(object): target_host, exec_path, initial_manifest=None, - out_base_path=None, - add_conf_dirs=None) + out_path=None, + add_conf_dirs=None): self.target_host = target_host - self.out_base_path = out_base_path + + # FIXME: stopped: create base that does not require moving later + if out_path: + self.out_path = out_path + else: + self.out_path = tempfile.mkdtemp() + + # FIXME: as well + self._init_cache_dir(None) + self.exec_path = exec_path self.custom_initial_manifest = initial_manifest @@ -55,7 +65,6 @@ class Local(object): self._init_log() self._init_permissions() self._init_paths() - self._init_cache_dir(cache_dir) self._init_conf_dirs() @@ -78,17 +87,11 @@ class Local(object): os.umask(0o077) def _init_paths(self): - - # FIXME: inherited behaviour from old context - if not self.out_base_path: - self.out_base_path = tempfile.mkdtemp() - - # Depending on out_path - self.bin_path = os.path.join(self.out_base_path, "bin") - self.conf_path = os.path.join(self.out_base_path, "conf") - self.global_explorer_out_path = os.path.join(self.out_base_path, "explorer") - self.object_path = os.path.join(self.out_base_path, "object") + self.bin_path = os.path.join(self.out_path, "bin") + self.conf_path = os.path.join(self.out_path, "conf") + self.global_explorer_out_path = os.path.join(self.out_path, "explorer") + self.object_path = os.path.join(self.out_path, "object") # Depending on conf_path self.global_explorer_path = os.path.join(self.conf_path, "explorer") @@ -117,6 +120,11 @@ class Local(object): if self._add_conf_dirs: self.conf_dirs.extend(self._add_conf_dirs) + def _init_directories(self): + self.mkdir(self.conf_path) + self.mkdir(self.global_explorer_out_path) + self.mkdir(self.bin_path) + def _init_cache_dir(self, cache_dir): if cache_dir: self.cache_path = cache_dir @@ -170,22 +178,16 @@ class Local(object): return self.run(command, env, return_output) def create_files_dirs(self): - self._create_context_dirs() + self._init_directories() self._create_conf_path_and_link_conf_dirs() self._link_types_for_emulator() def save_cache(self): destination = os.path.join(self.cache_path, self.target_host) - self.log.debug("Saving " + self.out_base_path + " to " + destination) + self.log.debug("Saving " + self.out_path + " to " + destination) if os.path.exists(destination): shutil.rmtree(destination) - shutil.move(self.out_base_path, destination) - - - def _create_context_dirs(self): - self.mkdir(self.conf_path) - self.mkdir(self.global_explorer_out_path) - self.mkdir(self.bin_path) + shutil.move(self.out_path, destination) def _create_conf_path_and_link_conf_dirs(self): # Link destination directories diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 6d89324b..647474fa 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -60,8 +60,10 @@ class Remote(object): self._init_env() def _init_env(self): - os.environ['__remote_copy'] = self.remote_copy - os.environ['__remote_exec'] = self.remote_exec + """Setup environment for scripts - HERE????""" + # FIXME: better do so in exec functions that require it! + os.environ['__remote_copy'] = self._copy + os.environ['__remote_exec'] = self._exec def create_files_dirs(self): diff --git a/cdist/context.py b/cdist/log.py similarity index 73% rename from cdist/context.py rename to cdist/log.py index 0c11502e..063059a2 100644 --- a/cdist/context.py +++ b/cdist/log.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -21,22 +21,24 @@ # import logging -import os -import sys -class Context(object): +class Log(logging.Logger): """Hold information about current context""" - def __init__(self, target_host) + def __init__(self, name): # Context logging - self.log = logging.getLogger(self.target_host) - self.log.addFilter(self) + self.name = name + # Init real logger + super().__init__(name) + + # Add ourselves as a filter + self.addFilter(self) def filter(self, record): """Add hostname to logs via logging Filter""" - record.msg = self.target_host + ": " + str(record.msg) + record.msg = self.name + ": " + str(record.msg) return True diff --git a/scripts/cdist b/scripts/cdist index e9a5833e..bbf45d17 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -65,7 +65,7 @@ def commandline(): dest='manifest', required=False) parser['configinstall'].add_argument('-n', '--dry-run', help='Do not execute code', action='store_true') - parser['configinstall'].add_argument('-o', '--output-base-path', + parser['configinstall'].add_argument('-o', '--out-path', help='Directory prefix to save cdist output in') parser['configinstall'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', @@ -159,9 +159,11 @@ if __name__ == "__main__": import os import re import cdist + import cdist.log - log = logging.getLogger("cdist") + 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])): emulator() From cd8695d3ebcd356c4d23ff0b056b6e87a9ea4b5c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 08:48:41 +0200 Subject: [PATCH 195/548] move create_files_dirs more to up - it is similar to init() Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index c7a1c28c..b3478cf9 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -125,6 +125,12 @@ class Local(object): self.mkdir(self.global_explorer_out_path) self.mkdir(self.bin_path) + def create_files_dirs(self): + self._init_directories() + self._create_conf_path_and_link_conf_dirs() + self._link_types_for_emulator() + + def _init_cache_dir(self, cache_dir): if cache_dir: self.cache_path = cache_dir @@ -177,11 +183,6 @@ class Local(object): return self.run(command, env, return_output) - def create_files_dirs(self): - self._init_directories() - self._create_conf_path_and_link_conf_dirs() - self._link_types_for_emulator() - def save_cache(self): destination = os.path.join(self.cache_path, self.target_host) self.log.debug("Saving " + self.out_path + " to " + destination) From 9db29493779803f3fd598760c84e421711729c7f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 08:49:51 +0200 Subject: [PATCH 196/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 3227caa9..c172bd3e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 2.3.1: * Core: Support relative paths for configuration directories + * Core: Code cleanup (removed context class, added log class) 2.3.0: 2013-08-12 * Core: Added support for cdist shell From 10b27e63cae79b5d1600bb434e00a03eee939765 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 11:21:36 +0200 Subject: [PATCH 197/548] rename out_path -> out_dir for consistency Signed-off-by: Nico Schottelius --- scripts/cdist | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index bbf45d17..d9c48b12 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -65,8 +65,9 @@ def commandline(): dest='manifest', required=False) parser['configinstall'].add_argument('-n', '--dry-run', help='Do not execute code', action='store_true') - parser['configinstall'].add_argument('-o', '--out-path', - help='Directory prefix to save cdist output in') + parser['configinstall'].add_argument('-o', '--out-dir', + help='Directory to save cdist output in', + destination="out_path") parser['configinstall'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', action='store_true', dest='parallel') From b3cf339d06f16be0c011cd387699a475da7ad47e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 11:21:53 +0200 Subject: [PATCH 198/548] fallback to sys.argv[0] by default Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index b3478cf9..6e4029f3 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-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -41,7 +41,7 @@ class Local(object): """ def __init__(self, target_host, - exec_path, + exec_path=sys.argv[0], initial_manifest=None, out_path=None, add_conf_dirs=None): From 8298bb0bf5b8e19ee1188fdef89f08e43f8c85ea Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 11:33:44 +0200 Subject: [PATCH 199/548] fix test cdist.test.config_install.ConfigInstallRunTestCase Signed-off-by: Nico Schottelius --- cdist/config_install.py | 1 - cdist/exec/remote.py | 12 ++++++++++-- cdist/test/config_install/__init__.py | 22 +++++++++++----------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index c7f141dd..2db4c4af 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -117,7 +117,6 @@ class ConfigInstall(object): try: local = cdist.exec.local.Local( target_host=host, - exec_path=sys.argv[0], initial_manifest=args.manifest, out_path=args.out_path, add_conf_dirs=args.conf_dir) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 647474fa..01f028a9 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -43,12 +43,20 @@ class Remote(object): Directly accessing the remote side from python code is a bug. """ - def __init__(self, target_host, remote_exec, remote_copy): + def __init__(self, + target_host, + remote_exec, + remote_copy, + base_path=None): self.target_host = target_host - self.base_path = os.environ.get('__cdist_remote_out_dir', "/var/lib/cdist") self._exec = remote_exec self._copy = remote_copy + if base_path: + self.base_path = base_path + else: + self.base_path = "/var/lib/cdist" + self.conf_path = os.path.join(self.base_path, "conf") self.object_path = os.path.join(self.base_path, "object") diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py index b8daf4f8..4047abe4 100644 --- a/cdist/test/config_install/__init__.py +++ b/cdist/test/config_install/__init__.py @@ -27,7 +27,6 @@ from cdist import test from cdist import core import cdist -import cdist.context import cdist.config import cdist.core.cdist_type import cdist.core.cdist_object @@ -49,22 +48,23 @@ class ConfigInstallRunTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() self.out_dir = os.path.join(self.temp_dir, "out") - self.remote_out_dir = os.path.join(self.temp_dir, "remote") + os.mkdir(self.out_dir) + self.local = cdist.exec.local.Local( + target_host=self.target_host, + out_path=self.out_dir) - os.environ['__cdist_out_dir'] = self.out_dir - os.environ['__cdist_remote_out_dir'] = self.remote_out_dir - - self.context = cdist.context.Context( + self.remote_dir = os.path.join(self.temp_dir, "remote") + os.mkdir(self.remote_dir) + self.remote = cdist.exec.remote.Remote( target_host=self.target_host, remote_copy=self.remote_copy, remote_exec=self.remote_exec, - exec_path=test.cdist_exec_path, - debug=True) + base_path=self.remote_dir) - self.context.local.object_path = object_base_path - self.context.local.type_path = type_base_path + self.local.object_path = object_base_path + self.local.type_path = type_base_path - self.config = cdist.config.Config(self.context) + self.config = cdist.config.Config(self.local, self.remote) self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) self.object_index = dict((o.name, o) for o in self.objects) From a76d8bb517ed58083af71bbedab8a4afbd1b0e84 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 11:45:22 +0200 Subject: [PATCH 200/548] :%s/self.out_path/self.base_path/g Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 6e4029f3..3a3ac706 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -43,16 +43,16 @@ class Local(object): target_host, exec_path=sys.argv[0], initial_manifest=None, - out_path=None, + base_path=None, add_conf_dirs=None): self.target_host = target_host # FIXME: stopped: create base that does not require moving later - if out_path: - self.out_path = out_path + if base_path: + self.base_path = base_path else: - self.out_path = tempfile.mkdtemp() + self.base_path = tempfile.mkdtemp() # FIXME: as well self._init_cache_dir(None) @@ -88,10 +88,10 @@ class Local(object): def _init_paths(self): # Depending on out_path - self.bin_path = os.path.join(self.out_path, "bin") - self.conf_path = os.path.join(self.out_path, "conf") - self.global_explorer_out_path = os.path.join(self.out_path, "explorer") - self.object_path = os.path.join(self.out_path, "object") + 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.object_path = os.path.join(self.base_path, "object") # Depending on conf_path self.global_explorer_path = os.path.join(self.conf_path, "explorer") @@ -185,10 +185,10 @@ class Local(object): def save_cache(self): destination = os.path.join(self.cache_path, self.target_host) - self.log.debug("Saving " + self.out_path + " to " + destination) + self.log.debug("Saving " + self.base_path + " to " + destination) if os.path.exists(destination): shutil.rmtree(destination) - shutil.move(self.out_path, destination) + shutil.move(self.base_path, destination) def _create_conf_path_and_link_conf_dirs(self): # Link destination directories From ffeaa3d06bd8736e51a0074bb3c73c5998b8957d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 11:45:43 +0200 Subject: [PATCH 201/548] fix old bug / joining wrong args Signed-off-by: Nico Schottelius --- cdist/exec/remote.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 01f028a9..dfeccd94 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -149,6 +149,6 @@ class Remote(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]) except UnicodeDecodeError: raise DecodeError(command) From 2f5de23ae9df42dd059f840ebd9a39fcf49aad96 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 12:03:25 +0200 Subject: [PATCH 202/548] out_path -> base_path Signed-off-by: Nico Schottelius --- cdist/core/manifest.py | 2 +- cdist/emulator.py | 15 ++++++++++----- cdist/test/code/__init__.py | 10 +++++----- cdist/test/emulator/__init__.py | 20 ++++++++++---------- cdist/test/explorer/__init__.py | 19 +++++++++---------- cdist/test/manifest/__init__.py | 8 ++++---- 6 files changed, 39 insertions(+), 35 deletions(-) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 8da7f96d..97121474 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -94,7 +94,7 @@ 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 - '__global': self.local.out_path, + '__global': self.local.base_path, '__target_host': self.target_host, } if self.log.getEffectiveLevel() == logging.DEBUG: diff --git a/cdist/emulator.py b/cdist/emulator.py index add20e70..af4c620e 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -28,6 +28,8 @@ import sys import cdist from cdist import core +class MissingEnvironmentVariable(cdist.Error): + class Emulator(object): def __init__(self, argv, stdin=sys.stdin.buffer, env=os.environ): self.argv = argv @@ -36,12 +38,15 @@ class Emulator(object): self.object_id = '' - self.global_path = self.env['__global'] - self.target_host = self.env['__target_host'] + try: + self.global_path = self.env['__global'] + self.target_host = self.env['__target_host'] - # Internally only - self.object_source = self.env['__cdist_manifest'] - self.type_base_path = self.env['__cdist_type_base_path'] + # Internally only + self.object_source = self.env['__cdist_manifest'] + self.type_base_path = self.env['__cdist_type_base_path'] + + except KeyError: self.object_base_path = os.path.join(self.global_path, "object") diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 284ef9c0..95a9e10f 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -41,11 +41,11 @@ class CodeTestCase(test.CdistTestCase): def setUp(self): self.target_host = 'localhost' - self.out_path = self.mkdtemp() + self.base_path = self.mkdtemp() self.local = local.Local( target_host=self.target_host, - out_path = self.out_path, + base_path = self.base_path, exec_path = cdist.test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -63,7 +63,7 @@ class CodeTestCase(test.CdistTestCase): self.cdist_object.create() def tearDown(self): - shutil.rmtree(self.out_path) + shutil.rmtree(self.base_path) shutil.rmtree(self.remote_base_path) def test_run_gencode_local_environment(self): @@ -75,7 +75,7 @@ class CodeTestCase(test.CdistTestCase): 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.out_path) + 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) @@ -90,7 +90,7 @@ class CodeTestCase(test.CdistTestCase): 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.out_path) + 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) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index ec0d7ae4..9f6d7000 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 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -33,7 +33,6 @@ from cdist.exec import local from cdist import emulator from cdist import core from cdist import config -import cdist.context import os.path as op my_dir = op.abspath(op.dirname(__file__)) @@ -46,11 +45,11 @@ class EmulatorTestCase(test.CdistTestCase): self.temp_dir = self.mkdtemp() handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) - out_path = self.temp_dir + base_path = self.temp_dir self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=base_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -108,11 +107,11 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() - out_path = os.path.join(self.temp_dir, "out") + base_path = os.path.join(self.temp_dir, "out") self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=base_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -135,13 +134,13 @@ class ArgumentsTestCase(test.CdistTestCase): def setUp(self): self.temp_dir = self.mkdtemp() - out_path = self.temp_dir + base_path = self.temp_dir handle, self.script = self.mkstemp(dir=self.temp_dir) os.close(handle) self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=base_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -183,6 +182,7 @@ class ArgumentsTestCase(test.CdistTestCase): 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() @@ -227,11 +227,11 @@ class StdinTestCase(test.CdistTestCase): os.environ = os.environ.copy() self.temp_dir = self.mkdtemp() - out_path = os.path.join(self.temp_dir, "out") + base_path = os.path.join(self.temp_dir, "out") self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=base_path, exec_path=test.cdist_exec_path, add_conf_dirs=[conf_dir]) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index a97b538a..d1b86725 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -39,26 +39,25 @@ conf_dir = op.join(fixtures, "conf") class ExplorerClassTestCase(test.CdistTestCase): def setUp(self): - self.target_host = 'localhost' - self.temp_dir = self.mkdtemp() - self.out_path = os.path.join(self.temp_dir, "out") + 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( target_host=self.target_host, - out_path=self.out_path, + base_path=self.local_path, exec_path=test.cdist_exec_path, - add_conf_dirs=[conf_dir]) + add_conf_dirs=[conf_dir], + ) self.local.create_files_dirs() self.remote = remote.Remote( - self.target_host, - self.remote_base_path, - self.remote_exec, - self.remote_copy) + 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( diff --git a/cdist/test/manifest/__init__.py b/cdist/test/manifest/__init__.py index 727017e7..c375a80f 100644 --- a/cdist/test/manifest/__init__.py +++ b/cdist/test/manifest/__init__.py @@ -46,11 +46,11 @@ class ManifestTestCase(test.CdistTestCase): self.orig_environ = os.environ os.environ = os.environ.copy() self.temp_dir = self.mkdtemp() - self.target_host = 'localhost' + out_path = self.temp_dir self.local = local.Local( target_host=self.target_host, - out_path=out_path, + base_path=out_path, exec_path = cdist.test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() @@ -78,7 +78,7 @@ class ManifestTestCase(test.CdistTestCase): 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.out_path) + 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) @@ -99,7 +99,7 @@ class ManifestTestCase(test.CdistTestCase): 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.out_path) + 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['__type'], cdist_type.absolute_path) self.assertEqual(output_dict['__object'], cdist_object.absolute_path) From 866645679a45cf2ec3fbf3b691e23782e48aaa0f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 13:34:29 +0200 Subject: [PATCH 203/548] throw a better exception when environment variables are missing Signed-off-by: Nico Schottelius --- cdist/emulator.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index af4c620e..22c819cd 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -28,7 +28,14 @@ import sys import cdist from cdist import core -class MissingEnvironmentVariable(cdist.Error): +class MissingRequiredEnvironmentVariableError(cdist.Error): + def __init__(self, name): + self.name = name + self.message = "Emulator requires the environment variable %s to be setup" % self.name + + def __str__(self): + return self.message + class Emulator(object): def __init__(self, argv, stdin=sys.stdin.buffer, env=os.environ): @@ -46,7 +53,8 @@ class Emulator(object): self.object_source = self.env['__cdist_manifest'] self.type_base_path = self.env['__cdist_type_base_path'] - except KeyError: + except KeyError as e: + raise MissingRequiredEnvironmentVariableError(e.args[0]) self.object_base_path = os.path.join(self.global_path, "object") From b527479620d38cf329bab54f16f84af738707e39 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 13:35:03 +0200 Subject: [PATCH 204/548] refactor out_path -> base_path Signed-off-by: Nico Schottelius --- cdist/core/code.py | 2 +- cdist/test/config_install/__init__.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/core/code.py b/cdist/core/code.py index fa1ed3c1..d5f59094 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -89,7 +89,7 @@ class Code(object): self.remote = remote self.env = { '__target_host': self.target_host, - '__global': self.local.out_path, + '__global': self.local.base_path, } def _run_gencode(self, cdist_object, which): diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py index 4047abe4..a66eaa13 100644 --- a/cdist/test/config_install/__init__.py +++ b/cdist/test/config_install/__init__.py @@ -47,11 +47,11 @@ class ConfigInstallRunTestCase(test.CdistTestCase): os.environ = os.environ.copy() self.temp_dir = self.mkdtemp() - self.out_dir = os.path.join(self.temp_dir, "out") - os.mkdir(self.out_dir) + self.local_dir = os.path.join(self.temp_dir, "local") + os.mkdir(self.local_dir) self.local = cdist.exec.local.Local( target_host=self.target_host, - out_path=self.out_dir) + base_path=self.local_dir) self.remote_dir = os.path.join(self.temp_dir, "remote") os.mkdir(self.remote_dir) From 975b93c20a1530aec7f9be89fe1f793fe843056f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 19 Aug 2013 13:37:40 +0200 Subject: [PATCH 205/548] fix all tests -> back to normal Signed-off-by: Nico Schottelius --- cdist/test/code/__init__.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 95a9e10f..fd0af338 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -39,21 +39,22 @@ conf_dir = op.join(fixtures, 'conf') class CodeTestCase(test.CdistTestCase): def setUp(self): - self.target_host = 'localhost' - - self.base_path = self.mkdtemp() + self.local_dir = self.mkdtemp() self.local = local.Local( target_host=self.target_host, - base_path = self.base_path, + base_path = self.local_dir, exec_path = cdist.test.cdist_exec_path, add_conf_dirs=[conf_dir]) self.local.create_files_dirs() - self.remote_base_path = self.mkdtemp() + self.remote_dir = self.mkdtemp() remote_exec = self.remote_exec remote_copy = self.remote_copy - self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) + self.remote = remote.Remote(target_host=self.target_host, + base_path=self.remote_dir, + remote_exec=remote_exec, + remote_copy=remote_copy) self.remote.create_files_dirs() self.code = code.Code(self.target_host, self.local, self.remote) @@ -63,8 +64,8 @@ class CodeTestCase(test.CdistTestCase): self.cdist_object.create() def tearDown(self): - shutil.rmtree(self.base_path) - shutil.rmtree(self.remote_base_path) + shutil.rmtree(self.local_dir) + shutil.rmtree(self.remote_dir) def test_run_gencode_local_environment(self): output_string = self.code.run_gencode_local(self.cdist_object) From 8aacbe288593198b7ffb0733b5bcf98ce1a596be Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 19 Aug 2013 22:15:16 +0200 Subject: [PATCH 206/548] Bourne is not bash see http://shebang.brandonmintern.com/bourne-is-not-bash-or-read-echo-and-backslash/ Signed-off-by: Steven Armstrong --- cdist/conf/type/__key_value/gencode-remote | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index 5fa24d5b..c1a6bca8 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -46,7 +46,8 @@ case "$state_should" in ;; wrongvalue) # change exisiting value - echo "sed \"s|^$key\($delimiter\+\).*|$key\1$value|\" \"$file\" > \"$file.cdist-tmp\"" + printf 'sed "s|^%s\(%s\+\).*|%s\\1%s|" "%s" > "%s.cdist-tmp"\n' \ + "$key" "$delimiter" "$key" "$value" "$file" "$file" echo "mv \"$file.cdist-tmp\" \"$file\"" ;; *) From 408d89433bb7e721ae4aba2bf6d0b4ef007174ff Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 20 Aug 2013 00:22:19 +0200 Subject: [PATCH 207/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index c172bd3e..5b16befb 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 2.3.1: * Core: Support relative paths for configuration directories * Core: Code cleanup (removed context class, added log class) + * Type __key_value:Fix quoting problem (Steven Armstrong) 2.3.0: 2013-08-12 * Core: Added support for cdist shell From 74e003d29bc6b9f9de8e2d3577eeb3b5d316eec2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 21 Aug 2013 18:52:35 +0200 Subject: [PATCH 208/548] +print cdist version on startup + exit_code = 2 for irq Signed-off-by: Nico Schottelius --- cdist/log.py | 8 +------- scripts/cdist | 10 +++------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/cdist/log.py b/cdist/log.py index 063059a2..8c3aac79 100644 --- a/cdist/log.py +++ b/cdist/log.py @@ -23,21 +23,15 @@ import logging class Log(logging.Logger): - """Hold information about current context""" def __init__(self, name): - # Context logging self.name = name - - # Init real logger super().__init__(name) - - # Add ourselves as a filter self.addFilter(self) def filter(self, record): - """Add hostname to logs via logging Filter""" + """Prefix messages with logger name""" record.msg = self.name + ": " + str(record.msg) diff --git a/scripts/cdist b/scripts/cdist index bbf45d17..4d10f37d 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -114,6 +114,7 @@ def commandline(): logging.root.setLevel(logging.DEBUG) log.debug(args) + log.info("version %s" % cdist.VERSION) # Work around python 3.3 bug: # http://bugs.python.org/issue16308 @@ -171,16 +172,11 @@ if __name__ == "__main__": commandline() except KeyboardInterrupt: - pass - - # FIXME: We always get exit code = 130 - # exit_code = 2 - # does not make a difference + exit_code = 2 except cdist.Error as e: log.error(e) exit_code = 1 - #sys.exit(20) - #print("ok2 %s" % exit_code) + # print("ok2 %s" % exit_code) sys.exit(exit_code) From 46a0689dfe6d409c95edc7b0f94391c6021bec54 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Aug 2013 11:15:43 +0200 Subject: [PATCH 209/548] how to store non-cdist related content in a cdist repo Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-best-practice.text | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/man/man7/cdist-best-practice.text b/docs/man/man7/cdist-best-practice.text index a254d10b..e6685cad 100644 --- a/docs/man/man7/cdist-best-practice.text +++ b/docs/man/man7/cdist-best-practice.text @@ -219,6 +219,22 @@ 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) From 200c15c5367c5f81e7859b99d3fd76e922eaaf7c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 27 Aug 2013 12:46:00 +0200 Subject: [PATCH 210/548] remove debug, ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + scripts/cdist | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 5b16befb..37d667b2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 2.3.1: * Core: Support relative paths for configuration directories * Core: Code cleanup (removed context class, added log class) + * Documentation: Add more best practises * Type __key_value:Fix quoting problem (Steven Armstrong) 2.3.0: 2013-08-12 diff --git a/scripts/cdist b/scripts/cdist index 4d10f37d..51d5535c 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- # -# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -178,5 +178,4 @@ if __name__ == "__main__": log.error(e) exit_code = 1 - # print("ok2 %s" % exit_code) sys.exit(exit_code) From 1b5010b74788524f991d5115c1026c2749f8d55f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 15:29:47 +0200 Subject: [PATCH 211/548] ++docs: cdist-troubleshooting Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-troubleshooting.text | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/man/man7/cdist-troubleshooting.text diff --git a/docs/man/man7/cdist-troubleshooting.text b/docs/man/man7/cdist-troubleshooting.text new file mode 100644 index 00000000..96090117 --- /dev/null +++ b/docs/man/man7/cdist-troubleshooting.text @@ -0,0 +1,52 @@ +cdist-troubleshooting(7) +======================== +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" +-------------------------------------------------------------------------------- + +We can clearly see that **somecommandthatdoesnotexist** +will fail in ~/.cdist/manifest/special. But as the custom +script is not called with the -e flag (exit on failure) of shell, +it does not lead to an error. And thus cdist sees the exit 0 +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 two solutions available: +-------------------------------------------------------------------------------- +# 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" +-------------------------------------------------------------------------------- + +SEE ALSO +-------- +- cdist(1) +- 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). From f50374af51cd5c7ab163232d182b4fbcb479c769 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 15:30:16 +0200 Subject: [PATCH 212/548] ++changes(2.3.1) Signed-off-by: Nico Schottelius --- docs/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 37d667b2..578f39e0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,10 +4,11 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.3.1: +2.3.1: 2013-08-28 * Core: Support relative paths for configuration directories * Core: Code cleanup (removed context class, added log class) * Documentation: Add more best practises + * Documentation: Add troubleshooting chapter * Type __key_value:Fix quoting problem (Steven Armstrong) 2.3.0: 2013-08-12 From bc4a9fda3ad0fc8d09cff2f13bf0aefd5ed564a8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 15:32:01 +0200 Subject: [PATCH 213/548] add doc/dev document that resulted in the troubleshooting document Signed-off-by: Nico Schottelius --- ...013-07-25.source-error-does-not-stop-cdist | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/dev/logs/2013-07-25.source-error-does-not-stop-cdist diff --git a/docs/dev/logs/2013-07-25.source-error-does-not-stop-cdist b/docs/dev/logs/2013-07-25.source-error-does-not-stop-cdist new file mode 100644 index 00000000..b0c43971 --- /dev/null +++ b/docs/dev/logs/2013-07-25.source-error-does-not-stop-cdist @@ -0,0 +1,56 @@ +Symptom: + running something in a manifest and that fails does not exist + the cdist run + +Analysis: + Find out what the shell does: + + [23:56] bento:testshell% cat a.sh + # source something that fails + . b.sh + [23:57] bento:testshell% cat b.sh + nosuchcommand + [23:57] bento:testshell% sh -e a.sh + a.sh: 2: .: b.sh: not found + [23:57] bento:testshell% echo $? + 2 + + -> exit 2 -> looks good + + + Find out what the python does: + + [23:57] bento:testshell% python3 + Python 3.3.2 (default, May 21 2013, 15:40:45) + [GCC 4.8.0 20130502 (prerelease)] on linux + Type "help", "copyright", "credits" or "license" for more information. + >>> import subprocess + >>> subprocess.check_call(["/bin/sh", "-e", "a.sh"]) + a.sh: 2: .: b.sh: not found + Traceback (most recent call last): + File "", line 1, in + File "/usr/lib/python3.3/subprocess.py", line 544, in check_call + raise CalledProcessError(retcode, cmd) + subprocess.CalledProcessError: Command '['/bin/sh', '-e', 'a.sh']' returned non-zero exit status 2 + >>> + + +Conclusion: + Manifests that execute (!) other shell scripts does + not necessarily give the -e flag to the other script + -> called script can have failures, but exit 0 + if something the last thing executed does exit 0! + +Solution: + Instead of doing stuff like + "$__manifest/special" + + use + sh -e "$__manifest/special" + + or source the script: + . "$__manifest/special" + + (runs the script in the same namespace/process as everything in the + calling script) + From 18c5e60ab1ff1f8871992bc052f60d301f30118f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 15:34:52 +0200 Subject: [PATCH 214/548] --context in tests Signed-off-by: Nico Schottelius --- cdist/test/config_install/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config_install/__init__.py index b8daf4f8..58a80917 100644 --- a/cdist/test/config_install/__init__.py +++ b/cdist/test/config_install/__init__.py @@ -27,7 +27,6 @@ from cdist import test from cdist import core import cdist -import cdist.context import cdist.config import cdist.core.cdist_type import cdist.core.cdist_object @@ -54,17 +53,18 @@ class ConfigInstallRunTestCase(test.CdistTestCase): os.environ['__cdist_out_dir'] = self.out_dir os.environ['__cdist_remote_out_dir'] = self.remote_out_dir - self.context = cdist.context.Context( + self.local = cdist.exec.local( + target_host=self.target_host, + exec_path=test.cdist_exec_path) + self.remote = cdist.exec.remote( target_host=self.target_host, remote_copy=self.remote_copy, - remote_exec=self.remote_exec, - exec_path=test.cdist_exec_path, - debug=True) + remote_exec=self.remote_exec) - self.context.local.object_path = object_base_path - self.context.local.type_path = type_base_path + self.local.object_path = object_base_path + self.local.type_path = type_base_path - self.config = cdist.config.Config(self.context) + self.config = cdist.config.Config(self.local, self.remote) self.objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) self.object_index = dict((o.name, o) for o in self.objects) From 136ddc05b59dc5cbe23f840dac7534a157778f73 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 15:39:17 +0200 Subject: [PATCH 215/548] context based changes Signed-off-by: Nico Schottelius --- cdist/emulator.py | 2 +- cdist/exec/remote.py | 2 +- cdist/test/code/__init__.py | 6 +++++- cdist/test/emulator/__init__.py | 1 - cdist/test/explorer/__init__.py | 1 - 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index add20e70..26f551c6 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 647474fa..469ec038 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index 284ef9c0..f555023f 100644 --- a/cdist/test/code/__init__.py +++ b/cdist/test/code/__init__.py @@ -53,7 +53,11 @@ class CodeTestCase(test.CdistTestCase): self.remote_base_path = self.mkdtemp() remote_exec = self.remote_exec remote_copy = self.remote_copy - self.remote = remote.Remote(self.target_host, self.remote_base_path, remote_exec, remote_copy) + self.remote = remote.Remote( + target_host=self.target_host, + remote_exec=remote_exec, + remote_copy=remote_copy) + self.remote.base_path = self.remote_base_path self.remote.create_files_dirs() self.code = code.Code(self.target_host, self.local, self.remote) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index ec0d7ae4..d68edd28 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -33,7 +33,6 @@ from cdist.exec import local from cdist import emulator from cdist import core from cdist import config -import cdist.context import os.path as op my_dir = op.abspath(op.dirname(__file__)) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index a97b538a..8ded89b7 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -56,7 +56,6 @@ class ExplorerClassTestCase(test.CdistTestCase): self.remote = remote.Remote( self.target_host, - self.remote_base_path, self.remote_exec, self.remote_copy) self.remote.create_files_dirs() From 2286acc6f22dde258c1a985e4c3292feb4d44694 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 15:44:52 +0200 Subject: [PATCH 216/548] fix some more tests for the next release Signed-off-by: Nico Schottelius --- cdist/test/code/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/test/code/__init__.py b/cdist/test/code/__init__.py index a518bd74..796e8a51 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 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -54,9 +54,9 @@ class CodeTestCase(test.CdistTestCase): self.remote = remote.Remote( target_host=self.target_host, remote_exec=remote_exec, - remote_copy=remote_copy) - self.remote.base_path = self.remote_base_path - tself.remote.create_files_dirs() + 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) From 3b9b0dde567e30a7e23c8cc097ddb5c2655474c3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 16:22:20 +0200 Subject: [PATCH 217/548] require branch merge to happen before pypi Signed-off-by: Nico Schottelius --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c61a6daf..1183be6f 100644 --- a/Makefile +++ b/Makefile @@ -211,7 +211,7 @@ git-release: git-tag # PYPI_FILE=.lock-pypi -pypi-release: $(PYPI_FILE) +pypi-release: $(PYPI_FILE) git-branch-merge $(PYPI_FILE): man $(VERSION_FILE) python3 setup.py sdist upload From 0c4847747b59fa814ab8c5defc6e9d6f72566f06 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 16:43:26 +0200 Subject: [PATCH 218/548] +space Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 578f39e0..4ba41cd9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,7 +9,7 @@ Changelog * Core: Code cleanup (removed context class, added log class) * Documentation: Add more best practises * Documentation: Add troubleshooting chapter - * Type __key_value:Fix quoting problem (Steven Armstrong) + * Type __key_value: Fix quoting problem (Steven Armstrong) 2.3.0: 2013-08-12 * Core: Added support for cdist shell From 726aaf2033e60c4b379c69e2bb285cd05225e05f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 16:44:36 +0200 Subject: [PATCH 219/548] document another release bug Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-08-28.release | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/dev/logs/2013-08-28.release diff --git a/docs/dev/logs/2013-08-28.release b/docs/dev/logs/2013-08-28.release new file mode 100644 index 00000000..23e23d88 --- /dev/null +++ b/docs/dev/logs/2013-08-28.release @@ -0,0 +1,5 @@ +- release process releases pypi from something + that is git describe based, not changelog based... + + - git describe should equal changelog, but may be + inconsistent due to branch merging! From 42bad3dd3719cd593e52d59a4be68e070b06cb00 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 16:46:35 +0200 Subject: [PATCH 220/548] dest, not destination Signed-off-by: Nico Schottelius --- scripts/cdist | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index f11a57e9..d138faba 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -66,8 +66,7 @@ def commandline(): parser['configinstall'].add_argument('-n', '--dry-run', help='Do not execute code', action='store_true') parser['configinstall'].add_argument('-o', '--out-dir', - help='Directory to save cdist output in', - destination="out_path") + help='Directory to save cdist output in', dest="out_path") parser['configinstall'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', action='store_true', dest='parallel') From b2d86ef2e6a9824d048e32bc91fa944b827d667a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 28 Aug 2013 16:47:00 +0200 Subject: [PATCH 221/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 4ba41cd9..bd136b2b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.3.2: + * Core: Fix typo in argument parser + 2.3.1: 2013-08-28 * Core: Support relative paths for configuration directories * Core: Code cleanup (removed context class, added log class) From 5b79a97d34f493ad5eebb25e14f869e71e959b38 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 29 Aug 2013 11:28:53 +0200 Subject: [PATCH 222/548] add hint to use /bin/sh -e consistently (thanks, Steven!) Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-troubleshooting.text | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-troubleshooting.text b/docs/man/man7/cdist-troubleshooting.text index 96090117..7c5e7612 100644 --- a/docs/man/man7/cdist-troubleshooting.text +++ b/docs/man/man7/cdist-troubleshooting.text @@ -31,7 +31,8 @@ it does not lead to an error. And thus cdist sees the exit 0 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 two solutions available: +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" @@ -40,6 +41,16 @@ sh -e "$__manifest/special" . "$__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 +... +-------------------------------------------------------------------------------- + + SEE ALSO -------- - cdist(1) From 3de9b869ac0d66e232af3e50f6801bc33189f615 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 29 Aug 2013 21:56:53 +0200 Subject: [PATCH 223/548] there is no such thing as cdist install in master remove all traces of it to prevent the ongoing merge issues when using the real thing Signed-off-by: Steven Armstrong --- cdist/config.py | 251 +++++++++++++++- cdist/config_install.py | 271 ------------------ cdist/core/cdist_type.py | 5 - cdist/emulator.py | 5 - cdist/install.py | 33 --- cdist/shell.py | 3 - cdist/test/cdist_type/__init__.py | 10 - .../{config_install => config}/__init__.py | 2 +- .../fixtures/object/__first/.keep | 0 .../fixtures/object/__first/man/.cdist/.keep | 0 .../fixtures/object/__second/.keep | 0 .../object/__second/on-the/.cdist/.keep | 0 .../fixtures/object/__third/.keep | 0 .../fixtures/object/__third/moon/.cdist/.keep | 0 .../object/__third/moon/.cdist/parameter/name | 0 .../__third/moon/.cdist/parameter/planet | 0 .../fixtures/type/__first/.keep | 0 .../fixtures/type/__second/.keep | 0 .../fixtures/type/__singleton_test/singleton | 0 .../fixtures/type/__third/.keep | 0 scripts/cdist | 38 +-- 21 files changed, 261 insertions(+), 357 deletions(-) delete mode 100644 cdist/config_install.py delete mode 100644 cdist/install.py rename cdist/test/{config_install => config}/__init__.py (99%) rename cdist/test/{config_install => config}/fixtures/object/__first/.keep (100%) rename cdist/test/{config_install => config}/fixtures/object/__first/man/.cdist/.keep (100%) rename cdist/test/{config_install => config}/fixtures/object/__second/.keep (100%) rename cdist/test/{config_install => config}/fixtures/object/__second/on-the/.cdist/.keep (100%) rename cdist/test/{config_install => config}/fixtures/object/__third/.keep (100%) rename cdist/test/{config_install => config}/fixtures/object/__third/moon/.cdist/.keep (100%) rename cdist/test/{config_install => config}/fixtures/object/__third/moon/.cdist/parameter/name (100%) rename cdist/test/{config_install => config}/fixtures/object/__third/moon/.cdist/parameter/planet (100%) rename cdist/test/{config_install => config}/fixtures/type/__first/.keep (100%) rename cdist/test/{config_install => config}/fixtures/type/__second/.keep (100%) rename cdist/test/{config_install => config}/fixtures/type/__singleton_test/singleton (100%) rename cdist/test/{config_install => config}/fixtures/type/__third/.keep (100%) diff --git a/cdist/config.py b/cdist/config.py index 2c6c2e6d..019f2cc7 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -20,7 +20,252 @@ # # -import cdist.config_install +import logging +import os +import shutil +import sys +import time +import pprint -class Config(cdist.config_install.ConfigInstall): - pass +import cdist + +import cdist.exec.local +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.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) + + def _init_files_dirs(self): + """Prepare files and directories for the run""" + self.local.create_files_dirs() + self.remote.create_files_dirs() + + @classmethod + def commandline(cls, args): + """Configure remote system""" + import multiprocessing + + # FIXME: Refactor relict - remove later + log = logging.getLogger("cdist") + + 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.') + 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) + + args.manifest = initial_manifest_temp_path + import atexit + atexit.register(lambda: os.remove(initial_manifest_temp_path)) + + process = {} + failed_hosts = [] + time_start = time.time() + + for host in args.host: + if args.parallel: + log.debug("Creating child process for %s", host) + 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", len(args.host), + (time_end - time_start)) + + if len(failed_hosts) > 0: + 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, + initial_manifest=args.manifest, + out_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) + + c = cls(local, remote) + c.run() + + 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) + 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 + + def run(self): + """Do what is most often done: deploy & cleanup""" + start_time = time.time() + + self._init_files_dirs() + + 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.local.save_cache() + 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): + yield cdist_object + + def iterate_once(self): + """ + Iterate over the objects once - helper method for + iterate_until_finished + """ + 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_until_finished(self): + """ + Go through all objects and solve them + one after another + """ + + objects_changed = True + + while objects_changed: + objects_changed = self.iterate_once() + + # Check whether all objects have been finished + unfinished_objects = [] + for cdist_object in self.object_list(): + if not cdist_object.state == cdist_object.STATE_DONE: + unfinished_objects.append(cdist_object) + + if unfinished_objects: + info_string = [] + + for cdist_object in unfinished_objects: + + requirement_names = [] + autorequire_names = [] + + 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): + autorequire_names.append(requirement.name) + + requirements = ", ".join(requirement_names) + autorequire = ", ".join(autorequire_names) + info_string.append("%s requires: %s autorequires: %s" % (cdist_object.name, requirements, autorequire)) + + raise cdist.UnresolvableRequirementsError("The requirements of the following objects could not be resolved: %s" % + ("; ".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.explorer.run_type_explorers(cdist_object) + self.manifest.run_type_manifest(cdist_object) + cdist_object.state = core.CdistObject.STATE_PREPARED + + def object_run(self, cdist_object): + """Run gencode and code for an 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) + + cdist_type = cdist_object.cdist_type + + # Generate + self.log.info("Generating and executing 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 not self.dry_run: + if cdist_object.code_local: + self.code.run_code_local(cdist_object) + if cdist_object.code_remote: + 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") + + + # 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/config_install.py b/cdist/config_install.py deleted file mode 100644 index 2db4c4af..00000000 --- a/cdist/config_install.py +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 2010-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 logging -import os -import shutil -import sys -import time -import pprint - -import cdist - -import cdist.exec.local -import cdist.exec.remote - -from cdist import core - -class ConfigInstall(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.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) - - def _init_files_dirs(self): - """Prepare files and directories for the run""" - self.local.create_files_dirs() - self.remote.create_files_dirs() - - @classmethod - def commandline(cls, args): - """Configure or install remote system""" - import multiprocessing - - # FIXME: Refactor relict - remove later - log = logging.getLogger("cdist") - - 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.') - 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) - - args.manifest = initial_manifest_temp_path - import atexit - atexit.register(lambda: os.remove(initial_manifest_temp_path)) - - process = {} - failed_hosts = [] - time_start = time.time() - - for host in args.host: - if args.parallel: - log.debug("Creating child process for %s", host) - 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", len(args.host), - (time_end - time_start)) - - if len(failed_hosts) > 0: - raise cdist.Error("Failed to configure the following hosts: " + - " ".join(failed_hosts)) - - @classmethod - def onehost(cls, host, args, parallel): - """Configure or install ONE system""" - - log = logging.getLogger(host) - - try: - local = cdist.exec.local.Local( - target_host=host, - initial_manifest=args.manifest, - out_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) - - c = cls(local, remote) - c.run() - - 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) - 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 - - def run(self): - """Do what is most often done: deploy & cleanup""" - start_time = time.time() - - self._init_files_dirs() - - 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.local.save_cache() - 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): - yield cdist_object - - def iterate_once(self): - """ - Iterate over the objects once - helper method for - iterate_until_finished - """ - 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_until_finished(self): - """ - Go through all objects and solve them - one after another - """ - - objects_changed = True - - while objects_changed: - objects_changed = self.iterate_once() - - # Check whether all objects have been finished - unfinished_objects = [] - for cdist_object in self.object_list(): - if not cdist_object.state == cdist_object.STATE_DONE: - unfinished_objects.append(cdist_object) - - if unfinished_objects: - info_string = [] - - for cdist_object in unfinished_objects: - - requirement_names = [] - autorequire_names = [] - - 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): - autorequire_names.append(requirement.name) - - requirements = ", ".join(requirement_names) - autorequire = ", ".join(autorequire_names) - info_string.append("%s requires: %s autorequires: %s" % (cdist_object.name, requirements, autorequire)) - - raise cdist.UnresolvableRequirementsError("The requirements of the following objects could not be resolved: %s" % - ("; ".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.explorer.run_type_explorers(cdist_object) - self.manifest.run_type_manifest(cdist_object) - cdist_object.state = core.CdistObject.STATE_PREPARED - - def object_run(self, cdist_object): - """Run gencode and code for an 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) - - cdist_type = cdist_object.cdist_type - - # Generate - self.log.info("Generating and executing 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 not self.dry_run: - if cdist_object.code_local: - self.code.run_code_local(cdist_object) - if cdist_object.code_remote: - 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") - - - # 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/cdist_type.py b/cdist/core/cdist_type.py index 0efb10f4..864970a9 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -99,11 +99,6 @@ class CdistType(object): """Check whether a type is a singleton.""" return os.path.isfile(os.path.join(self.absolute_path, "singleton")) - @property - def is_install(self): - """Check whether a type is used for installation (if not: for configuration)""" - return os.path.isfile(os.path.join(self.absolute_path, "install")) - @property def explorers(self): """Return a list of available explorers""" diff --git a/cdist/emulator.py b/cdist/emulator.py index bbc246a6..5b0ff1f6 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -78,11 +78,6 @@ class Emulator(object): def run(self): """Emulate type commands (i.e. __file and co)""" - if '__install' in self.env: - if not self.cdist_type.is_install: - self.log.debug("Running in install mode, ignoring non install type") - return True - self.commandline() self.setup_object() self.save_stdin() diff --git a/cdist/install.py b/cdist/install.py deleted file mode 100644 index 0f06f5e7..00000000 --- a/cdist/install.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# 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 . -# -# - -import os -import cdist.config_install - -class Install(cdist.config_install.ConfigInstall): - def __init__(self, *args, **kargs): - """Enhance config install with install support""" - - # Setup environ to be used in emulator - os.environ['__install'] = "yes" - - super().__init__(*args, **kargs) diff --git a/cdist/shell.py b/cdist/shell.py index 4b8edbe8..b88c3ccd 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -27,9 +27,6 @@ import subprocess import cdist.exec.local -# FIXME: only considering config here - enable -# command line switch for using install object -# when it is available import cdist.config log = logging.getLogger(__name__) diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index 5e774aa9..e97ce7e6 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -106,16 +106,6 @@ class TypeTestCase(test.CdistTestCase): cdist_type = core.CdistType(base_path, '__not_singleton') self.assertFalse(cdist_type.is_singleton) - def test_install_is_install(self): - base_path = fixtures - cdist_type = core.CdistType(base_path, '__install') - self.assertTrue(cdist_type.is_install) - - def test_not_install_is_install(self): - base_path = fixtures - cdist_type = core.CdistType(base_path, '__not_install') - self.assertFalse(cdist_type.is_install) - def test_with_explorers(self): base_path = fixtures cdist_type = core.CdistType(base_path, '__with_explorers') diff --git a/cdist/test/config_install/__init__.py b/cdist/test/config/__init__.py similarity index 99% rename from cdist/test/config_install/__init__.py rename to cdist/test/config/__init__.py index a66eaa13..80a45d9b 100644 --- a/cdist/test/config_install/__init__.py +++ b/cdist/test/config/__init__.py @@ -38,7 +38,7 @@ object_base_path = op.join(fixtures, 'object') type_base_path = op.join(fixtures, 'type') add_conf_dir = op.join(fixtures, 'conf') -class ConfigInstallRunTestCase(test.CdistTestCase): +class ConfigRunTestCase(test.CdistTestCase): def setUp(self): diff --git a/cdist/test/config_install/fixtures/object/__first/.keep b/cdist/test/config/fixtures/object/__first/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__first/.keep rename to cdist/test/config/fixtures/object/__first/.keep diff --git a/cdist/test/config_install/fixtures/object/__first/man/.cdist/.keep b/cdist/test/config/fixtures/object/__first/man/.cdist/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__first/man/.cdist/.keep rename to cdist/test/config/fixtures/object/__first/man/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/object/__second/.keep b/cdist/test/config/fixtures/object/__second/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__second/.keep rename to cdist/test/config/fixtures/object/__second/.keep diff --git a/cdist/test/config_install/fixtures/object/__second/on-the/.cdist/.keep b/cdist/test/config/fixtures/object/__second/on-the/.cdist/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__second/on-the/.cdist/.keep rename to cdist/test/config/fixtures/object/__second/on-the/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/object/__third/.keep b/cdist/test/config/fixtures/object/__third/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__third/.keep rename to cdist/test/config/fixtures/object/__third/.keep diff --git a/cdist/test/config_install/fixtures/object/__third/moon/.cdist/.keep b/cdist/test/config/fixtures/object/__third/moon/.cdist/.keep similarity index 100% rename from cdist/test/config_install/fixtures/object/__third/moon/.cdist/.keep rename to cdist/test/config/fixtures/object/__third/moon/.cdist/.keep diff --git a/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/name b/cdist/test/config/fixtures/object/__third/moon/.cdist/parameter/name similarity index 100% rename from cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/name rename to cdist/test/config/fixtures/object/__third/moon/.cdist/parameter/name diff --git a/cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/planet b/cdist/test/config/fixtures/object/__third/moon/.cdist/parameter/planet similarity index 100% rename from cdist/test/config_install/fixtures/object/__third/moon/.cdist/parameter/planet rename to cdist/test/config/fixtures/object/__third/moon/.cdist/parameter/planet diff --git a/cdist/test/config_install/fixtures/type/__first/.keep b/cdist/test/config/fixtures/type/__first/.keep similarity index 100% rename from cdist/test/config_install/fixtures/type/__first/.keep rename to cdist/test/config/fixtures/type/__first/.keep diff --git a/cdist/test/config_install/fixtures/type/__second/.keep b/cdist/test/config/fixtures/type/__second/.keep similarity index 100% rename from cdist/test/config_install/fixtures/type/__second/.keep rename to cdist/test/config/fixtures/type/__second/.keep diff --git a/cdist/test/config_install/fixtures/type/__singleton_test/singleton b/cdist/test/config/fixtures/type/__singleton_test/singleton similarity index 100% rename from cdist/test/config_install/fixtures/type/__singleton_test/singleton rename to cdist/test/config/fixtures/type/__singleton_test/singleton diff --git a/cdist/test/config_install/fixtures/type/__third/.keep b/cdist/test/config/fixtures/type/__third/.keep similarity index 100% rename from cdist/test/config_install/fixtures/type/__third/.keep rename to cdist/test/config/fixtures/type/__third/.keep diff --git a/scripts/cdist b/scripts/cdist index d138faba..6f6f13fe 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -26,7 +26,6 @@ def commandline(): import cdist.banner import cdist.config - # import cdist.install import cdist.shell # Construct parser others can reuse @@ -53,39 +52,35 @@ def commandline(): parents=[parser['loglevel']]) parser['banner'].set_defaults(func=cdist.banner.banner) - # Config and install (common stuff) - parser['configinstall'] = argparse.ArgumentParser(add_help=False) - parser['configinstall'].add_argument('host', nargs='+', + # Config + parser['config'] = parser['sub'].add_parser('config', + parents=[parser['loglevel']]) + parser['config'].add_argument('host', nargs='+', help='one or more hosts to operate on') - parser['configinstall'].add_argument('-c', '--conf-dir', + parser['config'].add_argument('-c', '--conf-dir', help='Add configuration directory (can be repeated, last one wins)', action='append') - parser['configinstall'].add_argument('-i', '--initial-manifest', + parser['config'].add_argument('-i', '--initial-manifest', help='Path to a cdist manifest or \'-\' to read from stdin.', dest='manifest', required=False) - parser['configinstall'].add_argument('-n', '--dry-run', + parser['config'].add_argument('-n', '--dry-run', help='Do not execute code', action='store_true') - parser['configinstall'].add_argument('-o', '--out-dir', + parser['config'].add_argument('-o', '--out-dir', help='Directory to save cdist output in', dest="out_path") - parser['configinstall'].add_argument('-p', '--parallel', + parser['config'].add_argument('-p', '--parallel', help='Operate on multiple hosts in parallel', action='store_true', dest='parallel') - parser['configinstall'].add_argument('-s', '--sequential', + parser['config'].add_argument('-s', '--sequential', help='Operate on multiple hosts sequentially (default)', action='store_false', dest='parallel') - - parser['configinstall'].add_argument('--remote-copy', + 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) - parser['configinstall'].add_argument('--remote-exec', + 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) - - # Config - parser['config'] = parser['sub'].add_parser('config', - parents=[parser['loglevel'], parser['configinstall']]) parser['config'].set_defaults(func=cdist.config.Config.commandline) # Shell @@ -96,12 +91,6 @@ def commandline(): parser['shell'].set_defaults(func=cdist.shell.Shell.commandline) - # Install - # 20120525/sar: commented until it actually does something - #parser['install'] = parser['sub'].add_parser('install', - # parents=[parser['loglevel'], parser['configinstall']]) - #parser['install'].set_defaults(func=install) - for p in parser: parser[p].epilog = "Get cdist at http://www.nico.schottelius.org/software/cdist/" @@ -133,9 +122,6 @@ def commandline(): args.func(args) -#def install(args): -# configinstall(args, mode=cdist.install.Install) - def emulator(): """Prepare and run emulator""" import cdist.emulator From 7143fd27060ac26f992097c5263dcdca61e19195 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 30 Aug 2013 01:32:30 +0200 Subject: [PATCH 224/548] base, not out Signed-off-by: Nico Schottelius --- cdist/config_install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/config_install.py b/cdist/config_install.py index 2db4c4af..d671314f 100644 --- a/cdist/config_install.py +++ b/cdist/config_install.py @@ -118,7 +118,7 @@ class ConfigInstall(object): local = cdist.exec.local.Local( target_host=host, initial_manifest=args.manifest, - out_path=args.out_path, + base_path=args.out_path, add_conf_dirs=args.conf_dir) remote = cdist.exec.remote.Remote( From 760b7e7afb3744a33cdbdf5bc6828bc19a267711 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 30 Aug 2013 02:55:22 +0200 Subject: [PATCH 225/548] ++changes(2.3.2) Signed-off-by: Nico Schottelius --- cdist/config.py | 2 +- docs/changelog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index 019f2cc7..dc0417f1 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -118,7 +118,7 @@ class Config(object): local = cdist.exec.local.Local( target_host=host, initial_manifest=args.manifest, - out_path=args.out_path, + base_path=args.out_path, add_conf_dirs=args.conf_dir) remote = cdist.exec.remote.Remote( diff --git a/docs/changelog b/docs/changelog index bd136b2b..f863e7b8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 2.3.2: * Core: Fix typo in argument parser + * Core: Code cleanup: Remove old install code (Steven Armstrong) 2.3.1: 2013-08-28 * Core: Support relative paths for configuration directories From 93f5ace932aa68e10947ae00a61ab99778fe3633 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 10:49:11 +0200 Subject: [PATCH 226/548] clenaup logging in emulator, cleanup emulator in main script Signed-off-by: Nico Schottelius --- cdist/emulator.py | 17 +---------------- scripts/cdist | 10 +++------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 5b0ff1f6..8d7b0854 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -63,18 +63,6 @@ class Emulator(object): self.__init_log() - def filter(self, record): - """Add hostname and object to logs via logging Filter""" - - prefix = self.target_host + ": (emulator)" - prefix = '{0}: emulator {1}'.format( - self.target_host, - core.CdistObject.join_name(self.type_name, self.object_id) - ) - record.msg = prefix + ": " + record.msg - - return True - def run(self): """Emulate type commands (i.e. __file and co)""" @@ -87,16 +75,13 @@ class Emulator(object): def __init_log(self): """Setup logging facility""" - logformat = '%(levelname)s: %(message)s' - logging.basicConfig(format=logformat) if '__cdist_debug' in self.env: logging.root.setLevel(logging.DEBUG) else: logging.root.setLevel(logging.INFO) - self.log = logging.getLogger(__name__) - self.log.addFilter(self) + self.log = logging.getLogger(self.target_host) def commandline(self): """Parse command line""" diff --git a/scripts/cdist b/scripts/cdist index 6f6f13fe..38ff5cb2 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -122,12 +122,6 @@ def commandline(): args.func(args) -def emulator(): - """Prepare and run emulator""" - import cdist.emulator - emulator = cdist.emulator.Emulator(sys.argv) - return emulator.run() - if __name__ == "__main__": # Sys is needed for sys.exit() import sys @@ -153,7 +147,9 @@ if __name__ == "__main__": log = logging.getLogger("cdist") if re.match("__", os.path.basename(sys.argv[0])): - emulator() + import cdist.emulator + emulator = cdist.emulator.Emulator(sys.argv) + emulator.run() else: commandline() From 4d8840dba0c36d93149e3fed966bbc032a4b0cee Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 10:50:42 +0200 Subject: [PATCH 227/548] also setup homedir Signed-off-by: Nico Schottelius --- cdist/conf/type/__cdist/manifest | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__cdist/manifest b/cdist/conf/type/__cdist/manifest index 16498c95..aeee415a 100755 --- a/cdist/conf/type/__cdist/manifest +++ b/cdist/conf/type/__cdist/manifest @@ -39,8 +39,15 @@ else source="git://github.com/telmich/cdist.git" fi -__user "$username" +# Currently hardcoded - if anyone cares, make a parameter +# out of it +home=/home/$username -require="__user/$username" __git "$directory" \ +__user "$username" --home "$home" + +require="__username/$user" __directory "$home" + --owner "$username" + +require="__user/$username __directory/$home" __git "$directory" \ --source "$source" \ --owner "$username" --branch "$branch" From 34b5fbd892167d8e3b3e18a2cafaa7b90bb070f9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 10:51:11 +0200 Subject: [PATCH 228/548] ++changes(2.3.2) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index f863e7b8..e349b063 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 2.3.2: * Core: Fix typo in argument parser * Core: Code cleanup: Remove old install code (Steven Armstrong) + * Type __cdist: Also create home directory 2.3.1: 2013-08-28 * Core: Support relative paths for configuration directories From 6af7eadc89fde159dea6ad94903dda6d83b2c324 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 11:21:19 +0200 Subject: [PATCH 229/548] add --shell to __cdist Signed-off-by: Nico Schottelius --- cdist/conf/type/__cdist/manifest | 10 ++++++++-- cdist/conf/type/__cdist/parameter/optional | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__cdist/manifest b/cdist/conf/type/__cdist/manifest index aeee415a..44d62f6c 100755 --- a/cdist/conf/type/__cdist/manifest +++ b/cdist/conf/type/__cdist/manifest @@ -21,6 +21,12 @@ directory="$__object_id" +if [ -f "$__object/parameter/shell" ]; then + shell="--shell $(cat "$__object/parameter/shell")" +else + shell="" +fi + if [ -f "$__object/parameter/username" ]; then username="$(cat "$__object/parameter/username")" else @@ -43,9 +49,9 @@ fi # out of it home=/home/$username -__user "$username" --home "$home" +__user "$username" --home "$home" $shell -require="__username/$user" __directory "$home" +require="__user/$username" __directory "$home" \ --owner "$username" require="__user/$username __directory/$home" __git "$directory" \ diff --git a/cdist/conf/type/__cdist/parameter/optional b/cdist/conf/type/__cdist/parameter/optional index d6582730..a5f14343 100644 --- a/cdist/conf/type/__cdist/parameter/optional +++ b/cdist/conf/type/__cdist/parameter/optional @@ -1,3 +1,4 @@ branch source username +shell From 6cd419b3341c26c5f9f92348b3025f4b840c69f7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 11:26:32 +0200 Subject: [PATCH 230/548] have __motd regenerate on Debian/Ubuntu Signed-off-by: Nico Schottelius --- cdist/conf/type/__motd/gencode-remote | 33 +++++++++++++++++++++++++++ docs/changelog | 3 +++ 2 files changed, 36 insertions(+) create mode 100755 cdist/conf/type/__motd/gencode-remote diff --git a/cdist/conf/type/__motd/gencode-remote b/cdist/conf/type/__motd/gencode-remote new file mode 100755 index 00000000..2aa84902 --- /dev/null +++ b/cdist/conf/type/__motd/gencode-remote @@ -0,0 +1,33 @@ +# 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 . +# +# + +os=$(cat "$__global/explorer/os") + +case "$os" in + debian|ubuntu) + + # Debian and Ubuntu need to be updated, + # as seen in /etc/init.d/bootlogs + echo "uname -snrvm > /var/run/motd" + echo "cat /etc/motd.tail >> /var/run/motd" + ;; + *) + exit 0 + ;; +esac diff --git a/docs/changelog b/docs/changelog index e349b063..78701e5d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,7 +7,10 @@ Changelog 2.3.2: * Core: Fix typo in argument parser * Core: Code cleanup: Remove old install code (Steven Armstrong) + * Core: Improve error message when using non-existing type in requirement * Type __cdist: Also create home directory + * Type __cdist: Add support for --shell parameter + * Type __motd: Regenerate motd on Debian and Ubuntu 2.3.1: 2013-08-28 * Core: Support relative paths for configuration directories From 73338c330b81593a4aeade753990c0c61382be17 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 11:30:22 +0200 Subject: [PATCH 231/548] record the type name, if there is no such type Signed-off-by: Nico Schottelius --- cdist/core/cdist_type.py | 5 +++-- cdist/emulator.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 864970a9..b6ba4f00 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -25,7 +25,8 @@ import os import cdist class NoSuchTypeError(cdist.Error): - def __init__(self, type_path, type_absolute_path): + def __init__(self, name, type_path, type_absolute_path): + self.name = name self.type_path = type_path self.type_absolute_path = type_absolute_path @@ -48,7 +49,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.path, self.absolute_path) + raise NoSuchTypeError(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 8d7b0854..f1f4b622 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -177,8 +177,8 @@ 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: - self.log.error("%s requires object %s with non-existing type at %s" % (self.cdist_object.name, requirement, self.object_source)) + except core.cdist_type.NoSuchTypeError as e: + self.log.error("%s requires object %s, but type %s does not exist (definded at %s)" % (self.cdist_object.name, requirement, e.name, self.object_source)) raise From 81fae9325fd30432f6001f16e2ae8a1dae89e312 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 11:31:45 +0200 Subject: [PATCH 232/548] cdist is written with a small c ... and the error message being made nicer Signed-off-by: Nico Schottelius --- scripts/cdist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/cdist b/scripts/cdist index 38ff5cb2..39449666 100755 --- a/scripts/cdist +++ b/scripts/cdist @@ -128,8 +128,8 @@ if __name__ == "__main__": cdistpythonversion = '3.2' if sys.version < cdistpythonversion: - print('Cdist requires Python >= ' + cdistpythonversion + - ' on the source host.', file=sys.stderr) + print('Python >= ' + cdistpythonversion + + ' is required on the source host.', file=sys.stderr) sys.exit(1) From 0f6b6f420c59f980597fa6384084d358365bd919 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 19:22:53 +0200 Subject: [PATCH 233/548] new type: __iptables_rule Signed-off-by: Nico Schottelius --- cdist/conf/type/__iptables_rule/man.text | 63 +++++++++++++++++++ cdist/conf/type/__iptables_rule/manifest | 46 ++++++++++++++ .../type/__iptables_rule/parameter/optional | 1 + .../type/__iptables_rule/parameter/required | 1 + docs/changelog | 1 + 5 files changed, 112 insertions(+) create mode 100644 cdist/conf/type/__iptables_rule/man.text create mode 100644 cdist/conf/type/__iptables_rule/manifest create mode 100644 cdist/conf/type/__iptables_rule/parameter/optional create mode 100644 cdist/conf/type/__iptables_rule/parameter/required diff --git a/cdist/conf/type/__iptables_rule/man.text b/cdist/conf/type/__iptables_rule/man.text new file mode 100644 index 00000000..4e5d2f26 --- /dev/null +++ b/cdist/conf/type/__iptables_rule/man.text @@ -0,0 +1,63 @@ +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 80 -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) +- 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/manifest b/cdist/conf/type/__iptables_rule/manifest new file mode 100644 index 00000000..a6abbd5e --- /dev/null +++ b/cdist/conf/type/__iptables_rule/manifest @@ -0,0 +1,46 @@ +# +# 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 . +# +# + +base_dir=/etc/iptables.d + +name="$__object_id" + +if [ -f "$__object/parameter/state" ]; then + state="$(cat "$__object/parameter/state")" +else + state="present" +fi + +################################################################################ +# Basic setup +# + +__directory "$base_dir" --state present + +# Have apply do the real job +require="$__object_name" __iptables_apply + +################################################################################ +# The rule +# + +require="__directory/$base_dir" __file "$base_dir/${name}" \ + --source "$__object/parameter/rule" \ + --state "$state" diff --git a/cdist/conf/type/__iptables_rule/parameter/optional b/cdist/conf/type/__iptables_rule/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__iptables_rule/parameter/optional @@ -0,0 +1 @@ +state diff --git a/cdist/conf/type/__iptables_rule/parameter/required b/cdist/conf/type/__iptables_rule/parameter/required new file mode 100644 index 00000000..2b254dff --- /dev/null +++ b/cdist/conf/type/__iptables_rule/parameter/required @@ -0,0 +1 @@ +rule diff --git a/docs/changelog b/docs/changelog index 78701e5d..c53227ca 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ Changelog * Core: Fix typo in argument parser * Core: Code cleanup: Remove old install code (Steven Armstrong) * Core: Improve error message when using non-existing type in requirement + * New Type: __iptables_rule * Type __cdist: Also create home directory * Type __cdist: Add support for --shell parameter * Type __motd: Regenerate motd on Debian and Ubuntu From f8d3e36efbd6185a2ac0d085b92d0ce3fe9c7dc5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 19:29:11 +0200 Subject: [PATCH 234/548] new type: __iptables_apply Signed-off-by: Nico Schottelius --- .../type/__iptables_apply/files/init-script | 48 +++++++++++++++++++ .../conf/type/__iptables_apply/gencode-remote | 2 + cdist/conf/type/__iptables_apply/man.text | 42 ++++++++++++++++ cdist/conf/type/__iptables_apply/manifest | 26 ++++++++++ cdist/conf/type/__iptables_apply/singleton | 0 cdist/conf/type/__iptables_rule/man.text | 1 + docs/changelog | 1 + 7 files changed, 120 insertions(+) create mode 100644 cdist/conf/type/__iptables_apply/files/init-script create mode 100644 cdist/conf/type/__iptables_apply/gencode-remote create mode 100644 cdist/conf/type/__iptables_apply/man.text create mode 100644 cdist/conf/type/__iptables_apply/manifest create mode 100644 cdist/conf/type/__iptables_apply/singleton diff --git a/cdist/conf/type/__iptables_apply/files/init-script b/cdist/conf/type/__iptables_apply/files/init-script new file mode 100644 index 00000000..2dc952e9 --- /dev/null +++ b/cdist/conf/type/__iptables_apply/files/init-script @@ -0,0 +1,48 @@ +#!/bin/sh +# Nico Schottelius +# Zürisee, Mon Sep 2 18:38:27 CEST 2013 +# +### BEGIN INIT INFO +# Provides: iptables +# Required-Start: $local_fs $remote_fs +# Required-Stop: $local_fs $remote_fs +# X-Start-Before: fail2ban +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Applies iptables ruleset +# Description: Applies all rules found in /etc/iptables.d +# and saves/restores previous status +### END INIT INFO + + +basedir=/etc/iptables.d +status="${basedir}/.pre-start" + +case $1 in + start) + # Save status + iptables-save > "$status" + + # Apply our ruleset + cd "$basedir" + 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") + done + fi + ;; + + stop) + # Restore from status before, if there is something to restore + if [ -f "$status" ]; then + iptables-restore < "$status" + fi + ;; + restart) + "$0" stop && "$0" start + ;; +esac diff --git a/cdist/conf/type/__iptables_apply/gencode-remote b/cdist/conf/type/__iptables_apply/gencode-remote new file mode 100644 index 00000000..0773b452 --- /dev/null +++ b/cdist/conf/type/__iptables_apply/gencode-remote @@ -0,0 +1,2 @@ +# Rebuild rules - FIXME: do conditionally as soon as cdist supports it +echo /etc/init.d/iptables restart diff --git a/cdist/conf/type/__iptables_apply/man.text b/cdist/conf/type/__iptables_apply/man.text new file mode 100644 index 00000000..87f4b4ee --- /dev/null +++ b/cdist/conf/type/__iptables_apply/man.text @@ -0,0 +1,42 @@ +cdist-type__iptables_apply(7) +============================= +Nico Schottelius + + +NAME +---- +cdist-type__iptables_apply - Apply the rules + + +DESCRIPTION +----------- +This cdist type deploys an init script that triggers +the configured rules and also re-applies them on +configuration. + + +REQUIRED PARAMETERS +------------------- +None + +OPTIONAL PARAMETERS +------------------- +None + +EXAMPLES +-------- + +None (__iptables_apply is used by __iptables_rule) + + +SEE ALSO +-------- +- cdist-type(7) +- cdist-type__iptables_rule(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_apply/manifest b/cdist/conf/type/__iptables_apply/manifest new file mode 100644 index 00000000..a22901ba --- /dev/null +++ b/cdist/conf/type/__iptables_apply/manifest @@ -0,0 +1,26 @@ +# +# 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 . +# +# + +__file /etc/init.d/iptables \ + --source "$__type/files/init-script" \ + --state present \ + --mode 0755 + +require="__file/etc/init.d/iptables" __start_on_boot iptables diff --git a/cdist/conf/type/__iptables_apply/singleton b/cdist/conf/type/__iptables_apply/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__iptables_rule/man.text b/cdist/conf/type/__iptables_rule/man.text index 4e5d2f26..eb230093 100644 --- a/cdist/conf/type/__iptables_rule/man.text +++ b/cdist/conf/type/__iptables_rule/man.text @@ -54,6 +54,7 @@ __iptables_rule munin --rule "-A INPUT -p tcp --dport 4949 -j ACCEPT" \ SEE ALSO -------- - cdist-type(7) +- cdist-type__iptables_apply(7) - iptables(8) diff --git a/docs/changelog b/docs/changelog index c53227ca..f6fd1c2c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * Core: Code cleanup: Remove old install code (Steven Armstrong) * Core: Improve error message when using non-existing type in requirement * New Type: __iptables_rule + * New Type: __iptables_apply * Type __cdist: Also create home directory * Type __cdist: Add support for --shell parameter * Type __motd: Regenerate motd on Debian and Ubuntu From e3f401900a3fb5215ed36488ac55aaa0a7e39911 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Sep 2013 19:58:11 +0200 Subject: [PATCH 235/548] add the type as well... Signed-off-by: Nico Schottelius --- cdist/conf/type/__panter_iptables/manifest | 9 +++++++++ cdist/conf/type/__panter_iptables/singleton | 0 2 files changed, 9 insertions(+) create mode 100644 cdist/conf/type/__panter_iptables/manifest create mode 100644 cdist/conf/type/__panter_iptables/singleton diff --git a/cdist/conf/type/__panter_iptables/manifest b/cdist/conf/type/__panter_iptables/manifest new file mode 100644 index 00000000..14ab786f --- /dev/null +++ b/cdist/conf/type/__panter_iptables/manifest @@ -0,0 +1,9 @@ +__iptables_rule policy-in --rule "-P INPUT DROP" +__iptables_rule policy-out --rule "-P OUTPUT ACCEPT" +__iptables_rule policy-fwd --rule "-P FORWARD DROP" + +__iptables_rule established --rule "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT" +__iptables_rule http --rule "-A INPUT -p tcp --dport 80 -j ACCEPT" +__iptables_rule ssh --rule "-A INPUT -p tcp --dport 80 -j ACCEPT" +__iptables_rule https --rule "-A INPUT -p tcp --dport 443 -j ACCEPT" +__iptables_rule munin --rule "-A INPUT -p tcp --dport 4949 -j ACCEPT" diff --git a/cdist/conf/type/__panter_iptables/singleton b/cdist/conf/type/__panter_iptables/singleton new file mode 100644 index 00000000..e69de29b From 5a2873efc84219dba0a8c21949a03cdd05389c79 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 3 Sep 2013 09:11:12 +0200 Subject: [PATCH 236/548] remove customer types Should not have been committed here - sorry for the noise. Signed-off-by: Nico Schottelius --- cdist/conf/type/__panter_iptables/manifest | 9 --------- cdist/conf/type/__panter_iptables/singleton | 0 2 files changed, 9 deletions(-) delete mode 100644 cdist/conf/type/__panter_iptables/manifest delete mode 100644 cdist/conf/type/__panter_iptables/singleton diff --git a/cdist/conf/type/__panter_iptables/manifest b/cdist/conf/type/__panter_iptables/manifest deleted file mode 100644 index 14ab786f..00000000 --- a/cdist/conf/type/__panter_iptables/manifest +++ /dev/null @@ -1,9 +0,0 @@ -__iptables_rule policy-in --rule "-P INPUT DROP" -__iptables_rule policy-out --rule "-P OUTPUT ACCEPT" -__iptables_rule policy-fwd --rule "-P FORWARD DROP" - -__iptables_rule established --rule "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT" -__iptables_rule http --rule "-A INPUT -p tcp --dport 80 -j ACCEPT" -__iptables_rule ssh --rule "-A INPUT -p tcp --dport 80 -j ACCEPT" -__iptables_rule https --rule "-A INPUT -p tcp --dport 443 -j ACCEPT" -__iptables_rule munin --rule "-A INPUT -p tcp --dport 4949 -j ACCEPT" diff --git a/cdist/conf/type/__panter_iptables/singleton b/cdist/conf/type/__panter_iptables/singleton deleted file mode 100644 index e69de29b..00000000 From a4151fee447f2a9df6cc6c285afab98cc1f8d011 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 3 Sep 2013 21:32:26 +0200 Subject: [PATCH 237/548] fix shell from previous context change Signed-off-by: Nico Schottelius --- cdist/shell.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cdist/shell.py b/cdist/shell.py index b88c3ccd..ebf9f434 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -38,11 +38,8 @@ class Shell(object): self.shell = shell self.target_host = "cdist-shell-no-target-host" - self.local = cdist.local.Local( - target_host=self.target_host, - remote_copy=cdist.REMOTE_COPY, - remote_exec=cdist.REMOTE_EXEC) - + self.local = cdist.exec.local.Local( + target_host=self.target_host) def _init_shell(self): """Select shell to execute, if not specified by user""" @@ -62,7 +59,7 @@ class Shell(object): 'PATH': "%s:%s" % (self.local.bin_path, os.environ['PATH']), '__cdist_type_base_path': self.local.type_path, # for use in type emulator '__cdist_manifest': "cdist shell", - '__global': self.local.out_path, + '__global': self.local.base_path, '__target_host': self.target_host, '__manifest': self.local.manifest_path, '__explorer': self.local.global_explorer_path, From 7646375218095cf2a9d0f9e415a7b5f5e989b6d0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Sep 2013 21:20:05 +0200 Subject: [PATCH 238/548] plan next release for ... today Signed-off-by: Nico Schottelius --- Makefile | 4 ---- bin/build-helper | 7 +++++++ docs/changelog | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 1183be6f..e13c5fc7 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,6 @@ # # -# dist = local -# release = remote - A2XM=a2x -f manpage --no-xmllint -a encoding=UTF-8 A2XH=a2x -f xhtml --no-xmllint -a encoding=UTF-8 helper=./bin/build-helper @@ -249,7 +246,6 @@ RELEASE+=man-dist pypi-release git-release RELEASE+=archlinux-release release: $(CHECKS) $(RELEASE) -#release: | $(CHECKS) man speeches echo "Manual steps: linkedin, twitter" # Code that is better handled in a shell script diff --git a/bin/build-helper b/bin/build-helper index 54940ab2..9409975c 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -173,6 +173,13 @@ eof ;; + release) + set -e + # First check everything is sane + "$0" check-date + "$0" check-unittest + ;; + test) export PYTHONPATH="$(pwd -P)" diff --git a/docs/changelog b/docs/changelog index f6fd1c2c..4ce46089 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.3.2: +2.3.2: 2013-09-04 * Core: Fix typo in argument parser * Core: Code cleanup: Remove old install code (Steven Armstrong) * Core: Improve error message when using non-existing type in requirement From 1927d4852a9fa2e094d55bff7a73733610d7026a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 4 Sep 2013 22:11:08 +0200 Subject: [PATCH 239/548] add tests for configurable default values for parameters Signed-off-by: Steven Armstrong --- cdist/test/cdist_type/__init__.py | 7 +++++++ .../parameter/default/optional1 | 1 + .../__with_parameter_defaults/parameter/optional | 2 ++ cdist/test/emulator/__init__.py | 15 +++++++++++++++ .../parameter/default/optional1 | 1 + .../type/__argument_defaults/parameter/optional | 2 ++ 6 files changed, 28 insertions(+) create mode 100644 cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/default/optional1 create mode 100644 cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/optional create mode 100644 cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/default/optional1 create mode 100644 cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/optional diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index e97ce7e6..79f824d3 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -146,3 +146,10 @@ class TypeTestCase(test.CdistTestCase): cdist_type = core.CdistType(base_path, '__without_boolean_parameters') self.assertEqual(cdist_type.boolean_parameters, []) + def test_with_parameter_defaults(self): + base_path = fixtures + cdist_type = core.CdistType(base_path, '__with_parameter_defaults') + self.assertTrue('optional1' in cdist_type.parameter_defaults) + self.assertFalse('optional2' in cdist_type.parameter_defaults) + self.assertEqual(cdist_type.parameter_defaults['optional1'], 'value1') + diff --git a/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/default/optional1 b/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/default/optional1 new file mode 100644 index 00000000..ef208405 --- /dev/null +++ b/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/default/optional1 @@ -0,0 +1 @@ +value1 diff --git a/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/optional b/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/optional new file mode 100644 index 00000000..8174d2a9 --- /dev/null +++ b/cdist/test/cdist_type/fixtures/__with_parameter_defaults/parameter/optional @@ -0,0 +1,2 @@ +optional1 +optional2 diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 9f6d7000..8c2dcd72 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -219,6 +219,21 @@ class ArgumentsTestCase(test.CdistTestCase): self.assertFalse('optional2' in cdist_object.parameters) self.assertEqual(cdist_object.parameters['optional1'], value) + def test_argument_defaults(self): + type_name = '__argument_defaults' + object_id = 'some-id' + value = 'value1' + argv = [type_name, object_id] + 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) + self.assertTrue('optional1' in cdist_object.parameters) + self.assertFalse('optional2' in cdist_object.parameters) + self.assertEqual(cdist_object.parameters['optional1'], value) + class StdinTestCase(test.CdistTestCase): diff --git a/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/default/optional1 b/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/default/optional1 new file mode 100644 index 00000000..ef208405 --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/default/optional1 @@ -0,0 +1 @@ +value1 diff --git a/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/optional b/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/optional new file mode 100644 index 00000000..8174d2a9 --- /dev/null +++ b/cdist/test/emulator/fixtures/conf/type/__argument_defaults/parameter/optional @@ -0,0 +1,2 @@ +optional1 +optional2 From fc40a40ae0b4bb884f50443187ec2852b1766553 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 4 Sep 2013 22:11:42 +0200 Subject: [PATCH 240/548] implement configurable default values for parameters Signed-off-by: Steven Armstrong --- cdist/core/cdist_type.py | 17 +++++++++++++++++ cdist/emulator.py | 6 ++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index b6ba4f00..46e126f9 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -62,6 +62,7 @@ class CdistType(object): self.__optional_parameters = None self.__optional_multiple_parameters = None self.__boolean_parameters = None + self.__parameter_defaults = None @classmethod def list_types(cls, base_path): @@ -190,3 +191,19 @@ class CdistType(object): finally: self.__boolean_parameters = parameters return self.__boolean_parameters + + @property + def parameter_defaults(self): + if not self.__parameter_defaults: + defaults = {} + try: + defaults_dir = os.path.join(self.absolute_path, "parameter", "default") + for name in os.listdir(defaults_dir): + with open(os.path.join(defaults_dir, name)) as fd: + defaults[name] = fd.read().strip() + except EnvironmentError: + # error ignored + pass + finally: + self.__parameter_defaults = defaults + return self.__parameter_defaults diff --git a/cdist/emulator.py b/cdist/emulator.py index f1f4b622..b1cd8f2d 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -96,10 +96,12 @@ class Emulator(object): 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) + parser.add_argument(argument, dest=parameter, action='store', required=False, + default=self.cdist_type.parameter_defaults.get(parameter, None)) for parameter in self.cdist_type.optional_multiple_parameters: argument = "--" + parameter - parser.add_argument(argument, dest=parameter, action='append', required=False) + parser.add_argument(argument, dest=parameter, action='append', required=False, + default=self.cdist_type.parameter_defaults.get(parameter, None)) for parameter in self.cdist_type.boolean_parameters: argument = "--" + parameter parser.add_argument(argument, dest=parameter, action='store_const', const='') From 9358efd273fdbe84814976215acbb0b4c2ec453c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 4 Sep 2013 22:23:01 +0200 Subject: [PATCH 241/548] document new feature: configurable default values for parameters Signed-off-by: Steven Armstrong --- docs/man/cdist-reference.text.sh | 7 ++++++- docs/man/man7/cdist-type.text | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index b0a9d32c..b41be801 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -116,8 +116,13 @@ confdir/type//parameter/required:: confdir/type//parameter/optional:: Parameters optionally accepted by type, \n seperated 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 seperated list. + Boolean parameters accepted by type, \n seperated list. confdir/type//explorer:: Location of the type specific explorers. diff --git a/docs/man/man7/cdist-type.text b/docs/man/man7/cdist-type.text index cfb50414..8415f991 100644 --- a/docs/man/man7/cdist-type.text +++ b/docs/man/man7/cdist-type.text @@ -82,10 +82,16 @@ follow the standard unix behaviour "the last given wins". 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/***. + 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 -------------------------------------------------------------------------------- @@ -108,6 +114,9 @@ if [ -f "$__object/parameter/logdirectory" ]; then logdirectory="$(cat "$__object/parameter/logdirectory")" fi +# optional parameter with predefined default +loglevel="$(cat "$__object/parameter/loglevel")" + # boolean parameter if [ -f "$__object/parameter/use_ssl" ]; then # file exists -> True From dc2b37cec12da7fe73e6844e7efb2412b5ea77a9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Sep 2013 22:33:26 +0200 Subject: [PATCH 242/548] release in Makefile is cumbersome, use shell Signed-off-by: Nico Schottelius --- Makefile | 47 +----------------------------- bin/build-helper | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 46 deletions(-) diff --git a/Makefile b/Makefile index e13c5fc7..419f8023 100644 --- a/Makefile +++ b/Makefile @@ -170,39 +170,6 @@ $(FREECODE_FILE): $(CHANGELOG_FILE) freecode-release: $(FREECODE_FILE) -################################################################################ -# git and git dependent stuff -# - -GIT_TAG_FILE=.git/refs/tags/$(CHANGELOG_VERSION) -GIT_SRC_BRANCH=master -GIT_DST_BRANCH=$(shell echo $(CHANGELOG_VERSION) | cut -d. -f '1,2') -GIT_CURRENT=.git-current-branch - -git-tag: $(GIT_TAG_FILE) - -$(GIT_TAG_FILE): - @printf "Enter tag description for $(CHANGELOG_VERSION)> " - @read tagmessage; git tag "$(CHANGELOG_VERSION)" -m "$$tagmessage" - -git-branch-merge: git-checkout-stable - git merge "$(CHANGELOG_VERSION)" - -git-checkout-stable: git-tag - @git rev-parse --abbrev-ref HEAD > $(GIT_CURRENT) - @git checkout "$(GIT_DST_BRANCH)" - -git-checkout-current: - git checkout "$$(cat $(GIT_CURRENT))" - -$(VERSION_FILE): .git/refs/heads/* .git/refs/tags/* .git/HEAD - echo "VERSION = \"$$(git describe)\"" > $@ - -git-release: git-tag - make git-branch-merge - make git-checkout-current - make pub - ################################################################################ # pypi # @@ -236,20 +203,8 @@ archlinux-release: $(ARCHLINUX_FILE) # Release # -CHECKS=check-date check-unittest - -check-unittest: $(VERSION_FILE) - -RELEASE=speeches-dist web-release -RELEASE+=ml-release freecode-release -RELEASE+=man-dist pypi-release git-release -RELEASE+=archlinux-release - -release: $(CHECKS) $(RELEASE) - echo "Manual steps: linkedin, twitter" - # Code that is better handled in a shell script -check-%: +check-% release: $(helper) $@ ################################################################################ diff --git a/bin/build-helper b/bin/build-helper index 9409975c..033d4ff7 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -173,11 +173,82 @@ eof ;; + release-git-tag) + target_version=$($0 changelog-version) + if git rev-parse --verify refs/tags/$target_version; 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 --exit-code --quiet HEAD; then + echo "Unclean tree, aborting" + exit 1 + fi + + # Ensure we are on the master branch + if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ]; then + echo "Releases are happening from the master branch, aborting" + exit 1 + fi + + # 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 + + # Verify that after the merge everything works + "$0" check-date + "$0" check-unittest + + # Generate man pages (indirect check if they build) + make man + + # Generate speeches (indirect check if they build) + make speeches + + ############################################################# + # Everything green, let's do the release + + # Tag the current commit + "$0" release-git-tag + + # Also merge back the version branch + git checkout master + git merge "$target_branch" + + + exit 0 + + make speeches-dist + + RELEASE=speeches-dist web-release + RELEASE+=ml-release freecode-release + RELEASE+=man-dist pypi-release git-release + RELEASE+=archlinux-release + ;; test) @@ -190,6 +261,10 @@ eof fi ;; + version-branch) + "$0" changelog-version | cut -d. -f '1,2' + ;; + version) echo "VERSION = \"$(git describe)\"" > cdist/version.py ;; From 8af3374965676d36940e3e496c1fd95d21759b60 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Sep 2013 22:37:39 +0200 Subject: [PATCH 243/548] ++debug Signed-off-by: Nico Schottelius --- bin/build-helper | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/build-helper b/bin/build-helper index 033d4ff7..75b8c16a 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -198,8 +198,12 @@ eof # Generate version file to be included in packaging "$0" version + set -x + pwd + git diff-index --exit-code --quiet HEAD + ret=$? # Ensure the git status is clean, else abort - if ! git diff-index --exit-code --quiet HEAD; then + if [ "$ret" -ne 0 ]; then echo "Unclean tree, aborting" exit 1 fi From 74449ba45edcae4120a1cd01c0094fa32eba188d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Sep 2013 22:45:59 +0200 Subject: [PATCH 244/548] --name-only Signed-off-by: Nico Schottelius --- bin/build-helper | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 75b8c16a..1b6921b7 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -198,12 +198,8 @@ eof # Generate version file to be included in packaging "$0" version - set -x - pwd - git diff-index --exit-code --quiet HEAD - ret=$? # Ensure the git status is clean, else abort - if [ "$ret" -ne 0 ]; then + if ! git diff-index --name-only --quiet HEAD >/dev/null; then echo "Unclean tree, aborting" exit 1 fi From c68c11dce1d59ac54b1fe60d45077e0aa24c5006 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Sep 2013 22:58:52 +0200 Subject: [PATCH 245/548] cleanup the release process Signed-off-by: Nico Schottelius --- Makefile | 10 ++++++---- bin/build-helper | 19 +++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 419f8023..816240a0 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,7 @@ man-dist: man check-date cp ${MAN7DSTDIR}/*.html ${MAN7DSTDIR}/*.css ${MANWEBDIR}/man7 cd ${MANWEBDIR} && git add . && git commit -m "cdist manpages update: $(CHANGELOG_VERSION)" || true -man-release: web-release +man-fix-link: web-pub # Fix ikiwiki, which does not like symlinks for pseudo security ssh tee.schottelius.org \ "cd /home/services/www/nico/www.nico.schottelius.org/www/software/cdist/man && rm -f latest && ln -sf "$(CHANGELOG_VERSION)" latest" @@ -143,9 +143,11 @@ web-doc: web-dist: web-blog web-doc -web-release: web-dist man-dist speeches-dist +web-pub: web-dist man-dist speeches-dist cd "${WEBDIR}" && make pub +web-release-all: man-fix-link + ################################################################################ # Release: Mailinglist # @@ -175,7 +177,7 @@ freecode-release: $(FREECODE_FILE) # PYPI_FILE=.lock-pypi -pypi-release: $(PYPI_FILE) git-branch-merge +pypi-release: $(PYPI_FILE) $(PYPI_FILE): man $(VERSION_FILE) python3 setup.py sdist upload @@ -187,7 +189,7 @@ $(PYPI_FILE): man $(VERSION_FILE) ARCHLINUX_FILE=.lock-archlinux ARCHLINUXTAR=cdist-$(CHANGELOG_VERSION)-1.src.tar.gz -$(ARCHLINUXTAR): PKGBUILD pypi-release +$(ARCHLINUXTAR): PKGBUILD makepkg -c --source PKGBUILD: PKGBUILD.in $(VERSION_FILE) diff --git a/bin/build-helper b/bin/build-helper index 1b6921b7..6de5b1e8 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -239,16 +239,23 @@ eof git checkout master git merge "$target_branch" + # Publish git changes + make pub - exit 0 + # publish man, speeches, website + make web-release-all - make speeches-dist + # Create and publish package for pypi + make pypi-release - RELEASE=speeches-dist web-release - RELEASE+=ml-release freecode-release - RELEASE+=man-dist pypi-release git-release - RELEASE+=archlinux-release + # Archlinux release is based on pypi + make archlinux-release + # Announce change on Freecode + make freecode-release + + # Announce change on ML + make ml-release ;; test) From c074d377aa23971e3116eb9357c09d8b35386d9c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Sep 2013 22:59:46 +0200 Subject: [PATCH 246/548] seperate check-% and release Signed-off-by: Nico Schottelius --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 816240a0..dd00328d 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,10 @@ archlinux-release: $(ARCHLINUX_FILE) # # Code that is better handled in a shell script -check-% release: +check-%: + $(helper) $@ + +release: $(helper) $@ ################################################################################ From 5f2aff73dc4755896718efe81f8667789d119809 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Sep 2013 23:11:41 +0200 Subject: [PATCH 247/548] show files that prevent release Signed-off-by: Nico Schottelius --- bin/build-helper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-helper b/bin/build-helper index 6de5b1e8..4ec4bf1a 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -199,7 +199,7 @@ eof "$0" version # Ensure the git status is clean, else abort - if ! git diff-index --name-only --quiet HEAD >/dev/null; then + if ! git diff-index --name-only --exit-code HEAD ; then echo "Unclean tree, aborting" exit 1 fi From 04ae94a2df222fe6f7a71e1949e0567ecc329265 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Sep 2013 23:14:02 +0200 Subject: [PATCH 248/548] +hint Signed-off-by: Nico Schottelius --- bin/build-helper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-helper b/bin/build-helper index 4ec4bf1a..aec02412 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -200,7 +200,7 @@ eof # Ensure the git status is clean, else abort if ! git diff-index --name-only --exit-code HEAD ; then - echo "Unclean tree, aborting" + echo "Unclean tree, see files above, aborting" exit 1 fi From 33559fad67163c2535a6eea092e5224207f2b6b0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Sep 2013 23:33:52 +0200 Subject: [PATCH 249/548] add comments to some tests Signed-off-by: Nico Schottelius --- cdist/test/explorer/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index d1b86725..b0e4b24c 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -69,11 +69,13 @@ class ExplorerClassTestCase(test.CdistTestCase): shutil.rmtree(self.temp_dir) def test_list_global_explorer_names(self): + """Ensure that all explorers are listed""" names = self.explorer.list_global_explorer_names() self.assertIn("foobar", names) self.assertIn("global", names) def test_transfer_global_explorers(self): + """Ensure transferring explorers to remote works""" self.explorer.transfer_global_explorers() source = self.local.global_explorer_path destination = self.remote.global_explorer_path @@ -85,7 +87,7 @@ class ExplorerClassTestCase(test.CdistTestCase): output = self.explorer.run_global_explorer('global') self.assertEqual(output, 'global\n') - def test_run_global_explorers(self): + def test_global_explorer_output(self): """Ensure output is created for every global explorer""" out_path = self.mkdtemp() @@ -102,6 +104,7 @@ class ExplorerClassTestCase(test.CdistTestCase): 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) From e1fa588a4dd308aed4f8635e69d0cd2ac85762db Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Sep 2013 12:57:52 +0200 Subject: [PATCH 250/548] clean should clean better Signed-off-by: Nico Schottelius --- Makefile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index dd00328d..660fbb10 100644 --- a/Makefile +++ b/Makefile @@ -228,14 +228,16 @@ clean: find * -name __pycache__ | xargs rm -rf -distclean: clean - rm -f cdist/version.py MANIFEST PKGBUILD - rm -rf dist/ - # Archlinux rm -f cdist-*.pkg.tar.xz cdist-*.tar.gz rm -rf pkg/ src/ + rm -f MANIFEST PKGBUILD + rm -rf dist/ + +distclean: clean + rm -f cdist/version.py + ################################################################################ # Misc # From 98cdc6c1392625725c5bc49edf603aa5a75d8369 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Sep 2013 13:02:39 +0200 Subject: [PATCH 251/548] fix tests so that the explorers are not changed while running tests Signed-off-by: Nico Schottelius --- cdist/test/explorer/__init__.py | 6 +++--- cdist/test/fixtures/remote | 1 - cdist/test/fixtures/remote/README | 3 +++ cdist/test/fixtures/remote/copy | 30 ++++++++++++++++++++++++++++++ cdist/test/fixtures/remote/exec | 23 +++++++++++++++++++++++ 5 files changed, 59 insertions(+), 4 deletions(-) delete mode 120000 cdist/test/fixtures/remote create mode 100644 cdist/test/fixtures/remote/README create mode 100755 cdist/test/fixtures/remote/copy create mode 100755 cdist/test/fixtures/remote/exec diff --git a/cdist/test/explorer/__init__.py b/cdist/test/explorer/__init__.py index b0e4b24c..92ef75a3 100644 --- a/cdist/test/explorer/__init__.py +++ b/cdist/test/explorer/__init__.py @@ -39,9 +39,9 @@ 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( diff --git a/cdist/test/fixtures/remote b/cdist/test/fixtures/remote deleted file mode 120000 index c5db6358..00000000 --- a/cdist/test/fixtures/remote +++ /dev/null @@ -1 +0,0 @@ -../../../other/examples/remote/local \ No newline at end of file diff --git a/cdist/test/fixtures/remote/README b/cdist/test/fixtures/remote/README new file mode 100644 index 00000000..cfd350f9 --- /dev/null +++ b/cdist/test/fixtures/remote/README @@ -0,0 +1,3 @@ +This effectively turns remote calling into local calling. + +Probably most useful for the unittesting. diff --git a/cdist/test/fixtures/remote/copy b/cdist/test/fixtures/remote/copy new file mode 100755 index 00000000..a5b5fe6f --- /dev/null +++ b/cdist/test/fixtures/remote/copy @@ -0,0 +1,30 @@ +#!/bin/sh +# +# 2012-2013 Nico Schottelius (nico-cdist 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 . +# +# +# This is based on other/examples/remote/local/, but uses --dereference for the +# test cases +# + +recursive=$1; shift +src=$1; shift +dst=$1; shift + +dst=$(echo $dst | sed "s/^${__target_host}://") +cp --dereference "$recursive" "$src" "$dst" diff --git a/cdist/test/fixtures/remote/exec b/cdist/test/fixtures/remote/exec new file mode 100755 index 00000000..838513a9 --- /dev/null +++ b/cdist/test/fixtures/remote/exec @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2012 Nico Schottelius (nico-cdist 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 . +# +# + +target_host=$1; shift +echo "$@" | /bin/sh From 7acf0412db2788b84e3c8eefe7f145691453c001 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Sep 2013 13:03:35 +0200 Subject: [PATCH 252/548] ++changes(2.3.2) Signed-off-by: Nico Schottelius --- docs/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 4ce46089..812c55ea 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,8 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.3.2: 2013-09-04 +2.3.2: 2013-09-05 + * Build: Ensure tests don't change attributes of non-test files * Core: Fix typo in argument parser * Core: Code cleanup: Remove old install code (Steven Armstrong) * Core: Improve error message when using non-existing type in requirement From 295a8a404d79cab8d5084791ece67c4b9b332858 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Sep 2013 13:19:47 +0200 Subject: [PATCH 253/548] more cleanups for the release process Signed-off-by: Nico Schottelius --- Makefile | 17 ++++++++--------- bin/build-helper | 10 ++++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 660fbb10..5910ab2e 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ WEBPAGE=$(WEBBASE).mdwn CHANGELOG_VERSION=$(shell $(helper) changelog-version) CHANGELOG_FILE=docs/changelog -VERSION_FILE=cdist/version.py +PYTHON_VERSION=cdist/version.py ################################################################################ # Manpages @@ -154,7 +154,7 @@ web-release-all: man-fix-link ML_FILE=.lock-ml # Only send mail once - lock until new changelog things happened -$(ML_FILE): $(CHANGELOG_FILE) git-release web-release +$(ML_FILE): $(CHANGELOG_FILE) $(helper) ml-release $(CHANGELOG_VERSION) touch $@ @@ -175,11 +175,7 @@ freecode-release: $(FREECODE_FILE) ################################################################################ # pypi # -PYPI_FILE=.lock-pypi - -pypi-release: $(PYPI_FILE) - -$(PYPI_FILE): man $(VERSION_FILE) +pypi-release: man $(PYTHON_VERSION) python3 setup.py sdist upload touch $@ @@ -192,10 +188,10 @@ ARCHLINUXTAR=cdist-$(CHANGELOG_VERSION)-1.src.tar.gz $(ARCHLINUXTAR): PKGBUILD makepkg -c --source -PKGBUILD: PKGBUILD.in $(VERSION_FILE) +PKGBUILD: PKGBUILD.in $(PYTHON_VERSION) ./PKGBUILD.in $(CHANGELOG_VERSION) -$(ARCHLINUX_FILE): $(ARCHLINUXTAR) $(VERSION_FILE) +$(ARCHLINUX_FILE): $(ARCHLINUXTAR) $(PYTHON_VERSION) burp -c system $(ARCHLINUXTAR) touch $@ @@ -205,6 +201,9 @@ archlinux-release: $(ARCHLINUX_FILE) # Release # +$(PYTHON_VERSION): .git/refs/heads/master + $(helper) version + # Code that is better handled in a shell script check-%: $(helper) $@ diff --git a/bin/build-helper b/bin/build-helper index aec02412..fdbf2ba4 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -256,6 +256,16 @@ eof # Announce change on ML make ml-release + + cat << eof +Manual steps post release: + + - linkedin + - hackernews + - twitter + +eof + ;; test) From 05716b2408202ce233082f8e7e49cc412071e6a0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Sep 2013 13:29:28 +0200 Subject: [PATCH 254/548] +hint Signed-off-by: Nico Schottelius --- bin/build-helper | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/build-helper b/bin/build-helper index fdbf2ba4..1d6070aa 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -262,6 +262,7 @@ Manual steps post release: - linkedin - hackernews + - reddit - twitter eof From 48e2468c5662b92e24cd686ba17ffed993396547 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 5 Sep 2013 13:45:27 +0200 Subject: [PATCH 255/548] changes(2.3.3)++ Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 812c55ea..4b8a7741 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.3.3: + * Core: Add support for default values of optional parameters (Steven Armstrong) + 2.3.2: 2013-09-05 * Build: Ensure tests don't change attributes of non-test files * Core: Fix typo in argument parser From 127c512f844cd44bda60d023119aa7ece0c345b2 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sun, 8 Sep 2013 22:10:25 +0200 Subject: [PATCH 256/548] call systemctl in subshell to prevent the explorer from failing if it exits non zero Signed-off-by: Steven Armstrong --- cdist/conf/type/__start_on_boot/explorer/state | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index b156fc82..4e0c82c2 100755 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -28,14 +28,9 @@ name="$__object_id" case "$os" in archlinux) - # convert bash array to shell - systemctl is-enabled "$name" >/dev/null 2>&1; ret=$? - - if [ "$ret" = 0 ]; then - state="present" - else - state="absent" - fi + state=$(systemctl is-enabled "$name" >/dev/null 2>&1 \ + && echo present \ + || echo absent) ;; debian|ubuntu|openwrt) @@ -48,7 +43,7 @@ case "$os" in [ "$state" ] || state="present" ;; - *) + *) echo "Unsupported os: $os" >&2 exit 1 ;; From a132adbb0345c833c85a37ac7a1ad6dd5968b8c3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Sep 2013 11:39:26 +0200 Subject: [PATCH 257/548] ++changes(2.3.3) Signed-off-by: Nico Schottelius --- docs/changelog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 4b8a7741..9e2971f9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,8 +4,10 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.3.3: +2.3.3: 2013-09-09 * Core: Add support for default values of optional parameters (Steven Armstrong) + * Type __start_on_boot: Bugfix for systemd (Steven Armstrong) + 2.3.2: 2013-09-05 * Build: Ensure tests don't change attributes of non-test files From 73f22c7af1b364c6f0e9b510298dc85f8ee8055c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Sep 2013 11:46:29 +0200 Subject: [PATCH 258/548] ensure version string is updated before pypi release Signed-off-by: Nico Schottelius --- bin/build-helper | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/build-helper b/bin/build-helper index 1d6070aa..b97528f1 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -245,6 +245,9 @@ eof # publish man, speeches, website make web-release-all + # Ensure that pypi release has the right version + "$0" version + # Create and publish package for pypi make pypi-release From 77d93b63fd2cb3f595b20fb35a199a1a717f5319 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Sep 2013 21:35:46 +0200 Subject: [PATCH 259/548] add an old logfile Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-09-05.test-cp | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 docs/dev/logs/2013-09-05.test-cp diff --git a/docs/dev/logs/2013-09-05.test-cp b/docs/dev/logs/2013-09-05.test-cp new file mode 100644 index 00000000..1f02ee5d --- /dev/null +++ b/docs/dev/logs/2013-09-05.test-cp @@ -0,0 +1,34 @@ +Test copy copys symlinks - making real files would be better + +Test how to use cp: + +[12:54] bento:~% cd test +[12:54] bento:test% ln -s /etc/passwd +[12:54] bento:test% cd .. +[12:54] bento:~% cp -r test test2 +[12:54] bento:~% ls -lh test2/ +total 4.0K +lrwxrwxrwx 1 nico nico 11 Sep 5 12:54 passwd -> /etc/passwd +[12:54] bento:~% rm -rf test2/ + +-------------------------------------------------------------------------------- +[12:54] bento:~% ls -lh test2/ +total 4.0K +lrwxrwxrwx 1 nico nico 11 Sep 5 12:54 passwd -> /etc/passwd +[12:54] bento:~% rm -rf test2/ +[12:54] bento:~% cp -r --dereference test test2 +[12:56] bento:~% ls -l test2/ +total 4 +-rw------- 1 nico nico 960 Sep 5 12:56 passwd +[12:56] bento:~% + +-------------------------------------------------------------------------------- +[13:04] bento:cdist% git describe +2.3.2 +[13:09] bento:cdist% vi MANIFEST.in +[13:09] bento:cdist% vi MANIFEST +[13:09] bento:cdist% vi setup.py +[13:09] bento:cdist% cat cdist/version.py +VERSION = "2.3.1-34-g7acf041" +[13:10] bento:cdist% + From 589d50bdbab1c5e21412f711518e00a80d062891 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 12 Sep 2013 21:56:02 +0200 Subject: [PATCH 260/548] make --dry-run work, fixes #199 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 dc0417f1..7e003835 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -126,7 +126,7 @@ class Config(object): remote_exec=args.remote_exec, remote_copy=args.remote_copy) - c = cls(local, remote) + c = cls(local, remote, dry_run=args.dry_run) c.run() except cdist.Error as e: From 472198419a0f49f29108cf32a35713b48db90a04 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 12 Sep 2013 22:28:29 +0200 Subject: [PATCH 261/548] don't assume first argument to be -r, fixes #200 Signed-off-by: Steven Armstrong --- cdist/test/fixtures/remote/copy | 9 +++------ other/examples/remote/local/copy | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/cdist/test/fixtures/remote/copy b/cdist/test/fixtures/remote/copy index a5b5fe6f..57369b53 100755 --- a/cdist/test/fixtures/remote/copy +++ b/cdist/test/fixtures/remote/copy @@ -1,6 +1,7 @@ #!/bin/sh # # 2012-2013 Nico Schottelius (nico-cdist schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -22,9 +23,5 @@ # test cases # -recursive=$1; shift -src=$1; shift -dst=$1; shift - -dst=$(echo $dst | sed "s/^${__target_host}://") -cp --dereference "$recursive" "$src" "$dst" +code="$(echo "$@" | sed "s|\([[:space:]]+\)$__target_host:|\1|g")" +cp --dereference $code diff --git a/other/examples/remote/local/copy b/other/examples/remote/local/copy index 644fee15..0ddc44c8 100755 --- a/other/examples/remote/local/copy +++ b/other/examples/remote/local/copy @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Nico Schottelius (nico-cdist schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -19,9 +20,5 @@ # # -recursive=$1; shift -src=$1; shift -dst=$1; shift - -dst=$(echo $dst | sed "s/^${__target_host}://") -cp "$recursive" "$src" "$dst" +code="$(echo "$@" | sed "s|\([[:space:]]+\)$__target_host:|\1|g")" +cp --dereference $code From bba68b6e40c872b76450071aab5d22bb10c79e47 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 18 Sep 2013 10:40:29 +0200 Subject: [PATCH 262/548] only delete links; delete existing destination before creating links Signed-off-by: Steven Armstrong --- cdist/conf/type/__link/explorer/type | 26 ++++++++++++++++ cdist/conf/type/__link/gencode-remote | 30 ++++++++++++++++--- .../conf/type/__link/parameter/default/state | 1 + 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100755 cdist/conf/type/__link/explorer/type create mode 100644 cdist/conf/type/__link/parameter/default/state diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type new file mode 100755 index 00000000..c02b3af8 --- /dev/null +++ b/cdist/conf/type/__link/explorer/type @@ -0,0 +1,26 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist armstrong.cc) + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + type="$(cat "$__object/parameter/type")" + case "$type" in + hard) + link_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 +else + echo unknown +fi diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index 2975ef69..2e41b7d9 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -40,17 +41,38 @@ case "$type" in esac state_is="$(cat "$__object/explorer/state")" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" [ "$state_should" = "$state_is" ] && exit 0 +file_type="$(cat "$__object/explorer/type")" case "$state_should" in present) - echo ln ${lnopt} -f \"$source\" \"$destination\" + if [ "$file_type" = "directory" ]; then + # our destination is currently a directory, move it out of the way + cat << DONE +destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")" +mv "$destination" "\$destination_old" +DONE + fi + + # create our link + cat << DONE +ln ${lnopt} -f "$source" "$destination" +DONE + + if [ "$file_type" = "directory" ]; then + # delete the legacy directory + cat << DONE +rm -rf "\$destination_old" +DONE + fi ;; absent) - echo rm -f \"$destination\" + # only delete if it is a sym/hard link + if [ "$file_type" = "symlink" -o "$file_type" = "hardlink" ]; then + echo rm -f \"$destination\" + fi ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__link/parameter/default/state b/cdist/conf/type/__link/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__link/parameter/default/state @@ -0,0 +1 @@ +present From 067614db1f15c5efcb330c0a417fab915595f724 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 18 Sep 2013 11:14:18 +0200 Subject: [PATCH 263/548] make explorers executable Signed-off-by: Steven Armstrong --- cdist/conf/type/__directory/explorer/group | 0 cdist/conf/type/__directory/explorer/mode | 0 cdist/conf/type/__directory/explorer/owner | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 cdist/conf/type/__directory/explorer/group mode change 100644 => 100755 cdist/conf/type/__directory/explorer/mode mode change 100644 => 100755 cdist/conf/type/__directory/explorer/owner diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner old mode 100644 new mode 100755 From 58f19df3863ca2ca01eaa9fd051257889db5149f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Sep 2013 12:33:39 +0200 Subject: [PATCH 264/548] ++changes(2.3.4) Signed-off-by: Nico Schottelius --- docs/changelog | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 9e2971f9..03c464f0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,11 +4,15 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.3.4: + * Core: Add missing bits to support dry run (Steven Armstrong) + * Core: Make unit test remote copy more compatible with scp (Steven Armstrong) + + 2.3.3: 2013-09-09 * Core: Add support for default values of optional parameters (Steven Armstrong) * Type __start_on_boot: Bugfix for systemd (Steven Armstrong) - 2.3.2: 2013-09-05 * Build: Ensure tests don't change attributes of non-test files * Core: Fix typo in argument parser From 4bee421f9713569118ec22ac885703262871fdfa Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 18 Sep 2013 13:25:45 +0200 Subject: [PATCH 265/548] rewrite type to work analog to __file and __link Signed-off-by: Steven Armstrong --- cdist/conf/type/__directory/explorer/group | 39 ------ cdist/conf/type/__directory/explorer/mode | 39 ------ cdist/conf/type/__directory/explorer/owner | 39 ------ cdist/conf/type/__directory/explorer/stat | 26 ++++ cdist/conf/type/__directory/explorer/state | 30 ----- cdist/conf/type/__directory/explorer/type | 16 +++ cdist/conf/type/__directory/gencode-remote | 116 +++++++++++------- .../type/__directory/parameter/default/state | 1 + 8 files changed, 117 insertions(+), 189 deletions(-) delete mode 100755 cdist/conf/type/__directory/explorer/group delete mode 100755 cdist/conf/type/__directory/explorer/mode delete mode 100755 cdist/conf/type/__directory/explorer/owner create mode 100755 cdist/conf/type/__directory/explorer/stat delete mode 100755 cdist/conf/type/__directory/explorer/state create mode 100755 cdist/conf/type/__directory/explorer/type create mode 100644 cdist/conf/type/__directory/parameter/default/state diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group deleted file mode 100755 index e5be37da..00000000 --- a/cdist/conf/type/__directory/explorer/group +++ /dev/null @@ -1,39 +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 . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" -os=$("$__explorer/os") - -case "$os" in - "freebsd") - cmd="stat -f %Sg" - ;; - *) - cmd="stat -c %G" - ;; -esac - -if [ -e "$destination" ]; then - $cmd "$destination" -fi - diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode deleted file mode 100755 index f75b282b..00000000 --- a/cdist/conf/type/__directory/explorer/mode +++ /dev/null @@ -1,39 +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 . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" -os=$("$__explorer/os") - -case "$os" in - "freebsd") - cmd="stat -f %Op" - ;; - *) - cmd="stat -c %a" - ;; -esac - -if [ -e "$destination" ]; then - $cmd "$destination" -fi - diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner deleted file mode 100755 index cebd199b..00000000 --- a/cdist/conf/type/__directory/explorer/owner +++ /dev/null @@ -1,39 +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 . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" -os=$("$__explorer/os") - -case "$os" in - "freebsd") - cmd="stat -f %Su" - ;; - *) - cmd="stat -c %U" - ;; -esac - -if [ -e "$destination" ]; then - $cmd "$destination" -fi - diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat new file mode 100755 index 00000000..2bd5d1c9 --- /dev/null +++ b/cdist/conf/type/__directory/explorer/stat @@ -0,0 +1,26 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist armstrong.cc) + +destination="/$__object_id" + +# nothing to work with, nothing we could do +[ -e "$destination" ] || exit 0 + +os=$("$__explorer/os") +case "$os" in + "freebsd") + # 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 +" "$destination" + ;; + *) + stat --printf="type: %F +owner: %u %U +group: %g %G +mode: %a %A +" "$destination" + ;; +esac diff --git a/cdist/conf/type/__directory/explorer/state b/cdist/conf/type/__directory/explorer/state deleted file mode 100755 index 9bdd9024..00000000 --- a/cdist/conf/type/__directory/explorer/state +++ /dev/null @@ -1,30 +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 . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" - -if [ -e "$destination" ]; then - echo present -else - echo absent -fi diff --git a/cdist/conf/type/__directory/explorer/type b/cdist/conf/type/__directory/explorer/type new file mode 100755 index 00000000..6e6a2956 --- /dev/null +++ b/cdist/conf/type/__directory/explorer/type @@ -0,0 +1,16 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist armstrong.cc) + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + echo file +elif [ -d "$destination" ]; then + echo directory +else + echo unknown +fi diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index f46a5967..ebe07318 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -19,53 +20,84 @@ # destination="/$__object_id" +state_should="$(cat "$__object/parameter/state")" +type="$(cat "$__object/explorer/type")" +stat_file="$__object/explorer/stat" -state_is="$(cat "$__object/explorer/state")" -owner_is="$(cat "$__object/explorer/owner")" -group_is="$(cat "$__object/explorer/group")" -mode_is="$(cat "$__object/explorer/mode")" +# variable to keep track if we have to set directory attributes +set_attributes= -state_should="present" -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -mode="" -[ -f "$__object/parameter/mode" ] && mode="$(cat "$__object/parameter/mode")" -owner="" -[ -f "$__object/parameter/owner" ] && owner="$(cat "$__object/parameter/owner")" -group="" -[ -f "$__object/parameter/group" ] && group="$(cat "$__object/parameter/group")" mkdiropt="" -[ -f "$__object/parameter/parents" ] && mkdiropt="-p" +[ -f "$__object/parameter/parents" ] && mkdiropt="-p" + recursive="" -[ -f "$__object/parameter/recursive" ] && recursive="-R" +if [ -f "$__object/parameter/recursive" ]; then + recursive="-R" + # need to allways set attributes when recursive is given + # as we don't want to check all subfolders/files + set_attributes=1 +fi + +get_current_value() { + if [ -s "$stat_file" ]; then + _name="$1" + _value="$2" + case "$_value" in + [0-9]*) + _index=2 + ;; + *) + _index=3 + ;; + esac + awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" + unset _name _value _index + fi +} + +set_group() { + echo chgrp $recursive \"$1\" \"$destination\" +} + +set_owner() { + echo chown $recursive \"$1\" \"$destination\" +} + +set_mode() { + echo chmod $recursive \"$1\" \"$destination\" +} case "$state_should" in - present) - if [ "$state_is" != "present" ]; then - echo mkdir $mkdiropt \"$destination\" - fi + present) + if [ "$type" != "directory" ]; + # our destination is not a directory, remove whatever is there + # and then create our directory and set all attributes + set_attributes=1 + cat << DONE +rm -f "$destination" +mkdir "$mkdiropt" "$destination" +DONE + fi - # Mode settings - if [ "$mode" ] && [ "$mode_is" != "$mode" -o -n "$recursive" ]; then - echo chmod $recursive \"$mode\" \"$destination\" - fi - - # Group - if [ "$group" ] && [ "$group_is" != "$group" -o -n "$recursive" ]; then - echo chgrp $recursive \"$group\" \"$destination\" - fi - - # Owner - if [ "$owner" ] && [ "$owner_is" != "$owner" -o -n "$recursive" ]; then - echo chown $recursive \"$owner\" \"$destination\" - fi - ;; - absent) - if [ "$state_is" != "absent" ]; then - echo rm -rf \"$destination\" - fi - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + # 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 + if [ -f "$__object/parameter/$attribute" ]; then + value_should="$(cat "$__object/parameter/$attribute")" + value_is="$(get_current_value "$attribute" "$value_should")" + if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then + "set_$attribute" "$value_should" + fi + fi + done + ;; + absent) + if [ "$type" = "directory" ]; then + echo rm -rf \"$destination\" + fi + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/cdist/conf/type/__directory/parameter/default/state b/cdist/conf/type/__directory/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__directory/parameter/default/state @@ -0,0 +1 @@ +present From 97a8793fddd8b6de31f75f0d564d54055ee5882e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 24 Sep 2013 15:54:14 +0200 Subject: [PATCH 266/548] add __postfix* types Signed-off-by: Steven Armstrong --- cdist/conf/type/__postfix/man.text | 42 ++++++++++ cdist/conf/type/__postfix/manifest | 33 ++++++++ cdist/conf/type/__postfix/singleton | 0 .../conf/type/__postfix_master/explorer/entry | 39 +++++++++ .../conf/type/__postfix_master/gencode-remote | 76 +++++++++++++++++ cdist/conf/type/__postfix_master/man.text | 73 +++++++++++++++++ cdist/conf/type/__postfix_master/manifest | 81 +++++++++++++++++++ .../type/__postfix_master/parameter/boolean | 1 + .../__postfix_master/parameter/default/chroot | 1 + .../parameter/default/maxproc | 1 + .../parameter/default/private | 1 + .../__postfix_master/parameter/default/state | 1 + .../__postfix_master/parameter/default/unpriv | 1 + .../__postfix_master/parameter/default/wakeup | 1 + .../type/__postfix_master/parameter/optional | 9 +++ .../type/__postfix_master/parameter/required | 2 + .../type/__postfix_postconf/explorer/value | 37 +++++++++ .../type/__postfix_postconf/gencode-remote | 60 ++++++++++++++ cdist/conf/type/__postfix_postconf/man.text | 51 ++++++++++++ .../parameter/default/state | 1 + .../__postfix_postconf/parameter/optional | 2 + .../__postfix_postconf/parameter/required | 1 + .../type/__postfix_postmap/gencode-remote | 21 +++++ cdist/conf/type/__postfix_postmap/man.text | 42 ++++++++++ .../conf/type/__postfix_reload/gencode-remote | 33 ++++++++ cdist/conf/type/__postfix_reload/man.text | 42 ++++++++++ cdist/conf/type/__postfix_reload/singleton | 0 27 files changed, 652 insertions(+) create mode 100644 cdist/conf/type/__postfix/man.text create mode 100755 cdist/conf/type/__postfix/manifest create mode 100644 cdist/conf/type/__postfix/singleton create mode 100755 cdist/conf/type/__postfix_master/explorer/entry create mode 100755 cdist/conf/type/__postfix_master/gencode-remote create mode 100644 cdist/conf/type/__postfix_master/man.text create mode 100755 cdist/conf/type/__postfix_master/manifest create mode 100644 cdist/conf/type/__postfix_master/parameter/boolean create mode 100644 cdist/conf/type/__postfix_master/parameter/default/chroot create mode 100644 cdist/conf/type/__postfix_master/parameter/default/maxproc create mode 100644 cdist/conf/type/__postfix_master/parameter/default/private create mode 100644 cdist/conf/type/__postfix_master/parameter/default/state create mode 100644 cdist/conf/type/__postfix_master/parameter/default/unpriv create mode 100644 cdist/conf/type/__postfix_master/parameter/default/wakeup create mode 100644 cdist/conf/type/__postfix_master/parameter/optional create mode 100644 cdist/conf/type/__postfix_master/parameter/required create mode 100755 cdist/conf/type/__postfix_postconf/explorer/value create mode 100755 cdist/conf/type/__postfix_postconf/gencode-remote create mode 100644 cdist/conf/type/__postfix_postconf/man.text create mode 100644 cdist/conf/type/__postfix_postconf/parameter/default/state create mode 100644 cdist/conf/type/__postfix_postconf/parameter/optional create mode 100644 cdist/conf/type/__postfix_postconf/parameter/required create mode 100755 cdist/conf/type/__postfix_postmap/gencode-remote create mode 100644 cdist/conf/type/__postfix_postmap/man.text create mode 100755 cdist/conf/type/__postfix_reload/gencode-remote create mode 100644 cdist/conf/type/__postfix_reload/man.text create mode 100644 cdist/conf/type/__postfix_reload/singleton diff --git a/cdist/conf/type/__postfix/man.text b/cdist/conf/type/__postfix/man.text new file mode 100644 index 00000000..1a91723a --- /dev/null +++ b/cdist/conf/type/__postfix/man.text @@ -0,0 +1,42 @@ +cdist-type__postfix(7) +====================== +Steven Armstrong + + +NAME +---- +cdist-type__postfix - install postfix + + +DESCRIPTION +----------- +This space intentionally left blank. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postfix +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +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). diff --git a/cdist/conf/type/__postfix/manifest b/cdist/conf/type/__postfix/manifest new file mode 100755 index 00000000..2dc70ce2 --- /dev/null +++ b/cdist/conf/type/__postfix/manifest @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + ubuntu|debian|archlinux) + __package postfix --state present + ;; + *) + 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/__postfix/singleton b/cdist/conf/type/__postfix/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__postfix_master/explorer/entry b/cdist/conf/type/__postfix_master/explorer/entry new file mode 100755 index 00000000..9d6b1514 --- /dev/null +++ b/cdist/conf/type/__postfix_master/explorer/entry @@ -0,0 +1,39 @@ +#!/bin/sh +# +# 2011 - 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 . +# + +config="/etc/postfix/master.cf" + +# no master.cf, nothing we could do +[ -f "$config" ] || exit 0 + +# NOTE: keep variables in sync in manifest,explorer,gencode-* +prefix="#cdist:$__object_name" +suffix="#/cdist:$__object_name" +awk -v prefix="$prefix" -v suffix="$suffix" '{ + if (index($0,prefix)) { + triggered=1 + } + if (triggered) { + if (index($0,suffix)) { + triggered=0 + } + print + } +}' "$config" diff --git a/cdist/conf/type/__postfix_master/gencode-remote b/cdist/conf/type/__postfix_master/gencode-remote new file mode 100755 index 00000000..a4d6462b --- /dev/null +++ b/cdist/conf/type/__postfix_master/gencode-remote @@ -0,0 +1,76 @@ +#!/bin/sh +# +# 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 . +# + +config="/etc/postfix/master.cf" +entry="$__object/files/entry" +state_should="$(cat "$__object/parameter/state")" +if [ ! -s "$__object/explorer/entry" ]; then + state_is='absent' +else + state_is=$(diff -q "$entry" "$__object/explorer/entry" >/dev/null \ + && echo present \ + || echo changed + ) +fi + +if [ "$state_should" = "$state_is" ]; then + # Nothing to do, move along + exit 0 +fi + + +remove_entry() { + # NOTE: keep variables in sync in manifest/explorer/gencode-* + prefix="#cdist:$__object_name" + suffix="#/cdist:$__object_name" + cat << DONE +tmpfile=\$(mktemp ${config}.cdist.XXXXXXXXXX) +awk -v prefix="$prefix" -v suffix="$suffix" ' +{ + if (index(\$0,prefix)) { + triggered=1 + } + if (triggered) { + if (index(\$0,suffix)) { + triggered=0 + } + } else { + print + } +}' "$config" > "\$tmpfile" +mv -f "\$tmpfile" "$config" +DONE +} + +case "$state_should" in + present) + if [ "$state_is" = "changed" ]; then + remove_entry + fi + cat << DONE +cat >> "$config" << ${__type##*/}_DONE +$(cat "$entry") +${__type##*/}_DONE +DONE + ;; + absent) + remove_entry + ;; +esac diff --git a/cdist/conf/type/__postfix_master/man.text b/cdist/conf/type/__postfix_master/man.text new file mode 100644 index 00000000..0ec78752 --- /dev/null +++ b/cdist/conf/type/__postfix_master/man.text @@ -0,0 +1,73 @@ +cdist-type__postfix_master(7) +============================= +Steven Armstrong + + +NAME +---- +cdist-type__postfix_master - configure postfix master.cf + + +DESCRIPTION +----------- +See master(5) for more information. + + +REQUIRED PARAMETERS +------------------- +type:: + See master(5) +command:: + See master(5) + + +BOOLEAN PARAMETERS +------------------ +noreload:: + don't reload postfix after changes + + +OPTIONAL PARAMETERS +------------------- +state:: + present or absent, defaults to present +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:: + a textual comment to add with the master.cf entry + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postfix_master smtp --type inet --command smtpd + +__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) +- master(5) + + +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). + diff --git a/cdist/conf/type/__postfix_master/manifest b/cdist/conf/type/__postfix_master/manifest new file mode 100755 index 00000000..1642e91b --- /dev/null +++ b/cdist/conf/type/__postfix_master/manifest @@ -0,0 +1,81 @@ +#!/bin/sh +# +# 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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + 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 + + +# 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" +suffix="#/cdist:$__object_name" + +# Generate entry for inclusion in master.cf +mkdir "$__object/files" +entry="$__object/files/entry" +( + echo "$prefix" + if [ -f "$__object/parameter/comment" ]; then + 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 + command="$(cat "$__object/parameter/command")" + # ensure we have a trailing newline + echo "$command" + options="$(cat "$__object/parameter/option" 2>/dev/null || true)" + for option in $options; do + echo " -o $option" + done + echo "$suffix" +) > "$entry" + +# Reload postfix after changes +if [ ! -f "$__object/parameter/noreload" ]; then + state_should="$(cat "$__object/parameter/state")" + if [ ! -s "$__object/explorer/entry" ]; then + state_is='absent' + else + state_is=$(diff -q "$entry" "$__object/explorer/entry" >/dev/null \ + && echo present \ + || echo changed + ) + fi + if [ "$state_is" != "$state_should" ]; then + require="$__object_name" __postfix_reload + fi +fi diff --git a/cdist/conf/type/__postfix_master/parameter/boolean b/cdist/conf/type/__postfix_master/parameter/boolean new file mode 100644 index 00000000..862edc87 --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/boolean @@ -0,0 +1 @@ +noreload diff --git a/cdist/conf/type/__postfix_master/parameter/default/chroot b/cdist/conf/type/__postfix_master/parameter/default/chroot new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/chroot @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/default/maxproc b/cdist/conf/type/__postfix_master/parameter/default/maxproc new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/maxproc @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/default/private b/cdist/conf/type/__postfix_master/parameter/default/private new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/private @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/default/state b/cdist/conf/type/__postfix_master/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__postfix_master/parameter/default/unpriv b/cdist/conf/type/__postfix_master/parameter/default/unpriv new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/unpriv @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/default/wakeup b/cdist/conf/type/__postfix_master/parameter/default/wakeup new file mode 100644 index 00000000..39cdd0de --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/default/wakeup @@ -0,0 +1 @@ +- diff --git a/cdist/conf/type/__postfix_master/parameter/optional b/cdist/conf/type/__postfix_master/parameter/optional new file mode 100644 index 00000000..792b42c5 --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/optional @@ -0,0 +1,9 @@ +service +private +unpriv +chroot +wakeup +maxproc +option +comment +state diff --git a/cdist/conf/type/__postfix_master/parameter/required b/cdist/conf/type/__postfix_master/parameter/required new file mode 100644 index 00000000..24c14146 --- /dev/null +++ b/cdist/conf/type/__postfix_master/parameter/required @@ -0,0 +1,2 @@ +type +command diff --git a/cdist/conf/type/__postfix_postconf/explorer/value b/cdist/conf/type/__postfix_postconf/explorer/value new file mode 100755 index 00000000..edf48b48 --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/explorer/value @@ -0,0 +1,37 @@ +#!/bin/sh +# +# 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 . +# + + +os=$("$__explorer/os") + +case "$os" in + 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="$(cat "$__object/parameter/key" 2>/dev/null || echo "$__object_id")" + +postconf -h "$key" diff --git a/cdist/conf/type/__postfix_postconf/gencode-remote b/cdist/conf/type/__postfix_postconf/gencode-remote new file mode 100755 index 00000000..60143590 --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/gencode-remote @@ -0,0 +1,60 @@ +#!/bin/sh +# +# 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 . +# + +os=$(cat "$__global/explorer/os") + +case "$os" in + 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 + +state_should="$(cat "$__object/parameter/state")" +if [ ! -s "$__object/explorer/value" ]; then + state_is='absent' +else + state_is=$(diff -q "$__object/parameter/value" "$__object/explorer/value" >/dev/null \ + && echo present \ + || echo changed + ) +fi + +if [ "$state_should" = "$state_is" ]; then + # Nothing to do, move along + exit 0 +fi + +key="$(cat "$__object/parameter/key" 2>/dev/null || echo "$__object_id")" +value="$(cat "$__object/parameter/value")" + +case "$state_should" in + absent) + # revert parameter to its default value + echo "postconf -# $key" + ;; + present) + echo "postconf -e '$key=$value'" + ;; +esac diff --git a/cdist/conf/type/__postfix_postconf/man.text b/cdist/conf/type/__postfix_postconf/man.text new file mode 100644 index 00000000..727637b1 --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/man.text @@ -0,0 +1,51 @@ +cdist-type__postfix_postconf(7) +=============================== +Steven Armstrong + + +NAME +---- +cdist-type__postfix_postconf - configure postfix main.cf + + +DESCRIPTION +----------- +See postconf(5) for possible keys and values. + +Note that this type directly runs the postconf executable. +It does not make changes to /etc/postfix/main.cf itself. + + +REQUIRED PARAMETERS +------------------- +value:: + the value for the postfix parameter + + +OPTIONAL PARAMETERS +------------------- +key:: + the name of the parameter. Defaults to __object_id + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__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) +- postconf(5) + + +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). diff --git a/cdist/conf/type/__postfix_postconf/parameter/default/state b/cdist/conf/type/__postfix_postconf/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__postfix_postconf/parameter/optional b/cdist/conf/type/__postfix_postconf/parameter/optional new file mode 100644 index 00000000..6ada755a --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/parameter/optional @@ -0,0 +1,2 @@ +key +state diff --git a/cdist/conf/type/__postfix_postconf/parameter/required b/cdist/conf/type/__postfix_postconf/parameter/required new file mode 100644 index 00000000..6d4e1507 --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/parameter/required @@ -0,0 +1 @@ +value diff --git a/cdist/conf/type/__postfix_postmap/gencode-remote b/cdist/conf/type/__postfix_postmap/gencode-remote new file mode 100755 index 00000000..1b370001 --- /dev/null +++ b/cdist/conf/type/__postfix_postmap/gencode-remote @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 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 . +# + +echo "postmap /$__object_id" diff --git a/cdist/conf/type/__postfix_postmap/man.text b/cdist/conf/type/__postfix_postmap/man.text new file mode 100644 index 00000000..37060d04 --- /dev/null +++ b/cdist/conf/type/__postfix_postmap/man.text @@ -0,0 +1,42 @@ +cdist-type__postfix_postmap(7) +============================== +Steven Armstrong + + +NAME +---- +cdist-type__postfix_postmap - run postmap on the given file + + +DESCRIPTION +----------- +This space intentionally left blank. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postfix_postmap /etc/postfix/generic +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +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). diff --git a/cdist/conf/type/__postfix_reload/gencode-remote b/cdist/conf/type/__postfix_reload/gencode-remote new file mode 100755 index 00000000..5822f1e3 --- /dev/null +++ b/cdist/conf/type/__postfix_reload/gencode-remote @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + ubuntu|debian|archlinux) + echo "postfix reload" + ;; + *) + 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/__postfix_reload/man.text b/cdist/conf/type/__postfix_reload/man.text new file mode 100644 index 00000000..c63356b5 --- /dev/null +++ b/cdist/conf/type/__postfix_reload/man.text @@ -0,0 +1,42 @@ +cdist-type__postfix_reload(7) +============================= +Steven Armstrong + + +NAME +---- +cdist-type__postfix_reload - tell postfix to reload its configuration + + +DESCRIPTION +----------- +This space intentionally left blank. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__postfix_reload +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +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). diff --git a/cdist/conf/type/__postfix_reload/singleton b/cdist/conf/type/__postfix_reload/singleton new file mode 100644 index 00000000..e69de29b From 2b6688910563d9e4122afe591023562028de4e64 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 26 Sep 2013 16:26:01 +0200 Subject: [PATCH 267/548] __line: support line/regexp containing / Signed-off-by: Nico Schottelius --- cdist/conf/type/__line/gencode-remote | 4 ++++ docs/changelog | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index 8ac273e2..d381fb20 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -49,6 +49,10 @@ case "$state_should" in [ "$line" ] && regex="^$line\$" + # Replace all / with \/ + regex=$(echo "$regex" | sed 's;/;\\/;g') + echo $regex >&2 + cat << eof tmp=\$(mktemp) sed '/$regex/d' "$file" > \$tmp && cat "\$tmp" > "$file" && rm -f "\$tmp" diff --git a/docs/changelog b/docs/changelog index 03c464f0..d6baad60 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,12 @@ Changelog 2.3.4: * Core: Add missing bits to support dry run (Steven Armstrong) * Core: Make unit test remote copy more compatible with scp (Steven Armstrong) + * New Type: __postfix (Steven Armstrong) + * New Type: __postfix_master (Steven Armstrong) + * 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 / 2.3.3: 2013-09-09 From 8a7639c19182f8e2d88a2a5029f30a54e07fc6a8 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 27 Sep 2013 21:51:36 +0200 Subject: [PATCH 268/548] preserve ownership and permissions of existing files Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_keys/gencode-remote | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__ssh_authorized_keys/gencode-remote b/cdist/conf/type/__ssh_authorized_keys/gencode-remote index cc86cc19..b886c96f 100755 --- a/cdist/conf/type/__ssh_authorized_keys/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_keys/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012-2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -24,7 +24,7 @@ if [ -f "$__object/parameter/file" ]; then else home="$(cut -d':' -f 6 "$__object/explorer/passwd")" file="$home/.ssh/authorized_keys" -fi +fi entry="$__object/files/entry" if [ ! -s "$__object/explorer/entry" ]; then @@ -48,6 +48,8 @@ remove_entry() { suffix="#/cdist:$__object_name" cat << DONE tmpfile=\$(mktemp) +# preserve ownership and permissions by copying existing file over tmpfile +cp -p "$file" "\$tmpfile" awk -v prefix="$prefix" -v suffix="$suffix" ' { if (index(\$0,prefix)) { From c769d0b681c400041d3cb1f9299e46f0840b1a91 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 27 Sep 2013 22:05:02 +0200 Subject: [PATCH 269/548] preserve ownership and permissions of existing file Signed-off-by: Steven Armstrong --- cdist/conf/type/__postfix_master/gencode-remote | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdist/conf/type/__postfix_master/gencode-remote b/cdist/conf/type/__postfix_master/gencode-remote index a4d6462b..51edc668 100755 --- a/cdist/conf/type/__postfix_master/gencode-remote +++ b/cdist/conf/type/__postfix_master/gencode-remote @@ -42,6 +42,8 @@ remove_entry() { suffix="#/cdist:$__object_name" cat << DONE tmpfile=\$(mktemp ${config}.cdist.XXXXXXXXXX) +# preserve ownership and permissions of existing file +cp -p "$config" "\$tmpfile" awk -v prefix="$prefix" -v suffix="$suffix" ' { if (index(\$0,prefix)) { From d166224e688bdd8841d1d023ed3a5986eecb2691 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 27 Sep 2013 22:06:08 +0200 Subject: [PATCH 270/548] create tmpfile on same volume as existing file Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_keys/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__ssh_authorized_keys/gencode-remote b/cdist/conf/type/__ssh_authorized_keys/gencode-remote index b886c96f..7fcb59c6 100755 --- a/cdist/conf/type/__ssh_authorized_keys/gencode-remote +++ b/cdist/conf/type/__ssh_authorized_keys/gencode-remote @@ -47,7 +47,7 @@ remove_entry() { prefix="#cdist:$__object_name" suffix="#/cdist:$__object_name" cat << DONE -tmpfile=\$(mktemp) +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) # preserve ownership and permissions by copying existing file over tmpfile cp -p "$file" "\$tmpfile" awk -v prefix="$prefix" -v suffix="$suffix" ' From a501444310177ddb96dcfee9cd4ea5ef3a7358fa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 27 Sep 2013 23:26:39 +0200 Subject: [PATCH 271/548] ++change(2.3.4) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index d6baad60..ba052a90 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,7 @@ Changelog * New Type: __postfix_postmap (Steven Armstrong) * New Type: __postfix_reload (Steven Armstrong) * Type __line: Ensure regex does not contain / + * Type __ssh_authorized_keys: Bugfix: Preserve ownership (Steven Armstrong) 2.3.3: 2013-09-09 From 9bd2e9d2e611ba943135a8d772a32d3673bde24b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 3 Oct 2013 01:37:53 +0200 Subject: [PATCH 272/548] --ws Signed-off-by: Nico Schottelius --- docs/changelog | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index ba052a90..35e7dbc0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.3.4: +2.3.4: 2013-10-03 * Core: Add missing bits to support dry run (Steven Armstrong) * Core: Make unit test remote copy more compatible with scp (Steven Armstrong) * New Type: __postfix (Steven Armstrong) @@ -15,7 +15,6 @@ Changelog * Type __line: Ensure regex does not contain / * Type __ssh_authorized_keys: Bugfix: Preserve ownership (Steven Armstrong) - 2.3.3: 2013-09-09 * Core: Add support for default values of optional parameters (Steven Armstrong) * Type __start_on_boot: Bugfix for systemd (Steven Armstrong) From 48a21de3ac7a817fb12365f15d036f2bd703c63e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 3 Oct 2013 14:10:03 +0900 Subject: [PATCH 273/548] let the ossawards pre begin Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-10-03.ossawards/infos | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/dev/logs/2013-10-03.ossawards/infos diff --git a/docs/dev/logs/2013-10-03.ossawards/infos b/docs/dev/logs/2013-10-03.ossawards/infos new file mode 100644 index 00000000..a18c686f --- /dev/null +++ b/docs/dev/logs/2013-10-03.ossawards/infos @@ -0,0 +1,13 @@ +Required for the ossawards until 2013-10-06: + - all source code + - licenses GPLv3 + - installation instructions, + - On Linux do the following: + - pip install + - + - necessary documents and + - a demo video onto our web hard. + - installation + - cdist via cdist + - presentation + - build from existing ones (?) From 5cc894e1e9b32e4d1c869fa92ffd7ac1b4043abe Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 3 Oct 2013 09:55:14 +0200 Subject: [PATCH 274/548] only use a single space to distinguish between the actual __target_host and the same used as part of the path; fixes #206 Signed-off-by: Steven Armstrong --- cdist/test/fixtures/remote/copy | 6 +----- other/examples/remote/local/copy | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cdist/test/fixtures/remote/copy b/cdist/test/fixtures/remote/copy index 57369b53..a4627716 100755 --- a/cdist/test/fixtures/remote/copy +++ b/cdist/test/fixtures/remote/copy @@ -18,10 +18,6 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# This is based on other/examples/remote/local/, but uses --dereference for the -# test cases -# -code="$(echo "$@" | sed "s|\([[:space:]]+\)$__target_host:|\1|g")" +code="$(echo "$@" | sed "s|\([[:space:]]\)$__target_host:|\1|g")" cp --dereference $code diff --git a/other/examples/remote/local/copy b/other/examples/remote/local/copy index 0ddc44c8..0cec3643 100755 --- a/other/examples/remote/local/copy +++ b/other/examples/remote/local/copy @@ -20,5 +20,5 @@ # # -code="$(echo "$@" | sed "s|\([[:space:]]+\)$__target_host:|\1|g")" +code="$(echo "$@" | sed "s|\([[:space:]]\)$__target_host:|\1|g")" cp --dereference $code From 55d83acaae9732c27cfdf7fbd9db248f595b971d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 5 Oct 2013 16:48:55 +0900 Subject: [PATCH 275/548] clarify mirrors Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-quickstart.text | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-quickstart.text b/docs/man/man7/cdist-quickstart.text index b718da64..8b754650 100644 --- a/docs/man/man7/cdist-quickstart.text +++ b/docs/man/man7/cdist-quickstart.text @@ -72,7 +72,9 @@ 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 +# Get cdist +# Mirrors can be found on +# http://www.nico.schottelius.org/software/cdist/install/#index2h4 git clone git://git.schottelius.org/cdist # Create manifest (maps configuration to host(s) From 1ec8be79efcef4a20f3341bde9fb8015b47253d9 Mon Sep 17 00:00:00 2001 From: Alex Greif Date: Sat, 5 Oct 2013 11:24:12 +0200 Subject: [PATCH 276/548] adjusted parameters for __package __file for current HEADa --- docs/man/man7/cdist-manifest.text | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index ade2eef1..cc6fad42 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -25,8 +25,8 @@ 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 = removed -__package apache2 --state removed +# Create object of type __package with the parameter state = absent +__package apache2 --state absent # Same with the __directory type __directory /tmp/cdist --state present @@ -135,12 +135,12 @@ 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 --type file +__file /etc/cdist-configured case "$__target_host" in my.server.name) - __file /root/bin/ --type directory - __file /etc/issue.net --type file --source "$__manifest/issue.net + __directory /root/bin/ + __file /etc/issue.net --source "$__manifest/issue.net ;; esac -------------------------------------------------------------------------------- @@ -148,7 +148,7 @@ esac The manifest of the type "nologin" may look like this: -------------------------------------------------------------------------------- -__file /etc/nologin --type file --source "$__type/files/default.nologin" +__file /etc/nologin --source "$__type/files/default.nologin" -------------------------------------------------------------------------------- From 2583cb213ee237558d401e60501d120ee3da6853 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 6 Oct 2013 08:45:23 +0900 Subject: [PATCH 277/548] ++changes(2.3.5) Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 35e7dbc0..d9be8b62 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.3.5: + * Documentation: Updated manpages of __package and __file (Alex Greif) + 2.3.4: 2013-10-03 * Core: Add missing bits to support dry run (Steven Armstrong) * Core: Make unit test remote copy more compatible with scp (Steven Armstrong) From 9b2d63080736448507dc14c25a6a6cb65c2e8629 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 9 Oct 2013 21:47:37 +0900 Subject: [PATCH 278/548] do not install recommends by default Signed-off-by: Nico Schottelius --- cdist/conf/type/__package_apt/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index a80d707e..2ba8320b 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -42,7 +42,7 @@ case "$state_is" in ;; esac -aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes" +aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes --no-install-recommends" [ "$state_is" = "$state_should" ] && exit 0 From 49c686319ed9fdb4e6eddcc489a4a59aee8a2b52 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 10 Oct 2013 09:51:26 +0900 Subject: [PATCH 279/548] add more exapmles to cdist-manifest Signed-off-by: Nico Schottelius --- cdist/conf/type/__package_apt/gencode-remote | 2 +- docs/changelog | 1 + docs/man/man7/cdist-manifest.text | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index 2ba8320b..7aba76d5 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -42,7 +42,7 @@ case "$state_is" in ;; esac -aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes --no-install-recommends" +aptget="DEBIAN_FRONTEND=noninteractive apt-get --quiet --yes --no-install-recommends -o DPkg::Options::=\"--force-confold\"" [ "$state_is" = "$state_should" ] && exit 0 diff --git a/docs/changelog b/docs/changelog index d9be8b62..bead7001 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 2.3.5: * Documentation: Updated manpages of __package and __file (Alex Greif) + * Type __package_apt: Do not install recommends by default 2.3.4: 2013-10-03 * Core: Add missing bits to support dry run (Steven Armstrong) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index cc6fad42..92d0b897 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -151,6 +151,17 @@ The manifest of the type "nologin" may look like this: __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 +-------------------------------------------------------------------------------- + + SEE ALSO -------- From 115f5915fdf5e23584891e03e31c71c1b5d299af Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 10 Oct 2013 09:52:18 +0900 Subject: [PATCH 280/548] ++changes(2.3.5) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index bead7001..2d78d228 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 2.3.5: * Documentation: Updated manpages of __package and __file (Alex Greif) + * Documentation: Add more exapmles to cdist-manifest (Dan Levin) * Type __package_apt: Do not install recommends by default 2.3.4: 2013-10-03 From 3c49e93bfed797084a398780fa47ebe44545626a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 10 Oct 2013 09:53:24 +0900 Subject: [PATCH 281/548] +releasedate Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 2d78d228..8af1009f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.3.5: +2.3.5: 2013-10-10 * Documentation: Updated manpages of __package and __file (Alex Greif) * Documentation: Add more exapmles to cdist-manifest (Dan Levin) * Type __package_apt: Do not install recommends by default From 68ac5af63b779dd8a6c84ca69b4bd12d9fa649ae Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 10 Oct 2013 09:56:08 +0900 Subject: [PATCH 282/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 8af1009f..217405c3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius 2.3.5: 2013-10-10 + * Core: Unit test fix for remote_copy (Steven Armstrong) * Documentation: Updated manpages of __package and __file (Alex Greif) * Documentation: Add more exapmles to cdist-manifest (Dan Levin) * Type __package_apt: Do not install recommends by default From e0b009308ab8385af4d31a16b5e788d64a560dfd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 14 Oct 2013 21:27:07 +0900 Subject: [PATCH 283/548] initial template for __locale Signed-off-by: Nico Schottelius --- cdist/conf/type/__locale/files/locale.gen | 3 ++ cdist/conf/type/__locale/gencode-remote | 37 ++++++++++++++ cdist/conf/type/__locale/man.text | 50 +++++++++++++++++++ cdist/conf/type/__locale/manifest | 8 +++ .../type/__locale/parameter/default/state | 1 + cdist/conf/type/__locale/parameter/optional | 1 + .../type/__locale/parameter/required_multiple | 1 + cdist/conf/type/__locale/singleton | 0 8 files changed, 101 insertions(+) create mode 100644 cdist/conf/type/__locale/files/locale.gen create mode 100644 cdist/conf/type/__locale/gencode-remote create mode 100644 cdist/conf/type/__locale/man.text create mode 100644 cdist/conf/type/__locale/manifest create mode 100644 cdist/conf/type/__locale/parameter/default/state create mode 100644 cdist/conf/type/__locale/parameter/optional create mode 100644 cdist/conf/type/__locale/parameter/required_multiple create mode 100644 cdist/conf/type/__locale/singleton diff --git a/cdist/conf/type/__locale/files/locale.gen b/cdist/conf/type/__locale/files/locale.gen new file mode 100644 index 00000000..cf8e8651 --- /dev/null +++ b/cdist/conf/type/__locale/files/locale.gen @@ -0,0 +1,3 @@ +de_CH.UTF-8 UTF-8 +de_DE.UTF-8 UTF-8 +en_US.UTF-8 UTF-8 diff --git a/cdist/conf/type/__locale/gencode-remote b/cdist/conf/type/__locale/gencode-remote new file mode 100644 index 00000000..aa03b46c --- /dev/null +++ b/cdist/conf/type/__locale/gencode-remote @@ -0,0 +1,37 @@ +cat << eof + +archive="/usr/lib/locale/locale-archive" + +regen=no + +if [ -f "$archive" ]; then + config_time=\$(stat --format "%Z" /etc/locale.gen) + archive_time=\$(stat --format "%Z" \"\$archive\") + + if [ "$config_time" -gt "$archive_time" ]; then + regen=yes + fi +else + regen=yes +fi + +if [ "\$regen" = yes ]; then + locale-gen +fi + +eof + + +## probably not needed, it seems to be /usr/lib/locale/locale-archive +## everwhere! + +# tmp=\$(mktemp /tmp/cdist.XXXXXXXX) +# find /usr/lib/locale -mindepth 1 > \$tmp +# while read archive; do +# archive_time=\$(stat --format "%Z" "\$archive\") +# +# if [ "\$config_time" -gt "\$archive_time" ]; then +# regen=yes +# break +# fi +# done < "$\tmp" diff --git a/cdist/conf/type/__locale/man.text b/cdist/conf/type/__locale/man.text new file mode 100644 index 00000000..9ed4a6d1 --- /dev/null +++ b/cdist/conf/type/__locale/man.text @@ -0,0 +1,50 @@ +cdist-type__locale(7) +===================== +Nico Schottelius + + +NAME +---- +cdist-type__locale - Configure locales + + +DESCRIPTION +----------- +This cdist type allows you to setup the locales. + + +REQUIRED MULTIPLE PARAMETERS +---------------------------- +name:: + Specify the locale to be present + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent' + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Configure locales en_US and de_CH, both as UTF8 +__locale --name "en_US.UTF-8 UTF-8" \ + --name "de_CH.UTF-8 UTF-8" \ + de_DE.UTF-8 UTF-8 + + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- locale(1) +- 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/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest new file mode 100644 index 00000000..dd3f0f55 --- /dev/null +++ b/cdist/conf/type/__locale/manifest @@ -0,0 +1,8 @@ +locales=$(cat "$__object/parameter/name") +state=$(cat "$__object/parameter/state") + +__package locales --state $state + +__file /etc/locale.gen \ + --mode 0644 \ + --source "$__object/parameter/name" diff --git a/cdist/conf/type/__locale/parameter/default/state b/cdist/conf/type/__locale/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__locale/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__locale/parameter/optional b/cdist/conf/type/__locale/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__locale/parameter/optional @@ -0,0 +1 @@ +state diff --git a/cdist/conf/type/__locale/parameter/required_multiple b/cdist/conf/type/__locale/parameter/required_multiple new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/cdist/conf/type/__locale/parameter/required_multiple @@ -0,0 +1 @@ +name diff --git a/cdist/conf/type/__locale/singleton b/cdist/conf/type/__locale/singleton new file mode 100644 index 00000000..e69de29b From 465749f377ff9d9e950f6ffdda8d159a976f1fdd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 14 Oct 2013 21:38:47 +0900 Subject: [PATCH 284/548] use localedef - locale-gen is a bad wrapper script Signed-off-by: Nico Schottelius --- cdist/conf/type/__locale/gencode-remote | 40 +++---------------- .../type/__locale/parameter/default/state | 1 - cdist/conf/type/__locale/parameter/optional | 1 - .../type/__locale/parameter/required_multiple | 1 - cdist/conf/type/__locale/singleton | 0 5 files changed, 5 insertions(+), 38 deletions(-) delete mode 100644 cdist/conf/type/__locale/parameter/default/state delete mode 100644 cdist/conf/type/__locale/parameter/optional delete mode 100644 cdist/conf/type/__locale/parameter/required_multiple delete mode 100644 cdist/conf/type/__locale/singleton diff --git a/cdist/conf/type/__locale/gencode-remote b/cdist/conf/type/__locale/gencode-remote index aa03b46c..ed8052a8 100644 --- a/cdist/conf/type/__locale/gencode-remote +++ b/cdist/conf/type/__locale/gencode-remote @@ -1,37 +1,7 @@ -cat << eof -archive="/usr/lib/locale/locale-archive" +locale=$__object_id +input=$(echo $locale | cut -d . -f 1) +charmap=$(echo $locale | cut -d . -f 2) +alias=/usr/share/locale/locale.alias -regen=no - -if [ -f "$archive" ]; then - config_time=\$(stat --format "%Z" /etc/locale.gen) - archive_time=\$(stat --format "%Z" \"\$archive\") - - if [ "$config_time" -gt "$archive_time" ]; then - regen=yes - fi -else - regen=yes -fi - -if [ "\$regen" = yes ]; then - locale-gen -fi - -eof - - -## probably not needed, it seems to be /usr/lib/locale/locale-archive -## everwhere! - -# tmp=\$(mktemp /tmp/cdist.XXXXXXXX) -# find /usr/lib/locale -mindepth 1 > \$tmp -# while read archive; do -# archive_time=\$(stat --format "%Z" "\$archive\") -# -# if [ "\$config_time" -gt "\$archive_time" ]; then -# regen=yes -# break -# fi -# done < "$\tmp" +echo localedef -A "$alias" -f "$charmap" -i "$input" diff --git a/cdist/conf/type/__locale/parameter/default/state b/cdist/conf/type/__locale/parameter/default/state deleted file mode 100644 index e7f6134f..00000000 --- a/cdist/conf/type/__locale/parameter/default/state +++ /dev/null @@ -1 +0,0 @@ -present diff --git a/cdist/conf/type/__locale/parameter/optional b/cdist/conf/type/__locale/parameter/optional deleted file mode 100644 index ff72b5c7..00000000 --- a/cdist/conf/type/__locale/parameter/optional +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/cdist/conf/type/__locale/parameter/required_multiple b/cdist/conf/type/__locale/parameter/required_multiple deleted file mode 100644 index f121bdbf..00000000 --- a/cdist/conf/type/__locale/parameter/required_multiple +++ /dev/null @@ -1 +0,0 @@ -name diff --git a/cdist/conf/type/__locale/singleton b/cdist/conf/type/__locale/singleton deleted file mode 100644 index e69de29b..00000000 From e7e610d8295095d45513121c31ac15efd1d7df41 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 14 Oct 2013 22:05:29 +0900 Subject: [PATCH 285/548] add state parameter Signed-off-by: Nico Schottelius --- cdist/conf/type/__locale/gencode-remote | 52 +++++++++++++++++-- cdist/conf/type/__locale/man.text | 19 +++---- cdist/conf/type/__locale/manifest | 36 ++++++++++--- .../type/__locale/parameter/default/state | 1 + cdist/conf/type/__locale/parameter/optional | 1 + 5 files changed, 88 insertions(+), 21 deletions(-) create mode 100644 cdist/conf/type/__locale/parameter/default/state create mode 100644 cdist/conf/type/__locale/parameter/optional diff --git a/cdist/conf/type/__locale/gencode-remote b/cdist/conf/type/__locale/gencode-remote index ed8052a8..538ce2cd 100644 --- a/cdist/conf/type/__locale/gencode-remote +++ b/cdist/conf/type/__locale/gencode-remote @@ -1,7 +1,51 @@ +#!/bin/sh +# +# 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 . +# +# +# Let localedef do the magic +# -locale=$__object_id -input=$(echo $locale | cut -d . -f 1) -charmap=$(echo $locale | cut -d . -f 2) +locale="$__object_id" + +# Hardcoded, create a pull request with +# branching on $os in case it is at another location alias=/usr/share/locale/locale.alias -echo localedef -A "$alias" -f "$charmap" -i "$input" +input=$(echo "$locale" | cut -d . -f 1) +charmap=$(echo "$locale" | cut -d . -f 2) + +# Adding locale? The name is de_CH.UTF-8 +# Removing locale? The name is de_CH.utf8. +# W-T-F! +locale_remove=$(echo "$locale" | sed 's/UTF-8/utf8/') + +state=$(cat "$__object/parameter/state") + +case "$state" in + present) + echo localedef -A "$alias" -f "$charmap" -i "$input" "$locale" + ;; + absent) + echo localedef --delete-from-archive "$locale_remove" + ;; + *) + echo "Unsupported state: $state" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__locale/man.text b/cdist/conf/type/__locale/man.text index 9ed4a6d1..f76c2059 100644 --- a/cdist/conf/type/__locale/man.text +++ b/cdist/conf/type/__locale/man.text @@ -10,15 +10,9 @@ cdist-type__locale - Configure locales DESCRIPTION ----------- -This cdist type allows you to setup the locales. +This cdist type allows you to setup locales. -REQUIRED MULTIPLE PARAMETERS ----------------------------- -name:: - Specify the locale to be present - - OPTIONAL PARAMETERS ------------------- state:: @@ -29,18 +23,21 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -# Configure locales en_US and de_CH, both as UTF8 -__locale --name "en_US.UTF-8 UTF-8" \ - --name "de_CH.UTF-8 UTF-8" \ - de_DE.UTF-8 UTF-8 +# Add locale de_CH.UTF-8 +__locale de_CH.UTF-8 +# 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) diff --git a/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest index dd3f0f55..5dd5fd8f 100644 --- a/cdist/conf/type/__locale/manifest +++ b/cdist/conf/type/__locale/manifest @@ -1,8 +1,32 @@ -locales=$(cat "$__object/parameter/name") -state=$(cat "$__object/parameter/state") +#!/bin/sh +# +# 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 . +# +# +# Install required packages +# -__package locales --state $state +os=$(cat "$__global/explorer/os") -__file /etc/locale.gen \ - --mode 0644 \ - --source "$__object/parameter/name" + +case "$os" in + debian) + # Debian needs a seperate package + __package locales --state present + ;; +esac diff --git a/cdist/conf/type/__locale/parameter/default/state b/cdist/conf/type/__locale/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__locale/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__locale/parameter/optional b/cdist/conf/type/__locale/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__locale/parameter/optional @@ -0,0 +1 @@ +state From 990581a4591bffc4ca758ec465a6b9b35fe25e8e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 14 Oct 2013 22:23:46 +0900 Subject: [PATCH 286/548] ++changes(2.3.6) Signed-off-by: Nico Schottelius --- docs/changelog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 217405c3..9128bab8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,10 +4,13 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.3.6: + * New Type: __locale + 2.3.5: 2013-10-10 * Core: Unit test fix for remote_copy (Steven Armstrong) * Documentation: Updated manpages of __package and __file (Alex Greif) - * Documentation: Add more exapmles to cdist-manifest (Dan Levin) + * Documentation: Add more examples to cdist-manifest (Dan Levin) * Type __package_apt: Do not install recommends by default 2.3.4: 2013-10-03 From 9db28fab97083364f2c9e96cd15a136136c9d6b1 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 15 Oct 2013 14:55:35 +0200 Subject: [PATCH 287/548] no late delete Signed-off-by: Steven Armstrong --- cdist/conf/type/__link/gencode-remote | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index 2e41b7d9..cbdfd30f 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -49,10 +49,9 @@ file_type="$(cat "$__object/explorer/type")" case "$state_should" in present) if [ "$file_type" = "directory" ]; then - # our destination is currently a directory, move it out of the way + # our destination is currently a directory, delete it cat << DONE -destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")" -mv "$destination" "\$destination_old" +rm -rf "$destination" DONE fi @@ -60,13 +59,6 @@ DONE cat << DONE ln ${lnopt} -f "$source" "$destination" DONE - - if [ "$file_type" = "directory" ]; then - # delete the legacy directory - cat << DONE -rm -rf "\$destination_old" -DONE - fi ;; absent) # only delete if it is a sym/hard link From 95513ab538396f2b5132d01a65905672ef8c34fb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 29 Oct 2013 12:23:07 +0100 Subject: [PATCH 288/548] __line: handle fixed strings correctly, posix gave us -F -x for this case Signed-off-by: Nico Schottelius --- cdist/conf/type/__line/explorer/state | 8 +++++--- cdist/conf/type/__line/gencode-remote | 27 +++++++++++++++++++-------- cdist/conf/type/__line/man.text | 11 ++++++----- docs/changelog | 1 + 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/cdist/conf/type/__line/explorer/state b/cdist/conf/type/__line/explorer/state index d240bf4d..d04d5d09 100755 --- a/cdist/conf/type/__line/explorer/state +++ b/cdist/conf/type/__line/explorer/state @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -24,16 +24,18 @@ file="/$__object_id" if [ -f "$__object/parameter/regex" ]; then regex=$(cat "$__object/parameter/regex") + greparg="" else if [ ! -f "$__object/parameter/line" ]; then echo "Parameter line and regex missing - cannot explore" >&2 exit 1 fi - regex="^$(cat "$__object/parameter/line")\$" + regex="$(cat "$__object/parameter/line")" + greparg="-F -x" fi # Allow missing file - thus 2>/dev/null -if grep -q "$regex" "$file" 2>/dev/null; then +if grep -q $greparg "$regex" "$file" 2>/dev/null; then echo present else echo absent diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index d381fb20..69f4d67a 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -38,7 +38,19 @@ case "$state_should" in exit 1 fi - echo "echo \"$line\" >> $file" + #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') + echo "echo '$line_sanitised' >> $file" ;; absent) @@ -47,17 +59,16 @@ case "$state_should" in exit 1 fi - [ "$line" ] && regex="^$line\$" - - # Replace all / with \/ - regex=$(echo "$regex" | sed 's;/;\\/;g') - echo $regex >&2 + greparg="" + if [ "$line" ]; then + regex="$line" + greparg="-F -x" + fi cat << eof tmp=\$(mktemp) -sed '/$regex/d' "$file" > \$tmp && cat "\$tmp" > "$file" && rm -f "\$tmp" +grep -v $greparg '$regex' '$file' > \$tmp && cat "\$tmp" > '$file' && rm -f "\$tmp" eof - #echo "echo q | ex -c \"/${line}/d|w|q\" \"${file}\"" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__line/man.text b/cdist/conf/type/__line/man.text index e1a5941c..f39ee929 100644 --- a/cdist/conf/type/__line/man.text +++ b/cdist/conf/type/__line/man.text @@ -32,11 +32,11 @@ regex:: given line, if the given regular expression does not match. In case of absent, ensure all lines matching the - regular expression are absent (cannot be combined with - the line parameter, if state is absent). + regular expression are absent. - If the regular expression contains / (slashes), they need - to be escaped with \ (backslash): / becomes \/. + The regular expression is interpreted by grep. + + Must not be combined with line, if state is absent. file:: If supplied, use this as the destination file. @@ -64,9 +64,10 @@ __line legacy_timezone --file /etc/rc.conf --regex 'TIMEZONE=.*' --state absent SEE ALSO -------- - cdist-type(7) +- grep(1) COPYING ------- -Copyright \(C) 2012 Nico Schottelius. Free use of this software is +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). diff --git a/docs/changelog b/docs/changelog index 9128bab8..eb756f07 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 2.3.6: * New Type: __locale + * Type __line: Ensure special characters are not interpreted 2.3.5: 2013-10-10 * Core: Unit test fix for remote_copy (Steven Armstrong) From 8c04316b65772f193ea2b62e345938196f83dba0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 29 Oct 2013 12:23:27 +0100 Subject: [PATCH 289/548] add logfile Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-10-29.__line | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 docs/dev/logs/2013-10-29.__line diff --git a/docs/dev/logs/2013-10-29.__line b/docs/dev/logs/2013-10-29.__line new file mode 100644 index 00000000..bc15de2c --- /dev/null +++ b/docs/dev/logs/2013-10-29.__line @@ -0,0 +1,6 @@ +- fix handling of fixed strings + - ensure special characters are not interpreted +[12:18] bento:~% cat /etc/bash.bashrc +cat: /etc/bash.bashrc: Permission denied +[12:19] bento:~% + From 48f492c55e7e5af80b13893a11926ffaf394a55f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 22 Nov 2013 07:15:29 +0100 Subject: [PATCH 290/548] add old speech from ossawards Signed-off-by: Nico Schottelius --- docs/speeches/2013-10-05_ossawards.odp | Bin 0 -> 210789 bytes .../ossawards-2013-1sys.png | Bin 0 -> 2320 bytes .../ossawards-2013-1sys1comp.png | Bin 0 -> 3309 bytes .../ossawards-2013-1sys4comp.png | Bin 0 -> 4062 bytes .../ossawards-2013-4comp.png | Bin 0 -> 2010 bytes .../ossawards-2013-4sys.png | Bin 0 -> 7538 bytes .../ossawards-2013-sys-cdist.png | Bin 0 -> 13919 bytes .../ossawards-2013-sys-chairman.png | Bin 0 -> 9756 bytes .../2013-10-05_ossawards/ossawards-2013.xoj | Bin 0 -> 29096 bytes 9 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/speeches/2013-10-05_ossawards.odp create mode 100644 docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys.png create mode 100644 docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys1comp.png create mode 100644 docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys4comp.png create mode 100644 docs/speeches/2013-10-05_ossawards/ossawards-2013-4comp.png create mode 100644 docs/speeches/2013-10-05_ossawards/ossawards-2013-4sys.png create mode 100644 docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-cdist.png create mode 100644 docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-chairman.png create mode 100644 docs/speeches/2013-10-05_ossawards/ossawards-2013.xoj diff --git a/docs/speeches/2013-10-05_ossawards.odp b/docs/speeches/2013-10-05_ossawards.odp new file mode 100644 index 0000000000000000000000000000000000000000..d0e4511ce7b495b9cbb70ba0ca3d72af851d9b9c GIT binary patch literal 210789 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

  • k75J&*CroYB*YTL285#`5W1Js?aioqQh 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 T0RVsl{sV$L-Zcg&@T>m=B+BL% literal 0 HcmV?d00001 diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys.png new file mode 100644 index 0000000000000000000000000000000000000000..d5b9586a9a77712e9854da631aa88c54cbed4f59 GIT binary patch literal 2320 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 literal 0 HcmV?d00001 diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys4comp.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-1sys4comp.png new file mode 100644 index 0000000000000000000000000000000000000000..5b37e09402ea3fc158cfae058d93ca5d52f390bf GIT binary patch literal 4062 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 literal 0 HcmV?d00001 diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-4comp.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-4comp.png new file mode 100644 index 0000000000000000000000000000000000000000..392eeeb8504517dd6f705f329efecb6d833c5079 GIT binary patch literal 2010 zcmbVNeK^y58{ZJxIkVK#L0&q~qnyZ&yhM+-$ZMgoX-GJZDU*nlye-s`_tzrwlEu7a z%ak!T$;*XeLeSwwqb_oUrn*F3y{UjSybc1>RoJ4~A*QKn*)UN^p<@1f*)XZR|pW zPM!qoSAlNbQUHwqEBv#!2?Cs_Q;8yu(j%s_e98BWaD<^!3#E|+X8ejfHK5BK#^OO%gj==on-9%T$;CWMoXt^JWX2msh(#zE^$ZJ^8G~@#BQxTQD`X z!}-p^n}#ADHDJ$Hjw8vpIjFCi_jPt~ACtHx&y|%OVPDM>96*dP+9^gZhkyF%-9X`? z?7HVoO>T;cihIQU=R0p&;tJkYqNoK01r7n^iV9r;BSu_l!^_q_hQ(l7K3W7YOwskez#twiCzz(EvIGaX0D(E7jc0n`je=K;sv=rrY z-(ZlY5j_1dXy+X}))S+0sJ5jc9O5Rz?-HrGp3H`g0&Nt%NLHj7pXuxC)9fK^$T2Fn zi!JX;9(+i*x1)&NT?bxaPZ`2JjWsY45!8&#%xoRi+1Xjh9Xm)`Pob#P1w|hHa4*Tf zE9pXx&{Z@WD|iq>clt5k<$&%pv=qCYLoQD;D0FG3G`@Z7&gJngc5aO@y+j@*IG{NE z!^n?TIgXBw*nj{kg+fWU4V-LUl1j5hHA1U6$#maiMpRVP$k4(wh~;zG`l6 zUL^VAU$M7*U~%y&AuNn6I3UsBkmBOwy|CCKF7)Mhm6HGn$ST!3ec6=M37w{<u+dZ%nDUi5amOvl>%is7 zwCeiq0^fkzrxMJrnu;g+MW#iC1HpgXU{!qm{&nj-%ANjpW)TU8)YsL$DvT!gb67PM z-RX`bq7EqfX1PXVu~0VNT7I42Owc2b&RV>?^jEG~R3$R8RI+>}2w|P_b?P!FB6A<+JAJUQf)L3l#he`?YlGfz3T7C!;s^qooY5Clp%vNk$t{ob`;O@&zmF)x zV6b)8BY#!$<%NeEz6hID4cNC&@0u2>tZQLuxf~BG>_PU!76cuK25IojzP8gZBEa0K zDeA()6|ZyW8mg=9#60TC<_l)@TuzSeiH3{}$hN_CVx!FSxm4pR2gU8n_ zF9^h+GCM9#cc-c_;#VlslD7W-{*mF~Y7E(39i3ztbnO~e66;r9UY@}g(u~8V=L$C( z9zC*MU!KR<=<)`O5i;rA*{P9H;0cR`>=Rx+k+6zx4PQrAm6nxp`F!I~D;(lpIDA89 zn(y4(rq^LmH9SVcXHHB^glt+-&8^9Fm#Whs0TsLm)VGi{j#9@le?@slR(@XuW$SvWcCm zr!6=`^)qrg`R)%*ZB0!H{(|jigFk1a^jPzfZph!N42UtH%6Uf;%D{OJIl?*;spoEt zqz9+0y$?Mv8=0^g=r=S;kErB1CNA); zFR&8EUqR(>9+-Vc*-@i#D30c`?B(f?yQMQbbag30W9T_>t{w6X)6v>|9*qPxNS=mW;Hra8^ zDE!{O*K=LJ=X(Blu2inu?Y=+f^M1cy>l31>p+tU`@hpNMa1+wiXaq^PW}?)$Yk5XMG`j^bp?{~vqYraluoBh zc@Tv8SVjJ>4tjJg$pfV`G}t=HbMBnEKc!d8MEJc|(^?km52J>e?mmAwJCKvp=n~F| zJGf{sT(L3`$HYX(S3;y4n=~ zMYvr<#^@LF>`|y-JrlwZdG;1L_9$iiYh_MtDb5QaG!$?tYUXm3awb}t^8yd+g%J7B zm;ZC=f8BEOTPSKz3@PUY_oo|EcZrCIrVe&if?vIoFEMY?tbFqD9Fyp|Kr(v0?)C3q z`1c0`M;sKDmCrmGuMTW(mKT?hNHf8C{@!S!*viCJJ{kWU!E(!aXIZzowKW}$pZWcJ zHWJ@LZ`#n)BXEDj^I+RnElHC0&+eM)&erC9r$tYqgt+U^bLr{nUvsoL&}j7BgnMc; zuh4rnij6ZyapNSH#=-(TUk|kV&y!L)s z&9;U=z@5)hefM)9Pv3RkLls|4`26{E)F&6Kr%gIJn*SsxCo>D%P%?=<;bSenz;!R! zB9xB5Bj%dEVN${4()U|GyE6(3_z8;d{6o0CvojwrV*h)qSH^YZqgB36t~Qn;x~Aq< z%5AU5y1RA0hwEc7yrtEVrK3 zx_2!P@8%f zyjfgczK7(S)=SUM%;dNJgsPGfpeN7F)U4N8)I3|e$i^n9$j5J3b_sd5^i3gD$&izq z+jVWUJYO?S7VE@1AO7cXZ?e>Np~qnWOKaU7-?FjcoJV^e`M%_qc-u=<{Yw9>BGp{& zti{#UuDLnO=(!5Vv7Dim+yOfVN=h@@-SdpX!3ZiJb)8k(TfE!C$J-l)^K@@*ZH?wM ztwlE)mfKMwa54Y0iNZD+EpIak1*>IF_?Iurqa!1It*t>truDHiQH=Lfq^Qz|ek8zpxk@egMd(Z=Bt#GI}ml9G~}Kf4nc>^Ovl-x?Ogo+hK4gCFQPI%#W1 z$36b_-%yMubyoaxY!J6AzGt?Ch>P`?NK;YvBX=Hcm7`3;z`zfAU9vB;d>YPS&usS^bj)5;S_TrAG z!)VzO?lWE>F)2waTZ5&!t!);Thozw7)l5Z@Dg12PdpmAXQM${QFMqWwzp7uDXt&0% zi={!PJ_nMST`{N2$jG2#Wp77Uu3-bbUwy>^xr5H}Z>8R!(3zk7LxQc$P6$m#^n z>%$oKLH2oq4FE&ErxqA5FKT4`$B*XfIxdId;(tU%MPZWu&PK}UIIY9<=Jwgx2s2LB zsQvM{Kus<2=rfU>FyrXh*iC5A!Os8{E!Zi*yNe7AD$&MeHdJj9ED7w|;ygSd$A{~F zBk2lcjNyuesimbi{r;>~8t<=R=^|@9)-{821u-!(LbH}o+5%n&gUh_Up#_HJ_jVLNmXu&t zj^l-GKXa+Z)_SNI6>xHKJ^fMjbjkDeS$cu4ky2};Zk_G*AGMe_&>N2%pPvp?XY<*n z>U<}d^0}wleZ>X9w)W|45Z1R|mnfvbwBBTO{i3+@B{^By7pAFBlXd23)#&@lQfc+| zGO97WTmrrTVCa=W{=Aw`usJ>doFe&VCRDpcz-v^&H&)@;$@Aa?YE4f5h{2@JtnoQb zP0)_#?WClnNzd1G{D#dieFI8Sbz#NDLc42Y?0Hv9~_iJ2hoSr9kF?{``3;SLtY!qP#p2w_4omnKdIA@Fy?; zMJ70NZ*M81$|p&(cRJqkGyzfHnAo`_^@UeW-_hT6PHZRBs!O!;(IXY{A{T3q2AIE@WTSkR?Bv#aumBUfYhybHYY@d ztPU288HvSYWN>ibPwoOWkT*DSGQ`F-$jK9hD>L9zn9QwQIyU~SU%`i%fg-3fYb31m z-q()V{WXCz+IGZw?tF`>S_Hhy1rDut3%TvNP08U9(0GT9EydU%S+4-ieA`pFK#VmM>gG6{G2v@Nt|;3>D?8`G~sLR7Yxt>&(yH>PMPP_W9t zFF>%K7)(}mX2O^+Gfe9B=waY~uU-k~DTJUHc*F^ZdTXD3ZV7f*cb@(XDJhk20$_Ny z7qxr?vOeQTg@I!ZJh zOiOR>OQ%IfQmn16Hp_`SPc`UJx95aZRf$t|YJre(6BOxrfAb}>xUjG{XiYC*Y&Kcv z(^CF*$!&XcbEfGfg>GLZj3_4pT`x9Hu^%aOq>O;1Q{UNwrIui}e)5_hr0PSm5nzylLH|wpFDR$@;W8n2JZSK<4k)P2@!tiRnF5{EI|Mx`GBVvv zCyOU)fE|eDTpzDd5)>4Cdf8o)1?pDVvEx@d(#3k)GnnTcSBNp7t0M9j-^SMOtqG6i zpHNfGh`RZ>>x*WYot^|)%u!bkcA(_U81rVEXnooWnNzrEWSK*D^(GB|GZ zQ%%hRx;6L33nI`6F$k)_P$W$MEb)0}W#sQ({c%#^Y$US;`^Qj*@K$DzIjU#VRa9iqNJeEH#wOi zARr(sf3UsuW<@&6scv79ZvbR(*UXmvV7>}M=NNwrvze*P`~xUBs!ou5alEFIvI7Jl z%De6cSIL|q7a%Y6D*LD?_ugJtij1kHXs?aAITyFR;sum?qIgscudcbKrsf1)9;G!O zn1L`l{`lPWh*z&@B1&FS($Tg0`};HJuDHy$l2cK}XmOjkxZH4bbhNdwu%N{=-?Lma z&7O+g+?bXlOwG&7!#Z}0;L-b=SsU_|Hht`JTh3PRe~p&g(kI?vK!zH z8xw!Fii({tY1eS!7aOm7I!k%s0wD-4@R*iY$;WVBd#Qaknjh2{!g{uLcNL9|na{)C zWH407%E=KRuw%pZelm7Lh2dA!<5AyR!LkrEm?yXfe6;EW{%tT5g0EBn0J_Sj3q34| zru&t$`bndSi3x+~*b@1W3)l(~{bmawJ@6DFAZ-qI*TO&{gtc(+@}32Xzp9;i2D~Nz z5jk*g>tbJq>-S$EUqgk1i312gq!d?$!+a7V#t$Fr9$yM)lVP20i|o~5qF|F&i^2-Y zn29Fnrg(@BHCupim|@>PIA9kSzX&~0nG+5Knuj@cjfUTlMj?!@+s#B9advk8LQfIh zZb|5Wj{8jP+;u#>k|aGN~^Q+ufVs(F@3|iL4DhUwUYkFN`K7XOBkmbm&V$T#MUpZ3YYo>MH zb;bImq1TKm9O_o=6~wd9mi_86BUPmK96UUvh?%wZJHb_5lM5Z&Tryt^jKq)z5S$ad zKLlDh$Ne_wnQJ_I3%J?ef-E9@{#i3ov=?0SEbyLapsh*mzsvNJIK&qo|u zLH=i=Ek(4nw0KxQ{A~b@+xN-U`Yq1`;+GU`t*(>aF|E{E4^wzz}3NWMi&3V-m*u)-od)niM4cAhtJ+>FMsy=<1$4n2G+tYjQu9CiK zf6vEq6DRXEO>S#7j9prqHR+Z|D@do4vOvlK&WweX zl@*)vz>o!O4d}OwFP)EUT@36k`qC9X>md+UI3|~ifX)Wlqf!zhQ!d|&3Czj4D(X1; z7D0jaInOE;2bly;SEngJWWpFmBt0(=(8*YZo}PXes?a-O3{*nXo~RVTtir~|Heemt zdzF-w6xcpNnMK@XPPr%PmVWsT>P9Ej&mij_ZB&uv{^mUUWas;v*06_Mk!&&=T6{Jj zG%$L?YFDUF$Rm1$m!TgfAc4c6!6hEdd6eT1V07603-iLR8L3*&T#t`@qI3%%H3glc zpvZ2woPkYHXs0TFM_JB@M{h4iDNh+?DpT1B$1~sOhm}Hvsz=e<~g&3AC^rq0K0K~rnbtIY8!y8n-Gz}Kh z;aetj8N@92@fG1AAyhjLA$N$eJ{W3h3P4WM14SjJdiO54Q$ge((9x>+FIOQppb1O` z1>Xw#G3;CPC*7~yx8C3Os<>*LWM~@*O&EG`4fE(=b3ose3W2gDE(;xk`1)=mEX)|r zz$=$3O2ZZ#7N#2CUqVWKB}Y0k7uzxmH>A%P)cYRB#l4T2M-J~q$^P}$bnS}94R4H(;?+!^AA z!6MTXWEd>ETT;ebj>PL0K?5U9^z_``D44SQLlXCBMFH>gRxPsb7{H_YeKcHLK3+|D zulLZLhxNG0LA1ZW|A9`#{k-S{82Nw0mygT)^_ylVX~DSFB|+mV$gWgLNJykHo6XqO zBq_|toZD|ELT&JPJRf*_0%y?tdRFT#Vf2tGfjj4q=!3ZI7D2IW;8`q_PmYEZ9Utlv zbI^LtSICMUgH^w&8^u?N`Mq(OjOHrPb`ytE1j_A6Bu;JhAcRxU2shnu+n%@A*47wUS)b7E@^-#u!0X~LTZ-ag;HxZXcTK9C@8%a~ ziiB!}LEBOzdAfNYuv8V;<_zEtqK2ZngN}4e+6CuQ&mFtG3lXnhQ(jN(Uc8aHDP$P1 zJ_~Uz^r@ShTUYTgM0LT)aHa}%o~MLbvXn%VBLsF~XnGL^-8@Apke^rdDEY=aAr#Xn zk+~CYvgDEW-G$}mW3`|$aj)I{9N82TKb0rfEx%9_PC<{}_@O8(O9;+d5s~u!TZLW2 zd91TKIygWGu@7cPtvqYhOY4mdR#qzd%^QPqJ6*yl7_u9}f;zR|>=Nkf!m{tDe6taT zzQzN38Qd^8Dzk~QTl3kNA^?>K(qtbT$iGinn!wdy|DacgONj26nog=!(n9noORte4 z&EFz-7k^d1$mI6;#GXet8RTJ)Xs-#vR&yY`Oa0vaj;D!PEDh9pfbq`wgK5yWVj}@9voFlS&i;IN zclWzpd9CLTmL?KxG?m@a(0CxjBj`BufS7nKc6pgUtEGJQt`Ig5HF)kU=RTP$hvDa| z+=HztD=A4!N@8KV?U`9Et!HlVxF_*_)*2Xi6OpuoPsvSgkPIOHeHlvD)vx=26*bFj zw7{UzSob7qIqp_K4OM zDl02%TA9y*`$ihTa>oDrB34-caJBn2Rw?vrzkW)XH+ghMsa-(A=+D61v=`|xgVwe+ z9T67gfzFV)BqCLQ$47jQVvsxmKEn`z=D?PSNlPc6Y{beAL&Tag889^A6u{)xdYKg{ zLj!4|u;5@Q%V`)^%zOv!0I3qBOelBoy1m~jCTlSq>`x#~$znW?*t}%bc14=2Lll?L z?eg5`&u)k#^++Qq&@=uJ*!K+Z*cECRy^W_acz+rg?Q~sTolrtImbnLl z$V+RT-+*|n`@5-%G(c3S`^ZUClX7NeX6olpViJ;&xR zkN68bthVeW&mTyCSn~|=hlJ&4HLj$jIK8_13VP{BjfbFLK?P)gTw@QGceI{0R_$D9J*CFQ^b{h}|P#8Xtj)-?tt;aZs!f z0FDK?CnhEWeQwE*`l=QQ{(B?yDwn1HijqAp59sGyUNqJm^7z@(^GOf0tD@^kWSFHMNa-ty}5 znhrCwu~7sxB1sw~AvBR{k3K?*L_Vp*`RJozUcr|Tzyhu|U zn;)N-F?$rp$x)%w|93$6-($u9o+199W5xg8viw`dFrk>SZ=wzkM-fCtK|{V!*6jIz E0J*5W+W-In literal 0 HcmV?d00001 diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-cdist.png b/docs/speeches/2013-10-05_ossawards/ossawards-2013-sys-cdist.png new file mode 100644 index 0000000000000000000000000000000000000000..5fa66641a7a76afe5c9a08c16f2fb912503daca1 GIT binary patch literal 13919 zcmcJ0cUX@7|M%ITl%mj(hE$>yX^|EoNz&FHk}_H-Z4F5qNzp=)Hl?AxM4=(2(%xxM z+T-^+@9*#T{XWO>{P8@`AJ1{$_iS`w$=(f`l1i^4hSxJK+ zD1`B!3hjFQKc8w&PksSxiEdvnL+5aB8Yr(yNbFaG^@^2NX3PQLi}+sPOI{q~KT7cUCTPW%ikEIg9F z5f}2k+LmoS+>*iVGBbSp>C+wQo5>#v9XP;5*o}VMBW&<4NXQpg>nU)Z6Cq3&XGYj0 zudwOT3T!NEa6skOvYo|tOgCM2~-mqJKQRaG@PHFRH;gv~=obbMV;Smw*@(sUi`#et@sNK=@@+<{$^X5(42_^F^ z$yCC$+;_u%Ny$5J-yU52J4TbEA8hdTuuNl2~@uIZ0mVU#A4VSu#Wx0+xdv$ae z9&w%Bn3R;HtfI14d%qa=#W*}Hj9_JD#kF@HI>c^nU&UDY_RSmh6rFvKqoa9cWjV#7 zHWFd6v5W@~9()`XWuN#~qvwF|EZyh%CK_%x^`1;huj!$$$C9C8)gw)Sl{H_%T24{N~LYUV`tz$KjcgCMBhZQBkKZUcAT`p|a<|fvg&$}naXjUUn0= z?c5!oX*D%9#jmz$Elrn}D)bKx zRkXLi?|6Cb-Me>ehaC96*+>9)UaZ^#&JfFv+J6?NhdNAys8R$T)DFyd`)mq(@W98m zcp<63nk8^&WNmm{TlA=onc%gC@%gm-RS)ZY`6fRN9D{Je%@ysQrE&%1$ITLo|r6} z?csK};B6OU8&_VyXVPTi#xlnP(Ie0ia@H%C4+ zI5_d3)fc;C0O;9Jpo7a;T5fh(;({)!>r+ily@=F}QLXXG9Xoay=bxInQ60jWQgmx8 zfh#Z0G@Ttm=^TIL=;XAU$hK}0xVAM(^GH$9?T;TnmQ@FH*n?U+irqOF85wEm=#GxJ z<>b_2r~0P9%AYhh=Y1r6-uru+L8Q%3P(mrHpdslD$1<*}SLl4;&-ApJwRJ$imfZj` zs)dCGT6+2lJbiuPEl0x=kCh06eQZLajKVtCa%LA*`ef|t;*>w5x<-+MNGR|u&bNSvR`KAu`Ed7T$|HI4wN1~0; zS5cw6fB$|SuU=yJkL{1uBy7IXevOr_cz!a}xmS)P*w2lP%wOZ={Z$gZ_3CJ*g3fMW z{~wC}7gv)4;NR5#zbJvG9B*$*pLs@HWTT;~>c)PDLl-|sYg>2y2L4vGwQa{iH0%Lo zM#M!#Yzqnsnrb>LZwB-^Y_bM^J7D!?2dcHTt89N5^UNNY|zrv32X#4S!GL zP>YibUR_zTn49={gnlVpJXz?tB*1OEhVm!KP1k&!Yhr+zBuz8!T--i!Y>EJ=Zt zxw&^{=6;f3Thfj6vM-&BYRNLMqPx;ss8VjENcnQ&V;`em+gkW#7KDvfM<{0 z*?1dZh*FYHMPZ~IejsqBeExS|cvMsX1=V_<-Mfc!Y60ZsEiJ5}T(af<+#YwmyohuK zY|`uRwk0cf=DIw&amLuhF3>(y84#+)?YPY}oXopE!hA$lHVX{u@qiJ}rhRsAg!$6! zxShRySx<%k@2<7gxd_YRr3o2dKfeUEn8U3_u2Mn4!TG&?H4S+qN!5K3&OD%^2Ny)^rZR9$_29>}YPJ8RtE&QMqf*{Mj z@5J~n>7d_xcBb6Kc0QK4%z|SE=-Wg%uPz@FI2&7MRs|ijAyhxD+KYl}Gduf+?znbt zMsB%{$q!F*VpX=pgY2XaA3mC_)r(uteEYUf#SE%5D>~rA|J5n7q4n{sCxxf$+yqIX zQ_BmE($dnUpFcC~IvL^{6~#VBRL|TklZ$@v=+PZNde+|DE)O4-M3;fNiHQll_c!-_ ziIWd~_;Bm>vF{8qGERf+2T01%Pti#$4`M$U_T&jYC?$N?$=;t%U4A(^5?t~gLGkfC z|6s<~oXahYW@cuu401*0HiBFBMrtHi`fk{=nVFfAn3|rhXfg2&X4$8|^}L9X5IsQB zdG;6kolV?~kYm1g?(pv1Ns*?Xa}<>YMVIfiUqJkVLXujH3ZX0#*#s;+Z8%#iTJi$e zrwI^ZVzRWd(rkZsbpsL1cEFp>qTFKtNj)0I9SU)B?xs+*P&4H}e-_n^DW5rW9CViuXwAPy4v*GWm;NVg30XTef|MDA;RwZb>EjScW{%M3@b7nn4jDjBV-ZQJ ze9S$#)v8WMZG9lDw0$r2zqHmr?~vWSd$+T*b2p^M{O=FkwMDVFrU!RQNNh7UHb&+4 zbe26XWvkOJ$3r}WP}v+<)tYNd8jN$JU-w3+2D!*glJ!HwcowoOS4-abA(Jw5084pT6dRaPq5nI-=IVHIaqb#EJa zMS5Z0@^U}=tm`8h7cN|Qn3rlO^5Nkg&8Z%L?q}!UUX*yZ<(1anagONA&9B#4Sy?Gw zX~DBn5Pj9b710uxooy}e94xAPYxNc6bYl5Wt!SS6k|d!Z%yLX5l68ZKl$6x`!a~BC zCz7}&8uGxi7G9{2R|HuySDR?Y9`acU>@?x81MJ@CKdlZ%cANcSMP6gO)U_ZG<}P>v z5{lv#eX?s!N<28BOOM~YDG5TzquF15TU&y6*RF;Brl1KVTQ88cuR2oO&RjSL7l=M^B%>o4m{+h*VMz&d<+x zL%R;QX6-^12G-Ol&;0r^9ibWU>(>>+D<+1MJe#tvv!q~GR#q;p4A{~$I(m=)^rLR9 zOUEv<@M45?)8ntUzaxuf2PY>JGqX2YL7;?;l{&o2zRk}ZP+#Kd3FhGu6JzG$;!;*s zt*nbW*buKsC2W|d&S3}VoazAcP+FgGEF3U#n~H{4Qj&$+bNN7J@BKjgwN-aQ0W6R$ zza>D4eCRJv5Bb11LL+kgw`gmCh7&&jh8jH8aSZphR|Y(RXWJzw#}ykJ+X{5;ces@- z_vGP2YNATbU6>`X;rYo;B)zbT8dm}x!@|RF!x%lov$R>!v#XbQxGSAJ`TX4T6Pp8+ z@NZ^L&cHoj;~Hbi0gGyIE*)4Hir+cvqGdhx_a_sgjddd)i!;{QSKC=Y8^b@|?gmF! z%dYbZ2-pCf90nW6+t_*CK;x2i?8oe!oaQ?_XgCiJmqv?O(n((Hpv^Z7!G|Zngjp`S zIXL{e9GZErZ)79@R?8HY3#N4H@89EET3W%A!cw-KN;*2`L`Aj74gxXk|EP0-pxf%ZZ+pPr{ zUeecQ1B9I>JGZ%69lG`BLh=WO)B2s?zq8EF&KAxcsGv*LPSLSm6AR^#Vzj6Z+B1Fl z&D*!(;o%fAGBSF4dbF?IAo1-S9V>!4q_F)oJLEkK>tm{5wV0Tg5*g!qAJKT#)v1mP zX9cmVn*L~SKPJpl0n5h1!tx5tpC6jOUGj=x-XAPO53JVwSI~-T$>AG&aTeh;vTls&z&se)y*vYN#3p`eGlH6wqP7+Y zXlD6ohdk@m-}6vFVg$F_6a{(AlFmHog{8G~a{2%lv+k`sT#)mh{!`&ig?V{-Eh1fc z_IDbk8i3@wW&0;+VPDeONdC)BSjj%CdE28zaO?LFW!b1Buh zNPlWB>=YmKi^Rm8kRNajWTBRH``DXCoQxDPni`7p?0x%H?wE!K^WfJw(VB5#Vd2XD zj}Mr3?AREfo;zc?j5vlud zaH&x0Wmhj78tzz}n+!#=kylW_d*sNDGtuHqSAIIw>}M3_^l!$k1$J<6+qP|;iHS+s z)iEq>L*i-HBkqe^V-DXa$6`&*w%a;pTu2q5egv8G;?x6@JmIm;JM!#bX})A!osL_h zb#S#5W8W@*$qV*jCrVi?N_FbSl?xYMJUG8STJq{*HO))*gRP~XzI>_9G^?;fY=JBE zKCvxUR8Sybs>p~=v3N#7B$9r#XRvYq%*fNIO!mrnS2Z=p!oouG7rvz#uzm>TCYiH) zYz)Dev1xbd?PVP+6xi!HXw8${?!Jg7NT-Lq#AAUU#zDmpprx}!8TjL^mF_2BSCW&=_ZbyzgVk!LWHwUR%LcSjdLJnp3VjzDC;=c?P?Dsw<@go_S=sKI^e zR%hWY^_1q0#b`AimI?%fneA5A)*pi_39!N2>E}2Uym(-^%<9RKHRGhO%uM<@HhyC* z8N0;Aw}Rz{xTe;|yGpoSXMZtujJ$zMqNJppZ#Gq3qZESA3EnQ@t;DN{^OxUAy#j#l z>kE}X@&4wx-S6Jx6BMuqW&?Uz=Ig-z2ORoq9Q?Ksc=8J9NSu;hp*!SqgaBbv^>gUV zv)B$^tP`Ab;bRWCnVuZyxfntY*{4!`!kizIPZnjwYz{ zh={1Y)Lav*wwYr34*Desh?eg^4v&wI9{>pnMyM=LRcz|mLSk<);#?{M*6T(=C!89> zQ}fzK`^dz)Gkyq<*E2pI3>9Z@X=kdv3EA$J-D<@AP=rwdvOup*^2?hcGG$Iw&*&;D zQjiKF&SNnkgK#v}4uuQb3GIbgJmcZ}7zv+AAZ)Myv%gQV*wD6Qs>OcrA`b!^AwQ}V zo8u==P!b5$HTR4;IXU^KqzFNoesC)0AVft)Qw{T(m3$!)x;ye64fmiZt>BgkFNhkQ zHm8}fmQ92m7H@)Sz3H#ktj8ddKY#v^=cvE`Li$$5)K9ud<`DxC3W>#klaQqotG9^9 z+HqL^9!QqM=UX5i>!Dp-?~+ZIfmYH;0RVTKEG+s|7DA9Zz>LA_ z(gXwq*xkH27<-NZM!~nWRqu%Nl)~<&pBF4Gd*H09@aR25L;gtWr;Zr7`D*8rVF3hK zR%1CG0V#XHdCC<2_exuKfNRy|r?Rdrk)kH)*?&3M*>}QPv5FYhe_TYY0a7G&IcNoe zTO>y~RqcK<6)2VeD*UIpT=(jaH|yZ?NH@B7T&6AOGEH}!P(?xGt8=?{NZXM?;{3$> z$<150RtA5(ow!zTeZ(7%f(Jg$#B)VLx8^jd?-*t`UYM+s2k-uDNIR`#U^UKbpZsFE?5CTcH4 zCdPX#7hnZwiSy^rH^7PI+5g>4^Sz{hVBj2FW^e`?24@g0Q+uH?A;`=7Oe>D#i1U7m zcs$Xg1(^sH{-`HU9w_l90Q7WKqR0f4QXxG({b6``8D}h2Ap220_uo~lmW(OyohI)q z@nYeGK7IVSr^U(XS8F&?-{rYxWbGLy-qld#>ZBpKwWHg`_d}*0lTFU{Edr{gAeN2v z^z^@ezSniN7=HqcQB2e*LjvAmTVM_ALv$mJkI;|-%uJKmMy5ljULv=^@9(vLU%YEPwayZjxExFuV%x+vu3Imq%r zna{iEcJ_<$$*vN42;lmcXSoZpJ~A|2BVT;`5d{o4Ceo)H7u|#3BDFs#$kO;Ma{70+ zU5t*7j;fFMEADRp{_d&)@#@M zo7)kWxrt!#e5C7QEL5^$vX*(}U8boQA+_N6 z$&(KZMRpV7IFfq>1qJ5{92^}#e)$rj#LHw<;$dXf{`kq0(;CSSRnMGBSx%-ZcBrw? zQ{`D*9214?q(Nx^UChVjpN3~T*$Ju z6K|mW{gAkfZ>LY{(Qxw!2?fe9BgMON`}S=%IX7v*eHIQd8Q|}3qNZ8Do|1sF zr9>Oa=WsbC5w7feW9)kw0yZ+h!}}kq@H@R4t*&ssGuCcf!cQR8-ycN-4dlb` zRk+lzwPx<5i1+pNwMnam*$7Wg-a`>DarwL5P%om-XF4g?kb%@*z)@=u;9(%Oto7|mr6*8n*a6o>(s9w2g!Qb#C4=Q&F@F3qO+$f=gJSU@doYVwukpIKq`~+5(TNOrpBV=ewvSY z8EMs}w(LDn5M*fd$5nWNHZbCZjti4I^6g0^AsZ^Wz-Zj~olOGQB7@j_)PL2TI3D_5`KPu8(vTJ_4Vbjau3!;Rm6mcX6l`4Y-;+wx-_}#@Zs%fq*Z); zup8NgkIGUpT4+!pWT=C4tgZ6}m__B)y*{5q!p0YmQBha75kV~3>2y*-*R<-CvT{7S zjGKv3L@JgSFY1iW4Gax6q2kUE0Fcw#`rm<;`0K8c5}x+nfp$(ZA&7ZV&fu?UIYQqvxRE{GUruNc*cjf#74uGP zG&)6Lo-~(aD2EjzyL2QLLU`<5n1JIX2y}93leP5s4YbsC@c7DfntbT!*a4*WLHiv# z;f7?1Y@ec2(HqyfYiMf;5HkajCORW^>#VJ<(e{14taHbco`C_~Hn(}ZvfLH~1T}4K z(L}vy$#Oa8;}4lOA@Xa>4-k&g68rSCUwtZBgZc$7+I)LuljaYJzJ;)9d=X%rjck2M znKwL4i8pyF(2||zkulkqIF+bDseneTQG{p7(FBMjEFip0>h}W3b-u`2n9FlII**LA zyRdUPwhu!B0(uxf-?q%tNjE%Yp7j_=v2Oi(omxp)k_SZC`}gm8M*EBAI(HFUw{1(5 z8VCDcqErwO5qTIJ`-Rhh#<||eltoz23&gC*$83f}1o3B+bH)E+ru(1%kKV5$M`OkE zkLY9=2czdh23If?caA1>Gk)=zxC5?lKpLt-)Kpgb^78V&zG@(1myOnO>TVPWQlkIb8yaEqac8mAc58F%P4^Fh*r zf28fY3H%<@wrzgkWvwyE`XW4LIo7u7`p?_9*^vo1Xrk!by-)Va}S+;B6%k4h868?ewM&2%UTx1 zg*-?$A#|2cjJ)YKD}3#UaMPwE?*IkQrcI$Lu9qEd85X%j5cMQxAjJ1BQoyW?DqMVK zyPp0gZn+ouC}v`@|G`=3p>9PdvwXzIq)e7^nurJ1qUZ#F{rW}y);-#Q9i*dac~J3T zgsK26EC-qm=_V!VEh}Z1^&z(cG=-jhg{JWIo&-C5EZGXc+{#fPcc$l>2Z8~*i%W>> z$WD`TqJ|>lyAsudQjc~TTDlI!I3Ye*57n(2dxRavqb~-|$c0nZ<)5?yZg&60IyOW> zWD2j|o`+@`CP#JvG+FDMqj!da;W1}3Kk_n89U&kRkD@|LpAVTE$-4YlR~JOoBR`{F z(7U6O$cv1TQUP$q;ud3LJh=EpW|B?IBud(zmm(e#LKAI~$s-wMx3%e-lFmE_a5f;4 zP+5t(dzV)1z=56rH0#UcjN1vJj-s`^pdId6QDJtJ_h_1lxXTc4e?;Sf*rLH!)m{6*eUvzYIHI0q; zF&HK5zBrRp>%KIeOYQYSW6#yj!t+xD+vPouP{hMbKXRVQartYbc-6_&w41|c7>4wM zjg1O13@h<1W%VX3(tVXgQVIzRr`E-JBD@Y*c}SJA9(n98;$c{r`maf=&(Vo7wJO|$ zztzs3-Hq<#ePur6okix6BlQVX6!A!OHrTX3fA)-)0QR|7t;$JBMIva@H)o?aQdYkE zPCiD?y+AeYDkM@fj=QQwI;blN`#|kA(OG2BKV*{=eeuiFQ$$T`>tmR0&9wGgW8e4L zV4!4WdHO5X0rG%SK~7GtYIPN2)B8!~*%iZ8S2SyxF49s-%r zrBW}7>sV>tTC@Z25*QDBdvCep>(@{Ma~#tflh%;iKS1AzBL0x$V4?j20)%s-*OGfm zU-Lm0^Aj`8x+dq)&;sN$5uoXF$=)ZR6w!ZmpZ+Y>R`MvisphQQf-fB6jpEPI&tE}I zZCyxl8*h`KRQUe=d&X09!+ZxnB)PN%$SJLDR7ODH4rKbr&!2-~88;9h?P$z9L3=SX zH6$GKrzJ3M^|t0*23p4fRlPRunl~(wkrd7*2S^#^#7JJ~JtZJyAk>--Qsk-zQEW6G1w8G7s?`FqE z5IAkEw9ZpWe1<%25pqO+T$2j<+_Tz9QB4<@f>|!HV06Wy|LPNb6lW{&2;s_nkV4OS zuP)l6-B3TP%b2?TM1p!4vT!_#KKkPn@fa0pfD|x3KY{X}sbV#O){w!&@V=D56%rwb z-l%jvgIzVJRKRg;4)I50B}`8^2~qR71M<-sIH=8p%iK?=Qwi#{>74Mfuic|w2M06! zEWGsqQ*$SY?6M5@7X3`q+hwyKuy>by7NJ3^M4B*#L8(Ccc^aKF&+`kr(4qNMTl*Y| z2g|L%N%WGfm*;=CX|jHnN0>2+)*RS7XrimcWM6x1Ow1YV8OlcR$dRXzEZ7T(#Tx5} zgK4s8v}C-qPia)&8_}k215bWjN$HYp{TVei0VsInK$Ap@6SwbGvT1ncCm9b^yyfE3heKQx<-?N;rS=KjgajFmw5>A^E)xgS6ouizNl&Kn?`)atLP*qjlx(hhN-j3owY z8!uR3H1ia5fN#G;em7TgZ|Q5wXaiRL>`RIm6}cJyT=28=w`a!#sogL1PE4o~mvBnj z;z&8tor=;k%6B+!+s1eBpypEl?V=)Cem*{ROdik@M#XMFx)-}^PtI)5&(E)t`&Q&Q zq(-T*viSF4%}O}c7=t*~1feX_{Qoh7o`H03P7y@5S3e7 zcBE85U+j8s<%Ximkx*shZ$s47)Tq6{ZP)BpY(ZXlluHnsiTWOB8enR2VSp92k2%UX z=x9M{>Bkrvoq4w-&h5_ziuj$!?$p25PRTy0gC?Sjfxzd$gW_wmlU=sB7B138FJg?a0hR)vKr*n=@mq|8bt#1(~=O!T?+MJuy1@1 z!4igX)c~buQpOar&Qm-T@hCZtU#m5a1tqtYcyD7pIwLC@8klzO+=>1xa!&u;Tq)$- zGX<&`ghA9)4u+iqq-?mB?q)F zC6KYub5{Bl#Nc^nH7$4oZS?%#j5@&lh-pJpKCv+rOW zvsltgfWJQyFEdEbFqK3yio(0gPhyzdOh{1BOKY#65^oPVfiA~?;s0d}y~*GRH;YAc zHy{$akNJB;pk5F}FFAmL(Es|<>{WD4o@HjLV>Y9|pITmCo{gP-#O)_J^a|%nt$PuJ zix{MN1{E~0=mtkXwimIpwAY5lf4-L@ljv~e7fm;~5$-~-dw1jltjT^pMifpzmMJMd zb2LLEx#r84i3q9v^aEXJ4Bark=yx>1{quv(Yr)*|#T}Lg#cuhgwd=f~>=LJEmthjA zjRtXE>29vIyx*0I!PFNoU((-PLOVKs`o`;Kn@bld00rw1Q}W$?vz~_La&89icyhzD zq{Fs)yI#I2+ zEoh&^w*Baf{pULXTlg^jg|TW37dVU~}wLHrsYM_t}V89!=`l&Ix!=#pwJ1%EPKxq1~-kQqh(BWHr=9DFWsH;CKb(b>s` zZa4-u2&UV2H{8z2#d#2tlsMH zABbiT07b5#MM zp+lu&N)o?|-bC+jk-qhZ4>RZt4nv>o>b{LhN_S~-XQ#1kt)T{u zrxEAh$u4e;4|t1a$mIm551($IV$xw>n4d3f%;djehox<8Z5{q=(%<_D?-#vxi>UeZ zsWJBGhV$p!t2c+J%_Lrx&io`OBeN87XJ4|<*iv%&*nhwC*dS)Vp-X?~(Zn(Txm6OT z_Q1H9_oDJk)in`=^H)3am>>8J9}n4d1MSYgzaAMH0EEn{(Eh(ECNiV zbF5H<`)*i_^{ohDCIFLBZ3f%#(jwNdY}@I(-JvRC{LJ{mqytpY2J^+}M$F|3YIHVc zzf8*5!UQ!ywqSi0pIc_W^j$0dvu=6v{``~eO9Q977r(VuMVybU9n*A0wwztr)#5AH zg&r{wiCv3*;oTkPo3!q23Fk*D$f3ahd=Eu+a*9odf&2~tM*Ye$Ya0Ivt$7}nz`ujH z&KgNW0i)sXkGX{M=H_jPS?(kz@^hQ9^ZFg7z>%k>rZxqekz2Ht&QCG&JYwpJj(pNN zqhH)JICuxp#IE#%?7|>p5wgriKs&ThHph{tb#XPyTy29`#t1J7TEZfmhsJXycN;{xl@BH~P z^rSI@B#|y#d(@=uZFMa3s6(TeyY-c0!w)-RC7#P3%FN3u8~?bG-Gu)_#@{5Xzk1E} zRom*ZINOz6Rr0eKQnG@Bg0AaaOpxt-R{Lh;wCnduE8fdjOq(mKCHoD;H?GV+=(W?^ z#y?nn@ju_}`JXQWsY=bu3Cp6D5(FJ+cbx6+Wbu;P=1E3)yn)i!SC-}`PukenXb_+SRi+#@n``L;Dco~$Ou_k*&QR9*%?uk6b`btjAUeF zkLNz$>-znk-}BFNJ^ws)HGB@|yg%>veZSWIiO|tfB||bG5eNjC+8rf51ma9G{J({m z2>upbi<^aih^#eKl@O=+-`PzC32=qP^^TDn0&&p_|L07hT!AB8Jnyb{SNZ$|l7Qs8 zSU_P=2?B8yp{8^j-@U)ruvjc5Wn6Q!tdWUHLUpzH zzvZ7%{QUenhOn%sxynjPy}8O!OXKx!?8#kGrUv@@3Hf)^Rf-MDI3tvT+s+}XIj!te zL<$Fw4|g4Zq={F#j7h|I+Hm-mq^C2k4p%&DYinEjmc&PW>5}5lVgs&Qw{D?5Jg{Xg zCk%ua5X8xE*{@$uSm?>pPM2`WJv#Eo{&8@2PQYS0)Yz%i)zx#y$4zlkDk>_8nVF^A z|FpEUs(iNWoW|=!kW8>sNoIzIbY%3RAyiaUNC8fml zbPY#G$EqiDD#p$JJ{414A3p}gFw3ZymX>mR!~UV}Gv0W_uC1+&!$qd1(*H;id4|8i z(a}-mM-SkJ!~zc7acCJCnRs<XZEa0mCL%75 z{WDaie|+#ymr}V_kDHsJnSEe2*oR!`r?Mm=;vq# zajMk^-vXBhOS-JAthnot1ge5qYI=ILot+)_Bz2muj#w6LSy|cO$2#cx*Z0fJ@5aT& z{aRjDfAA%SLqK4j?W4ZFerJDwLS<#81KjVxJEQA3sf~?|U(?g_J()84{9{diH{fHC zNoSL0x&$-iFqwh-^R!435+0nh^FZP4^B0-f{rvop7cRW%N*2<0a^e+#G@jDn{#)V7 zElC>lui<)=u zj&yZJks^^g!}Ew4J!EEPX0XawrEQnOhx~=^3_io5wzk~f)#kwCGywsD)bQcn-j{Q8 zbEIaqche<;GgOSq&lGCV4##t77;0!}P!p%6rAhm4JIG>Aq`5daNX(Pt;#!BwEEX>d z7*iMjS((t@U7Ohdk$!{QJ4B;>bNMIVV1K{97%Ctjpc!)-nDd8=oxMCXG<2G{KsZ^@ zjB15IHI`YxeIoU`J#sKQCPrmGXjJX)-TAeN4}4^2XlZH5FJ2THlrXM#!n!j;Wf(Lx z8kCv8&dQ2KLNPNjN<5?x>$B~86|gN{X3?_H+p9y4L|WIIcEcet(a~{BjjCyD+h4za zy?q7)1(h=mk#lQnf)3*>q;YMpWdn@MuUJ@EpvViOH|D;O zj+Vv6QJx;}PUZfC{rYl=OUnj2J0>!c7oEGCzWw*ar()NQww}OEyS2Y zQy((P;%l0x5>3@2D=e(D@gX#n@aNlm#i*>gnNQDyzmPGA$|DU^gqN6O-y4OYbYZLD>5WiQS{;$P?)j~)jSWhs`*2YAe*3P+ z4y{kMv{>(tytl76dT$4KzsUNWffiqO!B*)2a0=}~#(U)^PSYQsDwnocwH&B}NA88IawvYDRDyyncn(U5`9%%uR*x1=|8kPkf zA5hcMsw$mk_@jYt@b_zMY`ncWuMrs?js5&t$#-Xk9`Jv8y#D&}cE2`@Onh9|{6M{% zJ(8UKK0owo)Y2H8yz)S~m7?$V5+&vFuGYJYEVArwZdx=7u+)t|&?Kt0hP5fM?y#8mGe$P&}F zj>~)QFfi2Uv!(8CMN7F+q+cL=FxmA=;8J70V}Cw>lDaOB&J3I_>F8RD$OH98vWpil za=H|Gy@MFE1I-#Yd#o-DU7uWL0doD)@>f^H2V>fJASQv{L zi+X8aa^dsm=O^mjo(DgB);Tg_#BoNy%v`3`ftHn3NJ!{le=&Pt^g?|-oEI0?J*c(f`4zUO;uYip?aQ=x>;y^l}NjTdOMNQjE+jfP72@BI~B zB?kzegEridJ3V?f=cg0#{2~i-^zU%RgQQZfU!_ z!3uXaHfA{QrcwKvtEj3z#~l9~5?y6$cAW{f9yE$jYFq5d`jUB;7gzV>fwBp3@Iqsw zG){_E$eg-re|p-|&aS(sXORVS6o+3_XFLb?qDCM|@ON zl%-NQs1dUU_lPtx$IT+u!0p5JmVT(n!t8AM?M8fGAFkF8l$zaot6xBVugp9Hl*SSi z*Y@^r{m7`Oyp$BW$e5VR|I}KvS>tqont#_$1?Jr^F-|h7Z4V|SUFwlLr5?YJ=R#nr zkWc=5Hf{^wbD$Y`nR`G41)d&zwMwbRFy*v9JI}}L^=B|TUo%zV)vH&DSy|fJnbJ9X zd)~fBdm_*V`hX7(u*dBUFKXp}UBPi26B| zdyAIw@$ueJ&bf>cN!zL>Ch5;F(6`k-o)X*=1;A|d-mnHVy&Mn&fPGo=`gPPJLPA1m z$3FI&%F5aOt;OP%%-byF1-0en6cbGApFCuD9#~uJ{qmb^@X#2Tc=-5n?6t4N$(3X& z4IY2q@>@pXgGw7S@GY++#mPuauIUkO=sd;A#`Ku?K?iP=ES zPd540_U-zD5E3%2d+Fifp?o+FzCx#ynD%D_=2SL4Jw58I3Jur3Tw-$a7oeznA2nU(H@xbd_3qufo*gfHTU(M+t-#Zx?%DRJ zq?pO4Z=Gk_LUU_GA9P$udI+sC_7G&^Xy6CWRqu%gkJoW=y1A>cZ_${8-(00o(mAS9 zpw#)$ftA`x2??Lp*482qJE|UzRDPQbZdBJkMZ?N*9_+BBSy*RMa}VZZi>1}C5!(Iz zQIoE&?l@k?lH1$abrfi4bzt;#oS->#B|vGE#$(c;*k@o7d}L?Oojb>T%aeb7vMK#p zaPUn|&an0I`cEL+X7f~IH^Juk9PMqaEG>Pl26<6=_$H1Ly?dC_;J_uRz%;Cp`l@U zaKv`Z!b(ikflDRct@Nz|O ziFyy&<`)-t!7(>F4++Y;EnJuaMw@E%(O<)0e0>}G9!cN5d)K_tTVzKlBnl0+N*yp( zTT!w9#!YyhUJ#Dh4%Vgn>G41z<@3oCPFXuUo6Nd$ce#Q*umY2z`^gK9rus2NknIGHj!Qd}-w6Xs zrkHxB(sR`qdzhS;#|GQfRZtIVgWGbn%JCEUsGZUYgDR_`R`NKxUZ)ZicNtdM!i+4KSPrORn`#=EC~Mq8J$&-)Cj9@YYa^xe9g9{=wy)UxkLQ zs;Z*yQczHE0EL^Fkf6`G&XdsT05~v^qj)|tB7#zSabZElYi&FSj7cs!TcLMg;0<`z z-mh_Ngtce0@S4)1rMWF&a(A~35SJv=?a7lINLd)f94L4%*GdYq0P@mI)K>uIhj!bd zM%j`>LI^ycJZWuI&VHpT3{BgluCe2(**>2bA@zhMeqqB2AY)cVrf3U6%5b`xSxfW5sDJcASXq6IZURW)4 z7bIX>KuD}$Y~PxFkl-!6aMcuLvoc)qYjyQ5RfJN-%F+IonE#%uwViF=_SdnobmQ7b zccDUq7XdMOczGkkF3<-DhpOWh0)80*hdcN9`M9~S-nemN^n+K~x2eY<=?7|DOpv6c zm-ru#)d=9zI6wnk9=gbPvV)~&d{Wyd<+rX%Nu_=8T8~NhxhG6x<+S_OpWJS$Ie@n) z`Q1ByZ0)(1ci2~EW?CgBB@06~hqEZk-pq{rXz&srmPtP6OP1y}jA6%}Ksv2BoGskUi=9`!`zpJR>4= zfCI4sL4=gAO*u#tc|f!}RvRnjv8)6FGZ)?*nRzN~2p&QmphLA>J_$)DCnvYuhmEox z`4A-eWL7DnmMfuiX~+V@VPIgOTYiB-EF9893V!0`Z&rJMXWaiS-&>w)ks~~Rp3m$H z#CQ-)sNv%zHa0eD1{4q2QFnk7^phvL{9Qdg1v!e(`#KZ2qM9-w@kD!i=ELD5wMH4~ z=z4+8J9~O!AtBP4hIgNXaOu~|iY7pO?&8YoD*kjjUeE)@^J-XFWNBqcDTB(1wDs}v z5%d0Q3HLOhYOxOI3?>Mhoqe?x4K^Lrc0Nns-kH#&)aln6^mr@#{kvxS9Pq0??9Nh@ zP;)joUlPub1cl$uxUCF};Db;|w7Ac9fVt|Q^oRSuL8Gxx8zoN58da9@%BBPn>iPqet_z2Y-;))D|bR+CcV3}YSQ4p zFKX88pW4{iSO_5jKDh*|W@Brs3}sLNhx-yjBzi{1V*Zuc*;#H$$y5kC33?ozoZ_RS z$x_qP^JXJwMys78r~du>_xo38g8Si)3;rx2<;@A=y-C7%xO|?Ml9^esZuta)?p(D5 z&K%2cL7JR-WQ-EMc<%+SJ*%+^EQ20s$FBneRfdWk7LDGwFEUGK!*n2AVLkxzr#uLn zAq=?0y9)45cN_8`E(n>d-$nWoGSwpz!}IeweZ0MU%dI|r1s4aA@PXQdB?$>h6{w;l zOgBWoQjl1+5yC`a`3)5Duemuz@X6Op%$w5mAjXBN1M8~_XGG1wVEijiIn|5i4*LK; zzoCYC!GJC(3r8SV^(?=WBT0NDt)OrgB9+L#{(c_V7C_npx~n=R#^M0aZ1tw*E4{+k zujc{Hzs$(EVq|QLPrzW?B4ug2X<=@WO(lBc1{Y)%IR1L5dz3r2zP=s@y~xAHmS;Hj z&b&$L_tH|f>ls)uiyTAi!=DK3vp@Km$p10i_|KH&zpni6xe5Nt|MMgzgtXAy&MtrY z2^b3`Axsi~H#7C2j5p6};%_j%W*p_pU^D7WvyvPMI0xJ0uf3iAO z%&LvR+KyU}5F$N|CcoW$_|e|&-~GB*5n1x2%Gt)CwBA5?*bg}>O&2>=1gj1!8ynBn zt3eF_)opJr@qs?n8a47PLRFBa3*zKLiCn<9+THyPLp1)2&r79%w}aksyhQuReJ2 z03t6*xBMmU^9bbbY&&WDI-oz;_*jM8bttmV&dy)6vkKtLX!)TCMewlg?%_ex1*9T@TiTLSn=m^FG=e6{rPve^Q9iObK=w;qA97PpiX10m@>V>DXS zV{P1snm>wG=<&}0Qo^a_ECT+~sH&o(<#u4GT1F2@GhJ&B0>Z!JJvyE#P^<4QPW~OgzYyhbUFE1JE^?NK0uPqQ5}k zvWVK`jEo=nNsSABgf)+rL^8fj1YLo5LzWi3Lqm&mUt&oI-Q3-&-?_o2Q!}?IH>qLu zm?hC~xD5de+hI=X2QH+??z3c)0uw;l(7#HvSmGoTqoEq@-jY zC_c2gV{+2G`~(_a_a!myKYWn$s5kp*wurNX!(V{Hdk3;CnHXGe@3f5HPWIVsy@NzS z{02ZG8aV`fvjrQgQwTo^0r_{xyMsF{05x{Dw)heYYtPCMi_^n2vEEuBO}tT z)AAqyu1F;UT0~Vx!x~7$5o>*lS7Z z5IL>o3RXh#=UK~_KnjP3Imo@icK@TjC#^M*fb4_4=XQV@j=rIsE4+^+4^Pp!tg4n4 z`R)=Z*d($mu3zKN3L;(C6|bA@}j28Mrfm=h+#Sl9g{$oG`U62tev zPNF(>=Cnti`0lO=>}i4*J3ZRct}@gig~45};6hpRK_nyy#g)6>0NX>w2HIj{%249G zh?&iOc23SpI8|;#7?c`uCIsyCa3!hxd<;61+w(jjStqV@9*s5o4vDHjLS7`O%E;2c zk8!!mMRwhYkS?wd0f#k9jIl7RDTDZ2AwUZfe};yloSas?vhNB-atR4(i=k4&>%7({ zk031o;apxWEFmmR5o)Baj^rhr(F;uccMdezUzjlPu8<$jNM3VsaglYMMi>jB=u2B;FT%WM5Qn1_lLugfh}-?oKOZlc?g5!FJHdo#Zw5{=9LFpf)xxr z+N&@=A_H}t>(lL;!{Ptv;OB=A2n1mU{#gK+Sv<6|x+YaQ36{%#Um7&;49u3p&vJ^0 zP$q@C>K@ky+8%$5iHULY>J#GQ(-`=d4K@fkTuCDg?X|OFgsYDMA+-tGQ})jy;NPrJ z^Pa-CGL@MPF>Mmh!}||z+^Dtgu|?r*?Csq^K`Wb405>W*hoNDDz^qH_28q``a3sy_ zmRU<+hBJ&Z_Wbcl78sPAO$x!Rh2Q-Jxq+6fvoN|TJ`T7F6rfCNtj6yyLGL60Mmfvf?dPebhZ2tFfV zQ1(1I@~L{LQv@Oy_xY{TXExOsn+cs2kI~d_-I{x+@DVtV@V;%QVY;A z*xO5SHyHyCRNW#13SxByMyWzHR!Bx245Z3)2mk&=#l+OQjOBY`H00%jmK5+jVnuC4 zkIPoKhWrp7aG;4b0h0zZIQ(4u?TWj*``7k%<&8R64#ddB)B2_m2{AD-ErG9yv?U@U za))6Bi0#*-$1=b*?r`33b@RfkM^)NiXq`j*x%=)c_1#h1r-@ z78Mgi@q@c&fMAA^?Ci|hb(3<-GXM@e%;$-S`j&qd>k9wHvAu$glaGx~b>EUE<|EjMrS4Q+d>fH%|7mDI5uR3y*} zFChL_f*MRZS%<)k6~c%1If!S(kRhc0OJk2)un@2EFvDX6ao{tML`Yj(TPz(SFE39K zP%__VYvEpzs5hp{7RZ<(6zPyd%$o(|qJRJXWeyGw+F8!8tyZC+y^{3q|X&(h19v)QjeF3o;?I0X@wRyby06qQ2TiR>Q6dquaL=u6{ z)$xVz+lFa^zNe=IC8eW-LoZCfi(u->{aUY0k`__8>GbohGBl>H^sBCUyjImDeFje% z?TG;>=0O#5GsB3mU#R6MI2gPhA~6%Zgv(TO1`NIP4a4GIVV}FfV@T_g;2-dNgMXX` z$R$OA1h2Ab2pih}|A_Mc@p#jJr2KzB-h_WB>c1avlDFN&m~e7Ddr);}04^icl(m#f I6)c1Q7m}XCL;wH) literal 0 HcmV?d00001 diff --git a/docs/speeches/2013-10-05_ossawards/ossawards-2013.xoj b/docs/speeches/2013-10-05_ossawards/ossawards-2013.xoj new file mode 100644 index 0000000000000000000000000000000000000000..ce55c8b15c696fea5bd8b9c3e2b695fed5790880 GIT binary patch literal 29096 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%0AEss$-`6tKHf!ll5U2jO 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 literal 0 HcmV?d00001 From 3759944a88cb54bb26a7a4fa6318ed85099f5a07 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 22 Nov 2013 09:33:05 +0100 Subject: [PATCH 291/548] add presentation for eth (to be hold in a few minutes) Signed-off-by: Nico Schottelius --- docs/speeches/2013-11-22_eth_linux_erfa.odp | Bin 0 -> 23648 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/speeches/2013-11-22_eth_linux_erfa.odp diff --git a/docs/speeches/2013-11-22_eth_linux_erfa.odp b/docs/speeches/2013-11-22_eth_linux_erfa.odp new file mode 100644 index 0000000000000000000000000000000000000000..8ddee6152376ff89feae0eb2bd8445978671c4cd GIT binary patch literal 23648 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 literal 0 HcmV?d00001 From 8a34b7dfeab4ac6b0f9641762fd85fef48daa838 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 22 Nov 2013 20:57:16 +0100 Subject: [PATCH 292/548] add final version of presentation + pdf variant Signed-off-by: Nico Schottelius --- docs/speeches/2013-11-22_eth_linux_erfa.odp | Bin 23648 -> 28518 bytes docs/speeches/2013-11-22_eth_linux_erfa.pdf | Bin 0 -> 307767 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/speeches/2013-11-22_eth_linux_erfa.pdf diff --git a/docs/speeches/2013-11-22_eth_linux_erfa.odp b/docs/speeches/2013-11-22_eth_linux_erfa.odp index 8ddee6152376ff89feae0eb2bd8445978671c4cd..71d4719b558fcdf2470a2aee1ef143b31cc76ad8 100644 GIT binary patch delta 24624 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 Y$Nv{SS!=MN1|e8Z4+pv3=CS9$0EV1OJ^%m! delta 19665 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 diff --git a/docs/speeches/2013-11-22_eth_linux_erfa.pdf b/docs/speeches/2013-11-22_eth_linux_erfa.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3c2430affc1c1fd60e8324646a73f7b3bcbe4ffd GIT binary patch literal 307767 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�yDiI=vf&v$2K1gHH7;E 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 Date: Mon, 25 Nov 2013 19:08:46 +0100 Subject: [PATCH 293/548] use printf instead of echo to avoid bash broken echo builtin Signed-off-by: Nico Schottelius --- 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 69f4d67a..1c46c16c 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -50,7 +50,7 @@ case "$state_should" in # line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g" -e 's/\\/\\\\/g') - echo "echo '$line_sanitised' >> $file" + echo "printf '%s\n' '$line_sanitised' >> $file" ;; absent) From 4302b7592daf6624ed263cf75056599cc65a56a9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 25 Nov 2013 19:09:20 +0100 Subject: [PATCH 294/548] prepare next release Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index eb756f07..e7d90609 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.3.6: +2.3.6: 2013-11-25 * New Type: __locale * Type __line: Ensure special characters are not interpreted From d1a569fecd0b48ef7bac35ed5e01621c58d2ad28 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 25 Nov 2013 23:18:19 +0100 Subject: [PATCH 295/548] remove bug comments -> no bug here Signed-off-by: Nico Schottelius --- cdist/core/code.py | 5 +---- cdist/core/manifest.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/cdist/core/code.py b/cdist/core/code.py index d5f59094..910d1c47 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -119,9 +119,6 @@ class Code(object): 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! - # FIXME: BUG2: we are called AFTER the code-remote has been transferred already: - # mkdir: cannot create directory `/var/lib/cdist/object/__directory/etc/acpi/actions/.cdist/code-remote': File exists - # OR: this is from previous run -> cleanup missing! self.remote.mkdir(destination) self.remote.transfer(source, destination) diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 97121474..6bb33bb3 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # From ca1c5ff71360459c90147383a229c1873c912ca7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 26 Nov 2013 00:25:00 +0100 Subject: [PATCH 296/548] add another log for notifications Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-11-25.notifications | 50 ++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 docs/dev/logs/2013-11-25.notifications diff --git a/docs/dev/logs/2013-11-25.notifications b/docs/dev/logs/2013-11-25.notifications new file mode 100644 index 00000000..33c6f31b --- /dev/null +++ b/docs/dev/logs/2013-11-25.notifications @@ -0,0 +1,50 @@ +Follow up from 2013-01-20: + + - (re-)create message file per object? + - yes, but do not necessarily save in object space + - save $anywhere + + - object_run + - current notifications are imported into a file available at $__messages_in + - after object run, everything that has been written to $__messages_out is merged into the $__messages file + + - functions: + self.explorer.run_global_explorers(self.local.global_explorer_out_path) + self.manifest.run_initial_manifest(self.local.initial_manifest) + self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest)) + self.explorer.run_type_explorers(cdist_object) + self.manifest.run_type_manifest(cdist_object) + self.local.run_script(type_manifest, env=self.env_type_manifest(cdist_object)) + self.code.run_gencode_local(cdist_object) + self.local.run_script(script, env=env, return_output=True) + self.code.run_gencode_remote(cdist_object) + self.local.run_script(script, env=env, return_output=True) + + + - message support in ... + - initialmanifest - yes + - explorer - no + - only locally - yes + + - how to use notification / messaging in cdist + - can be used in all local scripts: + - initial manifest + - type manifest + - type gencode-* + - order of object exeution is random or as you requested using require="" + + - example use: + +__file/gencode-local: + if [ "$local_cksum" != "$remote_cksum" ]; then + echo "$__remote_copy" "$source" "${__target_host}:${destination}" + echo "copy" >> "$__messages_out" + fi + +__nginx/manifest: + __file /etc/nginx/sites-enabled/myfile --source "$__type/files/nginx-config" + +__nginx/gencode-remote: + if grep -q "__file/etc/nginx/sites-enabled/myfile:copy" "$__messages_in"; then + echo /etc/init.d/nginx restart + fi From 22a83d2c9365ce757d6d01fd70bf97b7e7a52f83 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 26 Nov 2013 00:27:08 +0100 Subject: [PATCH 297/548] add new message object Signed-off-by: Nico Schottelius --- cdist/core/message.py | 66 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 cdist/core/message.py diff --git a/cdist/core/message.py b/cdist/core/message.py new file mode 100644 index 00000000..50f039f4 --- /dev/null +++ b/cdist/core/message.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +# +# 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 logging +import shutil +import tempfile + +import cdist + +log = logging.getLogger(__name__) + + +class Message(object): + """Support messaging between types + + """ + def __init__(self, prefix, global_messages): + self.prefix = prefix + self.global_messages = global_messages + + self.messages_in = tempfile.mkstemp(suffix='.cdist_message_in') + self.messages_out = tempfile.mkstemp(suffix='.cdist_message_out') + + shutil.copyfile(self.global_messages, self.messages_in) + + @property + def env(self, env): + env = {} + env['__messages_in'] = self.messages_in + env['__messages_out'] = self.messages_out + + return env + + def _cleanup(self): + os.remove(self.messages_in) + os.remove(self.messages_out) + + def _merge_messages(self): + with open(self.messages_in) as fd: + content = fd.readlines() + + with open(self.global_messages, 'a') as fd: + for line in content: + fd.write("%s:%s" % (self.prefix, line)) + + def merge_messages(self): + self._merge_messages() + self._cleanup() From ac5fa7cd6461717e6f82fc10dece2b16405b38b8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 26 Nov 2013 01:01:30 +0100 Subject: [PATCH 298/548] integrate messaging into cdist Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 11 ++++- cdist/{core => }/message.py | 26 +++++++---- cdist/test/message/__init__.py | 82 ++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 10 deletions(-) rename cdist/{core => }/message.py (77%) create mode 100644 cdist/test/message/__init__.py diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 3a3ac706..b0109a4e 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -44,9 +44,11 @@ class Local(object): exec_path=sys.argv[0], initial_manifest=None, base_path=None, - add_conf_dirs=None): + add_conf_dirs=None, + message_prefix=None): self.target_host = target_host + self.message_prefix=message_prefix # FIXME: stopped: create base that does not require moving later if base_path: @@ -92,6 +94,7 @@ class Local(object): self.conf_path = os.path.join(self.base_path, "conf") 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") # Depending on conf_path self.global_explorer_path = os.path.join(self.conf_path, "explorer") @@ -163,6 +166,9 @@ class Local(object): # Export __target_host for use in __remote_{copy,exec} scripts env['__target_host'] = self.target_host + if self.message_prefix: + message = cdist.Message(self.message_prefix, self.messages_path) + try: if return_output: return subprocess.check_output(command, env=env).decode() @@ -172,6 +178,9 @@ class Local(object): raise cdist.Error("Command failed: " + " ".join(command)) except OSError as error: raise cdist.Error(" ".join(*args) + ": " + error.args[1]) + finally: + if self.message_prefix: + message.merge_messages() def run_script(self, script, env=None, return_output=False): """Run the given script with the given environment. diff --git a/cdist/core/message.py b/cdist/message.py similarity index 77% rename from cdist/core/message.py rename to cdist/message.py index 50f039f4..057c43d3 100644 --- a/cdist/core/message.py +++ b/cdist/message.py @@ -20,6 +20,7 @@ # import logging +import os import shutil import tempfile @@ -32,29 +33,36 @@ class Message(object): """Support messaging between types """ - def __init__(self, prefix, global_messages): + def __init__(self, prefix, messages): self.prefix = prefix - self.global_messages = global_messages + self.global_messages = messages - self.messages_in = tempfile.mkstemp(suffix='.cdist_message_in') - self.messages_out = tempfile.mkstemp(suffix='.cdist_message_out') + self.messages_in = tempfile.mkstemp(suffix='.cdist_message_in')[1] + self.messages_out = tempfile.mkstemp(suffix='.cdist_message_out')[1] + + self._copy_messages() - shutil.copyfile(self.global_messages, self.messages_in) @property - def env(self, env): + def env(self): env = {} env['__messages_in'] = self.messages_in env['__messages_out'] = self.messages_out return env + def _copy_messages(self): + """Copy global contents into our copy""" + shutil.copyfile(self.global_messages, self.messages_in) + def _cleanup(self): - os.remove(self.messages_in) - os.remove(self.messages_out) + if os.path.exists(self.messages_in): + os.remove(self.messages_in) + if os.path.exists(self.messages_out): + os.remove(self.messages_out) def _merge_messages(self): - with open(self.messages_in) as fd: + with open(self.messages_out) as fd: content = fd.readlines() with open(self.global_messages, 'a') as fd: diff --git a/cdist/test/message/__init__.py b/cdist/test/message/__init__.py new file mode 100644 index 00000000..653847f1 --- /dev/null +++ b/cdist/test/message/__init__.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# +# 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 tempfile + +from cdist import test +import cdist.message + +class MessageTestCase(test.CdistTestCase): + + def setUp(self): + 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) + + def tearDown(self): + os.remove(self.tempfile) + self.message._cleanup() + + def test_env(self): + """ + Ensure environment is correct + """ + + env = self.message.env + + self.assertIn('__messages_in', env) + self.assertIn('__messages_out', env) + + + def test_copy_content(self): + """ + Ensure content copying is working + """ + + with open(self.tempfile, "w") as fd: + fd.write(self.content) + + self.message._copy_messages() + + with open(self.tempfile, "r") as fd: + testcontent = fd.read() + + self.assertEqual(self.content, testcontent) + + def test_message_merge_prefix(self): + """Ensure messages are merged and are prefixed""" + + expectedcontent = "%s:%s" % (self.prefix, self.content) + + out = self.message.env['__messages_out'] + + with open(out, "w") as fd: + fd.write(self.content) + + self.message._merge_messages() + + with open(self.tempfile, "r") as fd: + testcontent = fd.read() + + self.assertEqual(expectedcontent, testcontent) From edec2abb1d583a12fa31f4645f8bd6037d8edb27 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 26 Nov 2013 01:01:44 +0100 Subject: [PATCH 299/548] adopt first type: __file for messaging Signed-off-by: Nico Schottelius --- cdist/conf/type/__file/gencode-local | 2 +- cdist/conf/type/__file/gencode-remote | 11 +++++++---- cdist/conf/type/__file/man.text | 11 ++++++++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 99456c5b..8cd9b24e 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -41,7 +41,7 @@ if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then if [ "$local_cksum" != "$remote_cksum" ]; then echo "$__remote_copy" "$source" "${__target_host}:${destination}" - echo "copy" >> "$__object/notifications" + echo "copy" >> "$__messages_out" fi else echo "Source \"$source\" does not exist." >&2 diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index fa2adc6f..6e1fa5be 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -38,20 +38,23 @@ case "$state_should" in # Group if [ -f "$__object/parameter/group" ]; then echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\" - echo "chgrp" >> "$__object/notifications" +# FIXME: only if necessary, not if parameter is present +# echo "chgrp" >> "$__object/notifications" fi # Owner if [ -f "$__object/parameter/owner" ]; then echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\" - echo "chown" >> "$__object/notifications" +# FIXME: only if necessary, not if parameter is present +# echo "chown" >> "$__object/notifications" fi # Mode - needs to happen last as a chown/chgrp can alter mode by # clearing S_ISUID and S_ISGID bits (see chown(2)) if [ -f "$__object/parameter/mode" ]; then echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" - echo "chmod" >> "$__object/notifications" +# FIXME: only if necessary, not if parameter is present +# echo "chmod" >> "$__object/notifications" fi ;; @@ -59,7 +62,7 @@ case "$state_should" in if [ "$exists" = "yes" ]; then echo rm -f \"$destination\" - echo "removal" >> "$__object/notifications" + echo "remove" >> "$__messages_out" fi ;; diff --git a/cdist/conf/type/__file/man.text b/cdist/conf/type/__file/man.text index 1c61fd51..9ac82d0f 100644 --- a/cdist/conf/type/__file/man.text +++ b/cdist/conf/type/__file/man.text @@ -41,6 +41,15 @@ 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. +MESSAGES +-------- + +copy:: + File was copied because cksum was different from local version + +remove:: + File exists, but state is absent, file will be removed by generated code. + EXAMPLES -------- @@ -81,5 +90,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +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). From 2f842d56eb1e55cf0fbbc6fbe35dc2faa7832f57 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 26 Nov 2013 01:17:37 +0100 Subject: [PATCH 300/548] integrate messaging into gencode, manifest Signed-off-by: Nico Schottelius --- cdist/core/code.py | 3 ++- cdist/core/manifest.py | 4 +++- cdist/exec/local.py | 23 ++++++++++++++--------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/cdist/core/code.py b/cdist/core/code.py index 910d1c47..f128697f 100644 --- a/cdist/core/code.py +++ b/cdist/core/code.py @@ -104,7 +104,8 @@ class Code(object): '__object_id': cdist_object.object_id, '__object_name': cdist_object.name, }) - return self.local.run_script(script, env=env, return_output=True) + 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.""" diff --git a/cdist/core/manifest.py b/cdist/core/manifest.py index 6bb33bb3..95bf4c25 100644 --- a/cdist/core/manifest.py +++ b/cdist/core/manifest.py @@ -122,7 +122,8 @@ class Manifest(object): if not os.path.isfile(initial_manifest): raise NoInitialManifestError(initial_manifest, user_supplied) - self.local.run_script(initial_manifest, env=self.env_initial_manifest(initial_manifest)) + 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) @@ -141,5 +142,6 @@ class Manifest(object): def run_type_manifest(self, cdist_object): 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)) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index b0109a4e..28c50eec 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -30,6 +30,7 @@ import logging import tempfile import cdist +import cdist.message from cdist import core class Local(object): @@ -44,11 +45,9 @@ class Local(object): exec_path=sys.argv[0], initial_manifest=None, base_path=None, - add_conf_dirs=None, - message_prefix=None): + add_conf_dirs=None): self.target_host = target_host - self.message_prefix=message_prefix # FIXME: stopped: create base that does not require moving later if base_path: @@ -131,6 +130,7 @@ class Local(object): def create_files_dirs(self): self._init_directories() self._create_conf_path_and_link_conf_dirs() + self._create_messages() self._link_types_for_emulator() @@ -153,7 +153,7 @@ 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): + def run(self, command, env=None, return_output=False, message_prefix=None): """Run the given command with the given environment. Return the output as a string. @@ -166,8 +166,8 @@ class Local(object): # Export __target_host for use in __remote_{copy,exec} scripts env['__target_host'] = self.target_host - if self.message_prefix: - message = cdist.Message(self.message_prefix, self.messages_path) + if message_prefix: + message = cdist.message.Message(message_prefix, self.messages_path) try: if return_output: @@ -179,10 +179,10 @@ class Local(object): except OSError as error: raise cdist.Error(" ".join(*args) + ": " + error.args[1]) finally: - if self.message_prefix: + if message_prefix: message.merge_messages() - def run_script(self, script, env=None, return_output=False): + 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. @@ -190,7 +190,7 @@ class Local(object): command = ["/bin/sh", "-e"] command.append(script) - return self.run(command, env, return_output) + 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.target_host) @@ -199,6 +199,11 @@ class Local(object): shutil.rmtree(destination) shutil.move(self.base_path, destination) + def _create_messages(self): + """Create empty messages""" + with open(self.messages_path, "w"): + pass + def _create_conf_path_and_link_conf_dirs(self): # Link destination directories for sub_dir in [ "explorer", "manifest", "type" ]: From db29ea8e7020b0850671aac9b8e9e142e7b0e960 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 12 Sep 2013 14:02:33 +0200 Subject: [PATCH 301/548] intial take on fixing the file type - upload file in a safer way - remove destination if it is not a file - only set attributes if required Signed-off-by: Steven Armstrong --- cdist/conf/type/__file/explorer/exists | 30 ------ cdist/conf/type/__file/explorer/stat | 30 ++++++ cdist/conf/type/__file/explorer/type | 16 ++++ cdist/conf/type/__file/gencode-local | 47 ++++++---- cdist/conf/type/__file/gencode-remote | 93 +++++++++++++------ cdist/conf/type/__file/man.text | 9 ++ .../conf/type/__file/parameter/default/state | 1 + 7 files changed, 150 insertions(+), 76 deletions(-) delete mode 100755 cdist/conf/type/__file/explorer/exists create mode 100755 cdist/conf/type/__file/explorer/stat create mode 100755 cdist/conf/type/__file/explorer/type create mode 100644 cdist/conf/type/__file/parameter/default/state diff --git a/cdist/conf/type/__file/explorer/exists b/cdist/conf/type/__file/explorer/exists deleted file mode 100755 index c319cb5d..00000000 --- a/cdist/conf/type/__file/explorer/exists +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -# -# 2011-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 . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" - -if [ -e "$destination" ]; then - echo yes -else - echo no -fi diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat new file mode 100755 index 00000000..40a00aba --- /dev/null +++ b/cdist/conf/type/__file/explorer/stat @@ -0,0 +1,30 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist armstrong.cc) + +destination="/$__object_id" + +# nothing to work with, nothing we could do +[ -e "$destination" ] || exit 0 + +os=$("$__explorer/os") +case "$os" in + "freebsd") + # 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" + ;; + *) + stat --printf="type: %F +owner: %u %U +group: %g %G +mode: %a %A +size: %s +links: %h +" "$destination" + ;; +esac diff --git a/cdist/conf/type/__file/explorer/type b/cdist/conf/type/__file/explorer/type new file mode 100755 index 00000000..6e6a2956 --- /dev/null +++ b/cdist/conf/type/__file/explorer/type @@ -0,0 +1,16 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist armstrong.cc) + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + echo file +elif [ -d "$destination" ]; then + echo directory +else + echo unknown +fi diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 087011c4..80a2bc20 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -17,34 +18,46 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# __file is a very basic type, which will probably be reused quite often -# destination="/$__object_id" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -exists="$(cat "$__object/explorer/exists")" +state_should="$(cat "$__object/parameter/state")" +type="$(cat "$__object/explorer/type")" -[ "$state_should" = "exists" -a "$exists" = "yes" ] && exit 0 # nothing to do +[ "$state_should" = "exists" -a "$type" = "file" ] && exit 0 # nothing to do +upload_file= +create_file= if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then - if [ -f "$__object/parameter/source" ]; then + if [ ! -f "$__object/parameter/source" ]; then + create_file=1 + else source="$(cat "$__object/parameter/source")" if [ "$source" = "-" ]; then source="$__object/stdin" fi - - if [ -f "$source" ]; then - local_cksum="$(cksum < "$source")" - remote_cksum="$(cat "$__object/explorer/cksum")" - - if [ "$local_cksum" != "$remote_cksum" ]; then - echo "$__remote_copy" "$source" "${__target_host}:${destination}" - fi - else + if [ ! -f "$source" ]; then echo "Source \"$source\" does not exist." >&2 exit 1 + else + if [ "$type" != "file" ]; then + # destination is not a regular file, upload source to replace it + upload_file=1 + else + local_cksum="$(cksum < "$source")" + remote_cksum="$(cat "$__object/explorer/cksum")" + if [ "$local_cksum" != "$remote_cksum" ]; then + # destination is a regular file, but not the right one + upload_file=1 + fi + fi + fi + fi + if [ "$create_file" -o "$upload_file" ]; then + mkdir "$__object/files" + tempfile_template="${destination}.cdist.XXXXXXXXXX" + echo "$__remote_exec ${__target_host} \"mktemp $tempfile_template\" > \"$__object/files/destination_upload\"" + if [ "$upload_file" ]; then + echo "$__remote_copy $source ${__target_host}:\$(cat \"$__object/files/destination_upload\")" fi fi fi diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 8b03e919..b0f7757f 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -17,52 +18,86 @@ # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # -# -# __file is a very basic type, which will probably be reused quite often -# destination="/$__object_id" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -exists="$(cat "$__object/explorer/exists")" +state_should="$(cat "$__object/parameter/state")" +type="$(cat "$__object/explorer/type")" +stat_file="$__object/explorer/stat" + +get_current_value() { + if [ -s "$stat_file" ]; then + _name="$1" + _value="$2" + case "$_value" in + [0-9]*) + _index=2 + ;; + *) + _index=3 + ;; + esac + awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" + unset _name _value _index + fi +} + +set_group() { + echo chgrp \"$1\" \"$destination\" +} + +set_owner() { + echo chown \"$1\" \"$destination\" +} + +set_mode() { + echo chmod \"$1\" \"$destination\" +} + +set_attributes= case "$state_should" in present|exists) - # No source? Create empty file - if [ ! -f "$__object/parameter/source" ]; then - if [ "$exists" = "no" ]; then - echo touch \"$destination\" + if [ -f "$__object/files/destination_upload" ]; then + # we uploaded a file, move it into place and set all attributes + destination_upload="$(cat "$__object/files/destination_upload")" + set_attributes=1 + if [ "$type" = "directory" ]; then + # our destination is currently a directory, move it out of the way, + # then delete it after moving our upload into place + cat << DONE +destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")" +mv "$destination" "$destination_old" +mv "$destination_upload" "$destination" +rm -rf "$destination_old" +DONE + else + # move our upload into place + echo "mv \"$destination_upload\" \"$destination\"" fi fi - # Group - if [ -f "$__object/parameter/group" ]; then - echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\" - fi - - # Owner - if [ -f "$__object/parameter/owner" ]; then - echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\" - fi - - # Mode - needs to happen last as a chown/chgrp can alter mode by - # clearing S_ISUID and S_ISGID bits (see chown(2)) - if [ -f "$__object/parameter/mode" ]; then - echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\" - fi + # Note: Mode - needs to happen last as a chown/chgrp can alter mode by + # clearing S_ISUID and S_ISGID bits (see chown(2)) + for attribute in group owner mode; do + if [ -f "$__object/parameter/$attribute" ]; then + value_should="$(cat "$__object/parameter/$attribute")" + value_is="$(get_current_value "$attribute" "$value_should")" + if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then + "set_$attribute" "$value_should" + fi + fi + done ;; absent) - - if [ "$exists" = "yes" ]; then + # FIXME: only delete if it's a file? or no matter what? + if [ "$type" = "file" ]; then echo rm -f \"$destination\" fi - ;; *) echo "Unknown state: $state_should" >&2 exit 1 ;; - esac diff --git a/cdist/conf/type/__file/man.text b/cdist/conf/type/__file/man.text index 1c61fd51..7cbde0ce 100644 --- a/cdist/conf/type/__file/man.text +++ b/cdist/conf/type/__file/man.text @@ -13,6 +13,15 @@ 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 ------------------- diff --git a/cdist/conf/type/__file/parameter/default/state b/cdist/conf/type/__file/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__file/parameter/default/state @@ -0,0 +1 @@ +present From 12ef3ca4d2766fae030790a52b6dff189dcc85dc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 12 Sep 2013 16:16:18 +0200 Subject: [PATCH 302/548] first generate and execute *-local, then *-remote Signed-off-by: Steven Armstrong --- cdist/config.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 7e003835..89f3e325 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -248,23 +248,29 @@ class Config(object): cdist_type = cdist_object.cdist_type - # Generate self.log.info("Generating and executing 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 not self.dry_run: - if cdist_object.code_local: + # local + cdist_object.code_local = self.code.run_gencode_local(cdist_object) + if cdist_object.code_local: + cdist_object.changed = True + if not self.dry_run: self.code.run_code_local(cdist_object) - if cdist_object.code_remote: + else: + self.log.info("Skipping code execution due to DRY RUN") + + # remote + cdist_object.code_remote = self.code.run_gencode_remote(cdist_object) + if cdist_object.code_remote: + cdist_object.changed = True + if not self.dry_run: 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") + else: + self.log.info("Skipping code execution due to DRY RUN") + if cdist_object.code_local or cdist_object.code_remote: + cdist_object.changed = True # Mark this object as done self.log.debug("Finishing run of " + cdist_object.name) From 5918de368d7541c051a83c340143f332f94e7631 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 18 Sep 2013 10:44:52 +0200 Subject: [PATCH 303/548] fix quoting, remove redundant code Signed-off-by: Steven Armstrong --- cdist/conf/type/__file/gencode-remote | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index b0f7757f..09f8e018 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -63,16 +63,22 @@ case "$state_should" in set_attributes=1 if [ "$type" = "directory" ]; then # our destination is currently a directory, move it out of the way, - # then delete it after moving our upload into place cat << DONE destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")" -mv "$destination" "$destination_old" -mv "$destination_upload" "$destination" -rm -rf "$destination_old" +mv "$destination" "\$destination_old" +DONE + fi + + # move our upload into place + cat << DONE +mv "$destination_upload" "$destination" +DONE + + if [ "$type" = "directory" ]; then + # delete the legacy directory + cat << DONE +rm -rf "\$destination_old" DONE - else - # move our upload into place - echo "mv \"$destination_upload\" \"$destination\"" fi fi From f82c4dc6694bf63fc1fcb868126b28c855ca108e Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 14 Oct 2013 21:17:59 +0200 Subject: [PATCH 304/548] no late delete Signed-off-by: Steven Armstrong --- cdist/conf/type/__file/gencode-remote | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 09f8e018..2e7ca633 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -62,24 +62,15 @@ case "$state_should" in destination_upload="$(cat "$__object/files/destination_upload")" set_attributes=1 if [ "$type" = "directory" ]; then - # our destination is currently a directory, move it out of the way, + # our destination is currently a directory, delete it cat << DONE -destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")" -mv "$destination" "\$destination_old" +rm -rf "$destination" DONE fi - # move our upload into place cat << DONE mv "$destination_upload" "$destination" DONE - - if [ "$type" = "directory" ]; then - # delete the legacy directory - cat << DONE -rm -rf "\$destination_old" -DONE - fi fi # Note: Mode - needs to happen last as a chown/chgrp can alter mode by @@ -96,7 +87,6 @@ DONE ;; absent) - # FIXME: only delete if it's a file? or no matter what? if [ "$type" = "file" ]; then echo rm -f \"$destination\" fi From a3dea70a97e60917f1e2f124985f7b77a0193feb Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 26 Nov 2013 16:14:44 +0100 Subject: [PATCH 305/548] Revert "first generate and execute *-local, then *-remote" This reverts commit cf22499538266b1b4fac1694254edfd8ba9be68d. --- cdist/config.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/cdist/config.py b/cdist/config.py index 89f3e325..7e003835 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -248,30 +248,24 @@ class Config(object): cdist_type = cdist_object.cdist_type + # Generate self.log.info("Generating and executing code for %s" % (cdist_object.name)) - - # local cdist_object.code_local = self.code.run_gencode_local(cdist_object) - if cdist_object.code_local: - cdist_object.changed = True - if not self.dry_run: - self.code.run_code_local(cdist_object) - else: - self.log.info("Skipping code execution due to DRY RUN") - - # remote cdist_object.code_remote = self.code.run_gencode_remote(cdist_object) - if cdist_object.code_remote: - cdist_object.changed = True - if not self.dry_run: - 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") - if cdist_object.code_local or cdist_object.code_remote: cdist_object.changed = True + # Execute + if not self.dry_run: + if cdist_object.code_local: + self.code.run_code_local(cdist_object) + if cdist_object.code_remote: + 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") + + # Mark this object as done self.log.debug("Finishing run of " + cdist_object.name) cdist_object.state = core.CdistObject.STATE_DONE From fcfd2d0a3c6410f73b73cd897f5dd09526868f35 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 26 Nov 2013 16:30:03 +0100 Subject: [PATCH 306/548] refactor so that there is no interaction between code-local and code-remote Signed-off-by: Steven Armstrong --- cdist/conf/type/__file/gencode-local | 17 +++++++++++++++-- cdist/conf/type/__file/gencode-remote | 18 +----------------- cdist/config.py | 4 +++- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index 80a2bc20..a9eb6b10 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -53,11 +53,24 @@ if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then fi fi if [ "$create_file" -o "$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" + touch "$__object/files/set-attributes" + + # upload file to temp location tempfile_template="${destination}.cdist.XXXXXXXXXX" - echo "$__remote_exec ${__target_host} \"mktemp $tempfile_template\" > \"$__object/files/destination_upload\"" + cat << DONE +destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template")" +DONE if [ "$upload_file" ]; then - echo "$__remote_copy $source ${__target_host}:\$(cat \"$__object/files/destination_upload\")" + cat << DONE +$__remote_copy $source ${__target_host}:\$destination_upload +DONE fi +# move uploaded file into place +cat << DONE +$__remote_exec $__target_host "rm -rf \"$destination\"; mv \"\$destination_upload\" \"$destination\"" +DONE fi fi diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 2e7ca633..e80d5fae 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -57,29 +57,13 @@ set_mode() { set_attributes= case "$state_should" in present|exists) - if [ -f "$__object/files/destination_upload" ]; then - # we uploaded a file, move it into place and set all attributes - destination_upload="$(cat "$__object/files/destination_upload")" - set_attributes=1 - if [ "$type" = "directory" ]; then - # our destination is currently a directory, delete it - cat << DONE -rm -rf "$destination" -DONE - fi - # move our upload into place - cat << DONE -mv "$destination_upload" "$destination" -DONE - fi - # Note: Mode - needs to happen last as a chown/chgrp can alter mode by # clearing S_ISUID and S_ISGID bits (see chown(2)) for attribute in group owner mode; do if [ -f "$__object/parameter/$attribute" ]; then value_should="$(cat "$__object/parameter/$attribute")" value_is="$(get_current_value "$attribute" "$value_should")" - if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then + if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then "set_$attribute" "$value_should" fi fi diff --git a/cdist/config.py b/cdist/config.py index 7e003835..3f8a7fc6 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -249,7 +249,7 @@ class Config(object): cdist_type = cdist_object.cdist_type # Generate - self.log.info("Generating and executing code for %s" % (cdist_object.name)) + self.log.info("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: @@ -257,6 +257,8 @@ 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)) if cdist_object.code_local: self.code.run_code_local(cdist_object) if cdist_object.code_remote: From dc27a15ec026ae8d4eeb73ae50c3931e2917bbe6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 27 Nov 2013 15:10:06 +0100 Subject: [PATCH 307/548] ++changes(2.3.7) Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index e7d90609..7dfaefb2 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +2.3.7: + * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) + 2.3.6: 2013-11-25 * New Type: __locale * Type __line: Ensure special characters are not interpreted From 6c3b1e3ca0369e9e46e9088467efe7d7d875f178 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 27 Nov 2013 16:05:10 +0100 Subject: [PATCH 308/548] add gpl header Signed-off-by: Steven Armstrong --- cdist/conf/type/__file/explorer/stat | 17 +++++++++++++++++ cdist/conf/type/__file/explorer/type | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat index 40a00aba..298221b7 100755 --- a/cdist/conf/type/__file/explorer/stat +++ b/cdist/conf/type/__file/explorer/stat @@ -1,5 +1,22 @@ #!/bin/sh +# # 2013 Steven Armstrong (steven-cdist 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 . +# destination="/$__object_id" diff --git a/cdist/conf/type/__file/explorer/type b/cdist/conf/type/__file/explorer/type index 6e6a2956..e723047c 100755 --- a/cdist/conf/type/__file/explorer/type +++ b/cdist/conf/type/__file/explorer/type @@ -1,5 +1,22 @@ #!/bin/sh +# # 2013 Steven Armstrong (steven-cdist 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 . +# destination="/$__object_id" From d7984df503a888b3ab889ac4aaaa0993e5dbfee4 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 18 Sep 2013 11:14:18 +0200 Subject: [PATCH 309/548] make explorers executable Signed-off-by: Steven Armstrong --- cdist/conf/type/__directory/explorer/group | 0 cdist/conf/type/__directory/explorer/mode | 0 cdist/conf/type/__directory/explorer/owner | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 cdist/conf/type/__directory/explorer/group mode change 100644 => 100755 cdist/conf/type/__directory/explorer/mode mode change 100644 => 100755 cdist/conf/type/__directory/explorer/owner diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner old mode 100644 new mode 100755 From 7b065e931f78d9b0031a407fa4b364ea7af3b180 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 18 Sep 2013 13:25:45 +0200 Subject: [PATCH 310/548] rewrite type to work analog to __file and __link Signed-off-by: Steven Armstrong --- cdist/conf/type/__directory/explorer/group | 39 ------ cdist/conf/type/__directory/explorer/mode | 39 ------ cdist/conf/type/__directory/explorer/owner | 39 ------ cdist/conf/type/__directory/explorer/stat | 26 ++++ cdist/conf/type/__directory/explorer/state | 30 ----- cdist/conf/type/__directory/explorer/type | 16 +++ cdist/conf/type/__directory/gencode-remote | 116 +++++++++++------- .../type/__directory/parameter/default/state | 1 + 8 files changed, 117 insertions(+), 189 deletions(-) delete mode 100755 cdist/conf/type/__directory/explorer/group delete mode 100755 cdist/conf/type/__directory/explorer/mode delete mode 100755 cdist/conf/type/__directory/explorer/owner create mode 100755 cdist/conf/type/__directory/explorer/stat delete mode 100755 cdist/conf/type/__directory/explorer/state create mode 100755 cdist/conf/type/__directory/explorer/type create mode 100644 cdist/conf/type/__directory/parameter/default/state diff --git a/cdist/conf/type/__directory/explorer/group b/cdist/conf/type/__directory/explorer/group deleted file mode 100755 index e5be37da..00000000 --- a/cdist/conf/type/__directory/explorer/group +++ /dev/null @@ -1,39 +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 . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" -os=$("$__explorer/os") - -case "$os" in - "freebsd") - cmd="stat -f %Sg" - ;; - *) - cmd="stat -c %G" - ;; -esac - -if [ -e "$destination" ]; then - $cmd "$destination" -fi - diff --git a/cdist/conf/type/__directory/explorer/mode b/cdist/conf/type/__directory/explorer/mode deleted file mode 100755 index f75b282b..00000000 --- a/cdist/conf/type/__directory/explorer/mode +++ /dev/null @@ -1,39 +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 . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" -os=$("$__explorer/os") - -case "$os" in - "freebsd") - cmd="stat -f %Op" - ;; - *) - cmd="stat -c %a" - ;; -esac - -if [ -e "$destination" ]; then - $cmd "$destination" -fi - diff --git a/cdist/conf/type/__directory/explorer/owner b/cdist/conf/type/__directory/explorer/owner deleted file mode 100755 index cebd199b..00000000 --- a/cdist/conf/type/__directory/explorer/owner +++ /dev/null @@ -1,39 +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 . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" -os=$("$__explorer/os") - -case "$os" in - "freebsd") - cmd="stat -f %Su" - ;; - *) - cmd="stat -c %U" - ;; -esac - -if [ -e "$destination" ]; then - $cmd "$destination" -fi - diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat new file mode 100755 index 00000000..2bd5d1c9 --- /dev/null +++ b/cdist/conf/type/__directory/explorer/stat @@ -0,0 +1,26 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist armstrong.cc) + +destination="/$__object_id" + +# nothing to work with, nothing we could do +[ -e "$destination" ] || exit 0 + +os=$("$__explorer/os") +case "$os" in + "freebsd") + # 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 +" "$destination" + ;; + *) + stat --printf="type: %F +owner: %u %U +group: %g %G +mode: %a %A +" "$destination" + ;; +esac diff --git a/cdist/conf/type/__directory/explorer/state b/cdist/conf/type/__directory/explorer/state deleted file mode 100755 index 9bdd9024..00000000 --- a/cdist/conf/type/__directory/explorer/state +++ /dev/null @@ -1,30 +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 . -# -# -# Check whether file exists or not -# - -destination="/$__object_id" - -if [ -e "$destination" ]; then - echo present -else - echo absent -fi diff --git a/cdist/conf/type/__directory/explorer/type b/cdist/conf/type/__directory/explorer/type new file mode 100755 index 00000000..6e6a2956 --- /dev/null +++ b/cdist/conf/type/__directory/explorer/type @@ -0,0 +1,16 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist armstrong.cc) + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + echo file +elif [ -d "$destination" ]; then + echo directory +else + echo unknown +fi diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index f46a5967..ebe07318 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -19,53 +20,84 @@ # destination="/$__object_id" +state_should="$(cat "$__object/parameter/state")" +type="$(cat "$__object/explorer/type")" +stat_file="$__object/explorer/stat" -state_is="$(cat "$__object/explorer/state")" -owner_is="$(cat "$__object/explorer/owner")" -group_is="$(cat "$__object/explorer/group")" -mode_is="$(cat "$__object/explorer/mode")" +# variable to keep track if we have to set directory attributes +set_attributes= -state_should="present" -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" -mode="" -[ -f "$__object/parameter/mode" ] && mode="$(cat "$__object/parameter/mode")" -owner="" -[ -f "$__object/parameter/owner" ] && owner="$(cat "$__object/parameter/owner")" -group="" -[ -f "$__object/parameter/group" ] && group="$(cat "$__object/parameter/group")" mkdiropt="" -[ -f "$__object/parameter/parents" ] && mkdiropt="-p" +[ -f "$__object/parameter/parents" ] && mkdiropt="-p" + recursive="" -[ -f "$__object/parameter/recursive" ] && recursive="-R" +if [ -f "$__object/parameter/recursive" ]; then + recursive="-R" + # need to allways set attributes when recursive is given + # as we don't want to check all subfolders/files + set_attributes=1 +fi + +get_current_value() { + if [ -s "$stat_file" ]; then + _name="$1" + _value="$2" + case "$_value" in + [0-9]*) + _index=2 + ;; + *) + _index=3 + ;; + esac + awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" + unset _name _value _index + fi +} + +set_group() { + echo chgrp $recursive \"$1\" \"$destination\" +} + +set_owner() { + echo chown $recursive \"$1\" \"$destination\" +} + +set_mode() { + echo chmod $recursive \"$1\" \"$destination\" +} case "$state_should" in - present) - if [ "$state_is" != "present" ]; then - echo mkdir $mkdiropt \"$destination\" - fi + present) + if [ "$type" != "directory" ]; + # our destination is not a directory, remove whatever is there + # and then create our directory and set all attributes + set_attributes=1 + cat << DONE +rm -f "$destination" +mkdir "$mkdiropt" "$destination" +DONE + fi - # Mode settings - if [ "$mode" ] && [ "$mode_is" != "$mode" -o -n "$recursive" ]; then - echo chmod $recursive \"$mode\" \"$destination\" - fi - - # Group - if [ "$group" ] && [ "$group_is" != "$group" -o -n "$recursive" ]; then - echo chgrp $recursive \"$group\" \"$destination\" - fi - - # Owner - if [ "$owner" ] && [ "$owner_is" != "$owner" -o -n "$recursive" ]; then - echo chown $recursive \"$owner\" \"$destination\" - fi - ;; - absent) - if [ "$state_is" != "absent" ]; then - echo rm -rf \"$destination\" - fi - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + # 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 + if [ -f "$__object/parameter/$attribute" ]; then + value_should="$(cat "$__object/parameter/$attribute")" + value_is="$(get_current_value "$attribute" "$value_should")" + if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then + "set_$attribute" "$value_should" + fi + fi + done + ;; + absent) + if [ "$type" = "directory" ]; then + echo rm -rf \"$destination\" + fi + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/cdist/conf/type/__directory/parameter/default/state b/cdist/conf/type/__directory/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__directory/parameter/default/state @@ -0,0 +1 @@ +present From f5a39e52810cdefbdcd4b3cdc65aad2700555822 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 27 Nov 2013 16:06:34 +0100 Subject: [PATCH 311/548] add gpl header Signed-off-by: Steven Armstrong --- cdist/conf/type/__directory/explorer/stat | 17 +++++++++++++++++ cdist/conf/type/__directory/explorer/type | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat index 2bd5d1c9..d8cdbb9e 100755 --- a/cdist/conf/type/__directory/explorer/stat +++ b/cdist/conf/type/__directory/explorer/stat @@ -1,5 +1,22 @@ #!/bin/sh +# # 2013 Steven Armstrong (steven-cdist 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 . +# destination="/$__object_id" diff --git a/cdist/conf/type/__directory/explorer/type b/cdist/conf/type/__directory/explorer/type index 6e6a2956..e723047c 100755 --- a/cdist/conf/type/__directory/explorer/type +++ b/cdist/conf/type/__directory/explorer/type @@ -1,5 +1,22 @@ #!/bin/sh +# # 2013 Steven Armstrong (steven-cdist 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 . +# destination="/$__object_id" From 6d5686229fd6da683ef692301ab356251992acff Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 18 Sep 2013 10:40:29 +0200 Subject: [PATCH 312/548] only delete links; delete existing destination before creating links Signed-off-by: Steven Armstrong --- cdist/conf/type/__link/explorer/type | 26 ++++++++++++++++ cdist/conf/type/__link/gencode-remote | 30 ++++++++++++++++--- .../conf/type/__link/parameter/default/state | 1 + 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100755 cdist/conf/type/__link/explorer/type create mode 100644 cdist/conf/type/__link/parameter/default/state diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type new file mode 100755 index 00000000..c02b3af8 --- /dev/null +++ b/cdist/conf/type/__link/explorer/type @@ -0,0 +1,26 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist armstrong.cc) + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + type="$(cat "$__object/parameter/type")" + case "$type" in + hard) + link_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 +else + echo unknown +fi diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index 2975ef69..2e41b7d9 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -40,17 +41,38 @@ case "$type" in esac state_is="$(cat "$__object/explorer/state")" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" [ "$state_should" = "$state_is" ] && exit 0 +file_type="$(cat "$__object/explorer/type")" case "$state_should" in present) - echo ln ${lnopt} -f \"$source\" \"$destination\" + if [ "$file_type" = "directory" ]; then + # our destination is currently a directory, move it out of the way + cat << DONE +destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")" +mv "$destination" "\$destination_old" +DONE + fi + + # create our link + cat << DONE +ln ${lnopt} -f "$source" "$destination" +DONE + + if [ "$file_type" = "directory" ]; then + # delete the legacy directory + cat << DONE +rm -rf "\$destination_old" +DONE + fi ;; absent) - echo rm -f \"$destination\" + # only delete if it is a sym/hard link + if [ "$file_type" = "symlink" -o "$file_type" = "hardlink" ]; then + echo rm -f \"$destination\" + fi ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__link/parameter/default/state b/cdist/conf/type/__link/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__link/parameter/default/state @@ -0,0 +1 @@ +present From 71b41df73324fa2f423b21c7d81b9baa4d6b131b Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 15 Oct 2013 14:55:35 +0200 Subject: [PATCH 313/548] no late delete Signed-off-by: Steven Armstrong --- cdist/conf/type/__link/gencode-remote | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/cdist/conf/type/__link/gencode-remote b/cdist/conf/type/__link/gencode-remote index 2e41b7d9..cbdfd30f 100755 --- a/cdist/conf/type/__link/gencode-remote +++ b/cdist/conf/type/__link/gencode-remote @@ -49,10 +49,9 @@ file_type="$(cat "$__object/explorer/type")" case "$state_should" in present) if [ "$file_type" = "directory" ]; then - # our destination is currently a directory, move it out of the way + # our destination is currently a directory, delete it cat << DONE -destination_old="\$(mktemp "${destination}.cdist.XXXXXXXXXX")" -mv "$destination" "\$destination_old" +rm -rf "$destination" DONE fi @@ -60,13 +59,6 @@ DONE cat << DONE ln ${lnopt} -f "$source" "$destination" DONE - - if [ "$file_type" = "directory" ]; then - # delete the legacy directory - cat << DONE -rm -rf "\$destination_old" -DONE - fi ;; absent) # only delete if it is a sym/hard link From abf291cb20106dcfb7c50587e2cb3408a296cf9a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 27 Nov 2013 16:08:12 +0100 Subject: [PATCH 314/548] add gpl header Signed-off-by: Steven Armstrong --- cdist/conf/type/__link/explorer/type | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cdist/conf/type/__link/explorer/type b/cdist/conf/type/__link/explorer/type index c02b3af8..579fd081 100755 --- a/cdist/conf/type/__link/explorer/type +++ b/cdist/conf/type/__link/explorer/type @@ -1,5 +1,25 @@ #!/bin/sh +# # 2013 Steven Armstrong (steven-cdist 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 . +# +# +# Mostly a wrapper for ln +# destination="/$__object_id" From 61dc7291dce2e040b9d6ec026af506189b9d5694 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 27 Nov 2013 16:28:06 +0100 Subject: [PATCH 315/548] ++changes(2.3.7) Signed-off-by: Nico Schottelius --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 7dfaefb2..3c185d48 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,8 @@ Changelog 2.3.7: * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) + * Type __link: Only remove links when state is absent (Steven Armstrong) + * Type __directory: Only remove directories when state is absent (Steven Armstrong) 2.3.6: 2013-11-25 * New Type: __locale From bc9d40df372c0c2f97c1be4d0634958815e3340f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 28 Nov 2013 14:10:15 +0100 Subject: [PATCH 316/548] ignore lock files Signed-off-by: Nico Schottelius --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 76ed1fcb..63f8076a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ cdist/version.py build .lock-* .git-current-branch +.lock* From 8998ea929890e918eab76d84c6e2825a7a25d223 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 29 Nov 2013 16:02:17 +0100 Subject: [PATCH 317/548] ++changes(2.3.7) Signed-off-by: Nico Schottelius --- docs/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 3c185d48..ec584026 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,8 +6,9 @@ Changelog 2.3.7: * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) - * Type __link: Only remove links when state is absent (Steven Armstrong) - * Type __directory: Only remove directories when state is absent (Steven Armstrong) + * Type __file: Only remove file when state is absent (Steven Armstrong) + * Type __link: Only remove link when state is absent (Steven Armstrong) + * Type __directory: Only remove directory when state is absent (Steven Armstrong) 2.3.6: 2013-11-25 * New Type: __locale From 48923d23d88adb9052b17cec5e4ab49fbbc262cf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 1 Dec 2013 18:37:08 +0100 Subject: [PATCH 318/548] if ... THEN ;-) Signed-off-by: Nico Schottelius --- cdist/conf/type/__directory/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index ebe07318..23fa4ed3 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. @@ -69,7 +69,7 @@ set_mode() { case "$state_should" in present) - if [ "$type" != "directory" ]; + if [ "$type" != "directory" ]; then # our destination is not a directory, remove whatever is there # and then create our directory and set all attributes set_attributes=1 From 7cf0d60b085f29716597ce11748e290b12a7bbfc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 1 Dec 2013 18:42:07 +0100 Subject: [PATCH 319/548] catch permissionserror when deleting old cache Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 3a3ac706..88b49be9 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -186,8 +186,13 @@ class Local(object): def save_cache(self): destination = os.path.join(self.cache_path, self.target_host) self.log.debug("Saving " + self.base_path + " to " + destination) - if os.path.exists(destination): - shutil.rmtree(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)) + shutil.move(self.base_path, destination) def _create_conf_path_and_link_conf_dirs(self): From 538a5b4964db93afc070ea89b84ff3ce6109d1fa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 1 Dec 2013 18:42:43 +0100 Subject: [PATCH 320/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ec584026..67eaca1a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * Type __file: Only remove file when state is absent (Steven Armstrong) * Type __link: Only remove link when state is absent (Steven Armstrong) * Type __directory: Only remove directory when state is absent (Steven Armstrong) + * Core: Fix backtrace when cache cannot be deleted 2.3.6: 2013-11-25 * New Type: __locale From d074713b94f026e4de78bb3c07b777a3066e7d85 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 2 Dec 2013 13:27:42 +0100 Subject: [PATCH 321/548] Fix explorer and globalopts issue in type __package_zypper Fixes #215. Signed-off-by: Nico Schottelius --- cdist/conf/type/__package_zypper/explorer/pkg_version | 2 +- cdist/conf/type/__package_zypper/gencode-remote | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) mode change 100755 => 100644 cdist/conf/type/__package_zypper/explorer/pkg_version mode change 100755 => 100644 cdist/conf/type/__package_zypper/gencode-remote diff --git a/cdist/conf/type/__package_zypper/explorer/pkg_version b/cdist/conf/type/__package_zypper/explorer/pkg_version old mode 100755 new mode 100644 index fb3b7753..655b464d --- a/cdist/conf/type/__package_zypper/explorer/pkg_version +++ b/cdist/conf/type/__package_zypper/explorer/pkg_version @@ -27,4 +27,4 @@ else name="$__object_id" fi -rpm -q --whatprovides "$name" 2>/dev/null || true +rpm -q --whatprovides "$name" | grep -v 'no package provides' || true diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote old mode 100755 new mode 100644 index ca9aec33..d1766126 --- a/cdist/conf/type/__package_zypper/gencode-remote +++ b/cdist/conf/type/__package_zypper/gencode-remote @@ -39,15 +39,22 @@ else state_should="present" fi +pkg_version="$(cat "$__object/explorer/pkg_version")" +if [ -z "$pkg_version" ]; then + state_is="absent" +else + state_is="present" +fi + # Exit if nothing is needed to be done [ "$state_is" = "$state_should" ] && exit 0 case "$state_should" in present) - echo zypper "$globalopts" install --auto-agree-with-licenses \"$name\" + echo zypper $globalopts install --auto-agree-with-licenses \"$name\" ">/dev/null" ;; absent) - echo pacman "$globalopts" remove \"$name\" + echo zypper $globalopts remove \"$name\" ">/dev/null" ;; *) echo "Unknown state: $state_should" >&2 From 1b36ed88f0b8d6b10ff7ae9478b83d0603bd0398 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Dec 2013 13:29:17 +0100 Subject: [PATCH 322/548] ++changes(2.3.7) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 67eaca1a..25079179 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * Type __file: Only remove file when state is absent (Steven Armstrong) * Type __link: Only remove link when state is absent (Steven Armstrong) * Type __directory: Only remove directory when state is absent (Steven Armstrong) + * Type __package_zypper: Fix explorer and parameter issue (Daniel Heule) * Core: Fix backtrace when cache cannot be deleted 2.3.6: 2013-11-25 From 9d86f8c9b7f379c90522ce99d5abde3c43474531 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Dec 2013 15:16:31 +0100 Subject: [PATCH 323/548] 2.3.7 release Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 25079179..b6122bec 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -2.3.7: +2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) * Type __file: Only remove file when state is absent (Steven Armstrong) * Type __link: Only remove link when state is absent (Steven Armstrong) From a95167b374e4de8dd16423017a477e6336f2d05d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 2 Dec 2013 15:49:02 +0100 Subject: [PATCH 324/548] remove quotes from mkdiropt Signed-off-by: Nico Schottelius --- cdist/conf/type/__directory/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index 23fa4ed3..800fc6e4 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -75,7 +75,7 @@ case "$state_should" in set_attributes=1 cat << DONE rm -f "$destination" -mkdir "$mkdiropt" "$destination" +mkdir $mkdiropt "$destination" DONE fi From 90896a9e06b10a5daa26235420d08b745d771f3f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 3 Dec 2013 14:36:38 +0100 Subject: [PATCH 325/548] update environment with messages environment Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 1 + cdist/message.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 28c50eec..f1313eea 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -168,6 +168,7 @@ class Local(object): if message_prefix: message = cdist.message.Message(message_prefix, self.messages_path) + env.update(message.env) try: if return_output: diff --git a/cdist/message.py b/cdist/message.py index 057c43d3..b840a84d 100644 --- a/cdist/message.py +++ b/cdist/message.py @@ -56,12 +56,14 @@ class Message(object): shutil.copyfile(self.global_messages, self.messages_in) def _cleanup(self): + """remove temporary files""" if os.path.exists(self.messages_in): os.remove(self.messages_in) if os.path.exists(self.messages_out): os.remove(self.messages_out) def _merge_messages(self): + """merge newly written lines into global file""" with open(self.messages_out) as fd: content = fd.readlines() From 68b7392021b5e6311b3283ab22cbc46cf761b12e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 3 Dec 2013 15:41:43 +0100 Subject: [PATCH 326/548] add support for messaging to __file, document messaging in reference Signed-off-by: Nico Schottelius --- cdist/conf/type/__file/gencode-local | 2 ++ cdist/conf/type/__file/gencode-remote | 8 ++++++-- cdist/conf/type/__file/man.text | 14 ++++++++++---- docs/man/cdist-reference.text.sh | 8 +++++++- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local index a9eb6b10..601705c8 100755 --- a/cdist/conf/type/__file/gencode-local +++ b/cdist/conf/type/__file/gencode-local @@ -30,6 +30,7 @@ create_file= if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then if [ ! -f "$__object/parameter/source" ]; then create_file=1 + echo create >> "$__messages_out" else source="$(cat "$__object/parameter/source")" if [ "$source" = "-" ]; then @@ -64,6 +65,7 @@ if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template")" DONE if [ "$upload_file" ]; then + echo upload >> "$__messages_out" cat << DONE $__remote_copy $source ${__target_host}:\$destination_upload DONE diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index e80d5fae..57bf3503 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -43,15 +43,18 @@ get_current_value() { } set_group() { - echo chgrp \"$1\" \"$destination\" + echo chgrp \"$1\" \"$destination\" + echo chgrp $1 >> "$__messages_out" } set_owner() { - echo chown \"$1\" \"$destination\" + echo chown \"$1\" \"$destination\" + echo chown $1 >> "$__messages_out" } set_mode() { echo chmod \"$1\" \"$destination\" + echo chmod $1 >> "$__messages_out" } set_attributes= @@ -73,6 +76,7 @@ case "$state_should" in absent) if [ "$type" = "file" ]; then echo rm -f \"$destination\" + echo remove >> "$__messages_out" fi ;; diff --git a/cdist/conf/type/__file/man.text b/cdist/conf/type/__file/man.text index b76573bb..a582b27b 100644 --- a/cdist/conf/type/__file/man.text +++ b/cdist/conf/type/__file/man.text @@ -52,12 +52,18 @@ source:: MESSAGES -------- - -copy:: - File was copied because cksum was different from local version - +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 diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index b41be801..a72452eb 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# 2010-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -191,6 +191,12 @@ __manifest:: __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 From b29a52db1a954249cae052ff80c1df6cf3d56f80 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 4 Dec 2013 09:37:01 +0100 Subject: [PATCH 327/548] Initial add vom type __zypper_repo --- .../type/__zypper_repo/explorer/all_repo_ids | 3 + .../__zypper_repo/explorer/enabled_repo_ids | 3 + .../conf/type/__zypper_repo/explorer/repo_id | 8 ++ cdist/conf/type/__zypper_repo/gencode-remote | 94 +++++++++++++++++++ cdist/conf/type/__zypper_repo/man.text | 68 ++++++++++++++ .../__zypper_repo/parameter/default/state | 1 + .../type/__zypper_repo/parameter/optional | 4 + docs/man/man7/.directory | 4 + 8 files changed, 185 insertions(+) create mode 100644 cdist/conf/type/__zypper_repo/explorer/all_repo_ids create mode 100644 cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids create mode 100644 cdist/conf/type/__zypper_repo/explorer/repo_id create mode 100644 cdist/conf/type/__zypper_repo/gencode-remote create mode 100644 cdist/conf/type/__zypper_repo/man.text create mode 100644 cdist/conf/type/__zypper_repo/parameter/default/state create mode 100644 cdist/conf/type/__zypper_repo/parameter/optional create mode 100644 docs/man/man7/.directory diff --git a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids new file mode 100644 index 00000000..e1772956 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids @@ -0,0 +1,3 @@ +#!/bin/sh +# +echo $(zypper lr -u | 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 new file mode 100644 index 00000000..6ece6e05 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids @@ -0,0 +1,3 @@ +#!/bin/sh +# +echo $(zypper lr -E | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_repo/explorer/repo_id b/cdist/conf/type/__zypper_repo/explorer/repo_id new file mode 100644 index 00000000..aa1e5f99 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/explorer/repo_id @@ -0,0 +1,8 @@ +#!/bin/sh +# +if [ -f "$__object/parameter/repo_uri" ]; then + uri="$(cat "$__object/parameter/repo_uri")" +else + uri="/$__object_id" +fi +echo $(zypper lr -u | grep -E "\<$uri\>" | cut -d'|' -f 1 | grep -E '^[0-9]' ) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote new file mode 100644 index 00000000..b56518c9 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -0,0 +1,94 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Manage repo services with Zypper (mostly suse) +# + +# Debug +#exec >&2 +#set -x + +zypper_def_opts=" -q " + +if [ -f "$__object/parameter/repo_desc" ]; then + desc="$(cat "$__object/parameter/repo_desc")" +else + desc="$__object_id" +fi + +if [ -f "$__object/parameter/repo_uri" ]; then + uri="$(cat "$__object/parameter/repo_uri")" +else + uri="$__object_id" +fi + +if [ -f "$__object/parameter/repo_id" ]; then + id="$(cat "$__object/parameter/repo_id")" +else + id="$__object_id" +fi + +if [ -f "$__object/parameter/state" ]; then + state="$(cat "$__object/parameter/state")" +else + state="present" +fi + +all_repo_ids="$(cat "$__object/explorer/all_repo_ids")" +enabled_repo_ids="$(cat "$__object/explorer/enabled_repo_ids")" +repo_id="$(cat "$__object/explorer/repo_id")" + +act_id="" +if grep -q $id $__object/explorer/all_repo_ids; then + act_id="$id" +elif grep -q $repo_id $__object/explorer/all_repo_ids; then + act_id="$repo_id" +fi + +case "$state" in + present) + if [ -z "$desc" ] || [ -z "$uri" ]; then + echo "parameter repo_desc and repo_uri for $state needed" >&2 + exit 4 + fi + if [ -z "$repo_id" ]; then + echo zypper $zypper_def_opts addrepo "'$uri'" "'$desc'" + fi + ;; + absent) + if [ ! -z "$act_id" ]; then + echo zypper $zypper_def_opts removerepo $act_id + fi + ;; + enabled) + if [ ! -z "$act_id" ]; then + echo zypper $zypper_def_opts modifyrepo -e $act_id + fi + ;; + disabled) + if [ ! -z "$act_id" ]; then + echo zypper $zypper_def_opts modifyrepo -d $act_id + fi + ;; + *) + echo "Unknown state: $state" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__zypper_repo/man.text b/cdist/conf/type/__zypper_repo/man.text new file mode 100644 index 00000000..c5d23713 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/man.text @@ -0,0 +1,68 @@ +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 repositorys. + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +state:: + Either "present" or "absent" or "enabled" or "disabled", defaults to "present" + +repo_uri:: + If supplied, use the uri and not the object id as the repo uri. + +repo_desc:: + If supplied, use the description and not the object id as the repo description, only used for state present if the repo must created + +repo_id:: + If supplied, use the id and not the object id as the repo id, can be used for with states absent,enabled,disabled + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# Ensure testrepo in installed +__zypper_repo testrepo --state present --repo_uri http://url.to.your.repo/with/path + +# Drop repo by repo uri +__zypper_repo testrepo --state absent --repo_uri http://url.to.your.repo/with/path + +# Drop repo by id nummber, attention: on every call to absent, repos are new 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 --repo_uri http://url.to.your.repo/with/path + +# disable a repo works like enabling +__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/parameter/default/state b/cdist/conf/type/__zypper_repo/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__zypper_repo/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__zypper_repo/parameter/optional b/cdist/conf/type/__zypper_repo/parameter/optional new file mode 100644 index 00000000..6f5a8325 --- /dev/null +++ b/cdist/conf/type/__zypper_repo/parameter/optional @@ -0,0 +1,4 @@ +state +repo_uri +repo_desc +repo_id diff --git a/docs/man/man7/.directory b/docs/man/man7/.directory new file mode 100644 index 00000000..e2ac7573 --- /dev/null +++ b/docs/man/man7/.directory @@ -0,0 +1,4 @@ +[Dolphin] +Timestamp=2013,12,4,9,33,47 +Version=3 +ViewMode=2 From 19219fe1f96b30ed5c8a38f40d3a2e63b7c4466a Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 4 Dec 2013 09:44:45 +0100 Subject: [PATCH 328/548] An allen orten correcte gpl headers eingesetzt ... --- .../type/__zypper_repo/explorer/all_repo_ids | 23 ++++++++++++++++++- .../__zypper_repo/explorer/enabled_repo_ids | 21 +++++++++++++++++ .../conf/type/__zypper_repo/explorer/repo_id | 21 +++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids index e1772956..b37d8ac5 100644 --- a/cdist/conf/type/__zypper_repo/explorer/all_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/all_repo_ids @@ -1,3 +1,24 @@ #!/bin/sh # -echo $(zypper lr -u | cut -d'|' -f 1 | grep -E '^[0-9]') +# 2013 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 . +# +# +# Retrieve all repo id nummbers - parsed zypper output +# +# +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 6ece6e05..a0d092b1 100644 --- a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids @@ -1,3 +1,24 @@ #!/bin/sh # +# 2013 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 . +# +# +# Retrieve all repo id nummbers from enabled repos - parsed zypper output +# +# echo $(zypper lr -E | cut -d'|' -f 1 | grep -E '^[0-9]') diff --git a/cdist/conf/type/__zypper_repo/explorer/repo_id b/cdist/conf/type/__zypper_repo/explorer/repo_id index aa1e5f99..8184860d 100644 --- a/cdist/conf/type/__zypper_repo/explorer/repo_id +++ b/cdist/conf/type/__zypper_repo/explorer/repo_id @@ -1,5 +1,26 @@ #!/bin/sh # +# 2013 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 . +# +# +# Retrieve the id from the repo with the uri from parameter repo_uri - parsed zypper output +# +# if [ -f "$__object/parameter/repo_uri" ]; then uri="$(cat "$__object/parameter/repo_uri")" else From b5a0c52684eb82d12c31ab8d5887695cb640b78e Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 4 Dec 2013 10:15:24 +0100 Subject: [PATCH 329/548] =?UTF-8?q?aus=20versehen=20eine=20.direcotry=20da?= =?UTF-8?q?tei=20vom=20dolphin=20eingecheckt,=20nun=20wieder=20gel=C3=B6sc?= =?UTF-8?q?ht=20...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/man/man7/.directory | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 docs/man/man7/.directory diff --git a/docs/man/man7/.directory b/docs/man/man7/.directory deleted file mode 100644 index e2ac7573..00000000 --- a/docs/man/man7/.directory +++ /dev/null @@ -1,4 +0,0 @@ -[Dolphin] -Timestamp=2013,12,4,9,33,47 -Version=3 -ViewMode=2 From 6a68c14a7632db061e7fe18d80e78ce9e0e531da Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 4 Dec 2013 10:56:45 +0100 Subject: [PATCH 330/548] letzter feinschliff bei der man page ... --- cdist/conf/type/__zypper_repo/man.text | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/man.text b/cdist/conf/type/__zypper_repo/man.text index c5d23713..4f2de508 100644 --- a/cdist/conf/type/__zypper_repo/man.text +++ b/cdist/conf/type/__zypper_repo/man.text @@ -10,7 +10,7 @@ cdist-type__zypper_repo - repository management with zypper DESCRIPTION ----------- -Zypper is usually used on the SuSE distribution to manage repositorys. +zypper is usually used on the SuSE distribution to manage repositories. REQUIRED PARAMETERS @@ -24,13 +24,13 @@ state:: Either "present" or "absent" or "enabled" or "disabled", defaults to "present" repo_uri:: - If supplied, use the uri and not the object id as the repo 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 the repo description, only used for state present if the repo must created + 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 the repo id, can be used for with states absent,enabled,disabled + If supplied, use the id and not the object id as repo id, can be used with state absent, enabled and disabled EXAMPLES @@ -43,7 +43,7 @@ __zypper_repo testrepo --state present --repo_uri http://url.to.your.repo/with/p # Drop repo by repo uri __zypper_repo testrepo --state absent --repo_uri http://url.to.your.repo/with/path -# Drop repo by id nummber, attention: on every call to absent, repos are new numbered from 1 to max +# 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 @@ -52,7 +52,7 @@ __zypper_repo testrepo2 --state enabled --repo_id 2 # enable repo by uri __zypper_repo testrepo3 --state enabled --repo_uri http://url.to.your.repo/with/path -# disable a repo works like enabling +# disable a repo works like enabling it __zypper_repo testrepo4 --state disabled --repo_id 4 -------------------------------------------------------------------------------- From b9dcd01ea1cb1842641f75e575e9d346b6ca46e1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 13:19:04 +0100 Subject: [PATCH 331/548] only restart the firewall (iptables) if needed Signed-off-by: Nico Schottelius --- cdist/conf/type/__iptables_apply/gencode-remote | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__iptables_apply/gencode-remote b/cdist/conf/type/__iptables_apply/gencode-remote index 0773b452..9cdf28cf 100644 --- a/cdist/conf/type/__iptables_apply/gencode-remote +++ b/cdist/conf/type/__iptables_apply/gencode-remote @@ -1,2 +1,3 @@ -# Rebuild rules - FIXME: do conditionally as soon as cdist supports it -echo /etc/init.d/iptables restart +if grep -q "^__file/etc/iptables.d/" "$__messages_in"; then + echo /etc/init.d/iptables restart +fi From ed10f4e5b44e002903ed67236773300122be41c6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 13:19:25 +0100 Subject: [PATCH 332/548] use default parameter Signed-off-by: Nico Schottelius --- cdist/conf/type/__iptables_rule/manifest | 7 +------ cdist/conf/type/__iptables_rule/parameter/default/state | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) create mode 100644 cdist/conf/type/__iptables_rule/parameter/default/state diff --git a/cdist/conf/type/__iptables_rule/manifest b/cdist/conf/type/__iptables_rule/manifest index a6abbd5e..f02ab18b 100644 --- a/cdist/conf/type/__iptables_rule/manifest +++ b/cdist/conf/type/__iptables_rule/manifest @@ -21,12 +21,7 @@ base_dir=/etc/iptables.d name="$__object_id" - -if [ -f "$__object/parameter/state" ]; then - state="$(cat "$__object/parameter/state")" -else - state="present" -fi +state="$(cat "$__object/parameter/state")" ################################################################################ # Basic setup diff --git a/cdist/conf/type/__iptables_rule/parameter/default/state b/cdist/conf/type/__iptables_rule/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__iptables_rule/parameter/default/state @@ -0,0 +1 @@ +present From acd42b259bd079a970cb4b2c9c2e1be31e020809 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 13:37:15 +0100 Subject: [PATCH 333/548] do not generate code when mode = 0xxx format Signed-off-by: Nico Schottelius --- cdist/conf/type/__file/gencode-remote | 75 +++++++++++++++------------ 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote index 57bf3503..dcf3857b 100755 --- a/cdist/conf/type/__file/gencode-remote +++ b/cdist/conf/type/__file/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. @@ -26,20 +26,20 @@ stat_file="$__object/explorer/stat" get_current_value() { - if [ -s "$stat_file" ]; then - _name="$1" - _value="$2" - case "$_value" in - [0-9]*) - _index=2 - ;; - *) - _index=3 - ;; - esac - awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" - unset _name _value _index - fi + if [ -s "$stat_file" ]; then + _name="$1" + _value="$2" + case "$_value" in + [0-9]*) + _index=2 + ;; + *) + _index=3 + ;; + esac + awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" + unset _name _value _index + fi } set_group() { @@ -59,29 +59,36 @@ set_mode() { set_attributes= case "$state_should" in - present|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 - if [ -f "$__object/parameter/$attribute" ]; then + present|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 + if [ -f "$__object/parameter/$attribute" ]; then value_should="$(cat "$__object/parameter/$attribute")" + + # change 0xxx format to xxx format => same as stat returns + if [ "$attribute" = mode ]; then + value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" + fi + value_is="$(get_current_value "$attribute" "$value_should")" if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then - "set_$attribute" "$value_should" + "set_$attribute" "$value_should" fi - fi - done - ;; + fi + done - absent) - if [ "$type" = "file" ]; then - echo rm -f \"$destination\" - echo remove >> "$__messages_out" - fi - ;; + ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + absent) + if [ "$type" = "file" ]; then + echo rm -f \"$destination\" + echo remove >> "$__messages_out" + fi + ;; + + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; esac From ccf0f4311d8d1420e0c79a04ce95ae3db154221d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 13:37:32 +0100 Subject: [PATCH 334/548] ++changes(3.0.0) (really!) Signed-off-by: Nico Schottelius --- docs/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/changelog b/docs/changelog index b6122bec..5fb0af36 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,12 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius + +3.0.0: + * Core: Messaging support added + * Type: __iptables_rule: Use default parameter + * Type __file: Do not generate code if mode is 0xxx + 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) * Type __file: Only remove file when state is absent (Steven Armstrong) From 77830609939f4bd0b4525ee5f72bfca1f970bd0e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 14:19:23 +0100 Subject: [PATCH 335/548] document messaging Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-messaging.text | 72 ++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 docs/man/man7/cdist-messaging.text diff --git a/docs/man/man7/cdist-messaging.text b/docs/man/man7/cdist-messaging.text new file mode 100644 index 00000000..0e53871e --- /dev/null +++ b/docs/man/man7/cdist-messaging.text @@ -0,0 +1,72 @@ +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 +-------------------------------------------------------------------------------- + + +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). From e50b54273a524cf938328e8b90faa904ccc1861f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 14:21:23 +0100 Subject: [PATCH 336/548] docs not, doc Signed-off-by: Nico Schottelius --- {doc => docs}/dev/logs/2012-05-24.preos | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {doc => docs}/dev/logs/2012-05-24.preos (100%) diff --git a/doc/dev/logs/2012-05-24.preos b/docs/dev/logs/2012-05-24.preos similarity index 100% rename from doc/dev/logs/2012-05-24.preos rename to docs/dev/logs/2012-05-24.preos From 7adbc6f91308450f6a5d361f5b5fb5740031338f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 14:44:27 +0100 Subject: [PATCH 337/548] add changes from preos Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 5fb0af36..577194bf 100644 --- a/docs/changelog +++ b/docs/changelog @@ -15,6 +15,7 @@ Changelog * Type __file: Only remove file when state is absent (Steven Armstrong) * Type __link: Only remove link when state is absent (Steven Armstrong) * Type __directory: Only remove directory when state is absent (Steven Armstrong) + * Type __directory: Fix newly introduced quoting issue * Type __package_zypper: Fix explorer and parameter issue (Daniel Heule) * Core: Fix backtrace when cache cannot be deleted From 808ea306347ae98f122dc453e9d4e416b166ad12 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 4 Dec 2013 14:50:11 +0100 Subject: [PATCH 338/548] Korrektur der intention, vim hat mich verschaukelt ... --- cdist/conf/type/__zypper_repo/gencode-remote | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index b56518c9..c2302662 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -65,27 +65,27 @@ fi case "$state" in present) if [ -z "$desc" ] || [ -z "$uri" ]; then - echo "parameter repo_desc and repo_uri for $state needed" >&2 - exit 4 - fi + echo "parameter repo_desc and repo_uri for $state needed" >&2 + exit 4 + fi if [ -z "$repo_id" ]; then - echo zypper $zypper_def_opts addrepo "'$uri'" "'$desc'" - fi + echo zypper $zypper_def_opts addrepo "'$uri'" "'$desc'" + fi ;; absent) if [ ! -z "$act_id" ]; then echo zypper $zypper_def_opts removerepo $act_id - fi + fi ;; enabled) if [ ! -z "$act_id" ]; then echo zypper $zypper_def_opts modifyrepo -e $act_id - fi + fi ;; disabled) if [ ! -z "$act_id" ]; then echo zypper $zypper_def_opts modifyrepo -d $act_id - fi + fi ;; *) echo "Unknown state: $state" >&2 From ea33b093f0e4c9f2c97a76d7e628937afe71012f Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 4 Dec 2013 14:58:15 +0100 Subject: [PATCH 339/548] cleanup of variable quoting --- cdist/conf/type/__zypper_repo/gencode-remote | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index c2302662..83b05dd0 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -56,9 +56,9 @@ enabled_repo_ids="$(cat "$__object/explorer/enabled_repo_ids")" repo_id="$(cat "$__object/explorer/repo_id")" act_id="" -if grep -q $id $__object/explorer/all_repo_ids; then +if grep -q "$id" "$__object/explorer/all_repo_ids"; then act_id="$id" -elif grep -q $repo_id $__object/explorer/all_repo_ids; then +elif grep -q "$repo_id" "$__object/explorer/all_repo_ids"; then act_id="$repo_id" fi @@ -74,17 +74,17 @@ case "$state" in ;; absent) if [ ! -z "$act_id" ]; then - echo zypper $zypper_def_opts removerepo $act_id + echo zypper $zypper_def_opts removerepo "'$act_id'" fi ;; enabled) if [ ! -z "$act_id" ]; then - echo zypper $zypper_def_opts modifyrepo -e $act_id + echo zypper $zypper_def_opts modifyrepo -e "'$act_id'" fi ;; disabled) if [ ! -z "$act_id" ]; then - echo zypper $zypper_def_opts modifyrepo -d $act_id + echo zypper $zypper_def_opts modifyrepo -d "'$act_id'" fi ;; *) From 71f5709fca00b4e0844ca200e3454c79017c8cb3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 15:15:21 +0100 Subject: [PATCH 340/548] add old workflow example Signed-off-by: Nico Schottelius --- docs/dev/logs/2011-11-17.workflow-example.dia | Bin 0 -> 1343 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/dev/logs/2011-11-17.workflow-example.dia diff --git a/docs/dev/logs/2011-11-17.workflow-example.dia b/docs/dev/logs/2011-11-17.workflow-example.dia new file mode 100644 index 0000000000000000000000000000000000000000..7a9cd0f7078452472ccfa26b0dc3f6a66b8d8d84 GIT binary patch literal 1343 zcmV-F1;F|riwFP!000021MON_kJ~m7e&1gqXn~+DytFRr$i^F_DT+QMNPsra1})Jt z8%i=L%DaB)Z!dLtZCySj%V-K2*abw5<{OUY_{Q|R_b&mJHkidE3TLtk6j{Qd8+j!3 zXY#kdet)p#_fL24Jc8beKcAsM5>JG2dNq?*oUh+br_ayNfNo>NBL*l*K#ZsVAWG3x z2unV#l`CV;4)pd33`5C8F^;8_1Vmv+dH%^%?PwCvHii zMawhs_-g(#kh^m2+kv!iNK6(KH(5_Yel_*m>!`23oveEAAMY6rxwh8!;Mo{rczJv9 z6XN0cM3|LjS~RT+vFRzVSLM!iOukfU))@pvTg(dezwX<#RJ`D#;z-ElWV5?E@JY1z z8@s&N?6=RKqzCDPD>#F^Cm@1;5N{@bQOcgG?oDVCMX=_ob@Uof7H}peP+)cY_2SW{ zf3c{lXTo|E`V{97CeWa&!HEv^M+ZQ|w&27Db~nTTb0nV#bdR{an|4fbFn1#s*7?VQ z&rD!uyMaAGvO-mN+`bX^QNF^&U-5SB5a>?n(-BPcJ$z~>3Q(2uN9_TYmY9Uq1E9=H z6{Q=*l2CdEM444z2Ep+QKNY_fnKs^$G24<{g#`bGH<(6(OSf?0BMqd@K~cz?5Yu&O zi2_2m!Y~xZvJ~@eTIocg${+m$(+%dtMTZ6Xatmsq-57FqCFG2Lpyd+URz_`6+h9MS za#KAs!n*(o%Ib#!Zho6MOo9fsag1*?wam7*Ki&7Zwx;)|=pPD_SMC=BN~^s@bQ+GSl-*kzcy zF3g0wVs|u5M2@?z+S5c{FY0NbH%E*`&sD|yK<)YhUsca34*lbO4EBXM*(uLNNZ-B) zF_8~(t&{BTNGp*+MFHkf#uTOf-I;9HLZRVVwRl!*eRh}l6@$*n@toLx$(9-tTiz6@6KVlwy2D4efsL8SFN%F{Rbeu zDHR-;^p3pxQeORw^ijNOj;9|*q4aTD8<)f%N%qhrTXlfxOf+CwCbUPQeTrze#y4g- zN;9IGFT40|jO2^z@k`7_ehj8RzrIzvkBL2WVk;Bn|CP?l?b4aV^Za|{YC0S{BD$zv zti9s)?ofU?;`Pg$oXXuAqDT{VB; z>Ej9xJZJn+bznG_aqvC(fa8Y&v~pF|#_?kuKe~+{Uz2!MOdS%BB%knAvbamvDLq(s zJrZ+86*uBkKE0Ci%fu`0?xY_!(i_SjIbuHM^Hmh{pW>h2`22AsKSPrrO$WN7+Y=io z<6JY&HRD_}&Nbs)GtM Date: Wed, 4 Dec 2013 15:16:31 +0100 Subject: [PATCH 341/548] add more old workflow examples Signed-off-by: Nico Schottelius --- docs/dev/logs/2011-11-16.workflow-example.dia | Bin 0 -> 1950 bytes docs/dev/logs/2011-11-16.workflow-example.png | Bin 0 -> 20490 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/dev/logs/2011-11-16.workflow-example.dia create mode 100644 docs/dev/logs/2011-11-16.workflow-example.png diff --git a/docs/dev/logs/2011-11-16.workflow-example.dia b/docs/dev/logs/2011-11-16.workflow-example.dia new file mode 100644 index 0000000000000000000000000000000000000000..8dab4a2cc30425f34ba78ef02cff47ee00a89143 GIT binary patch literal 1950 zcmV;P2VwXhiwFP!000021MOT(bK5o$zWY~jluJ9KKmdpb5y#G?>9jqh&7sLz1Cg-A zh9Wg2LoH$D9#o_S;QwqV?>}VDRwp0HUW%>LdkGI0u;; z{3oMG4$PoI@Ak@Z)&&GoOM7f_RBD}uqq$a2ET`(GHahlBIpjV7qjPsKyNu7Hc z-Sl4F<)7YQA!e{4=NZ{EIaZ@o$*=XIq4@}LjOdw4%VMXqBn!*mNq$D-RQjP zqVuXt&#NxXhO;EqsSNeD%2AR;O2&m&ozB(qdNN-|#>JjnR)baCg<2;&=6@%nY@Y=b zhrdPJp^-aI!{GVA-560L(=V73-9d5Qcrbg0aF>J8Q>g93!8m2f@O4hlGNIt1_A^w+D znsyc!c!4;M^mTZ@{I+J3Wb}{n^PUH z_I5aW5c>K!=_*pwp`WDjHvd?&83Qa|4Q-$#2dZtutrB4q;S&{(C%Rrb1+Lim9I4FY zJ+*5k5FohuK@F5yh?%F`4zS5fAv{jST^L1ssMuuHhpEu&QSb8K(wI8lku%$kaU~M` ztGZWFVz_h-7k(yz)EOv=b(KbY+_{s}FnTf*lX2E_GW}$c&Hz<$>K`h)S330NIv^iD zgDuytbUCl&a-^BkO$e=nQO{r-ZKh~5sqX3F$0#zCbsSGs_0?4Id|JUap5q%;DYGu^ z4^}zu`K0$LKU9(RP}8hOfXP9~1*pZeXLMKKYW$`2Ly~?q<;Dj?M}oC#11+iz+_c&-DT-iW zQWXSLVA5jEQPOmcIiMVx?;McJEj&(QzkSLNTig&RT*f?MfKCY9V)?-gvU27Mh&Xqt zi@E5UaA&FwauBQ7Ki|DMc(ASV)Lm9klN#zbst!>*lR>b_VYZyXxErOeaXl)G-?`j< z`6bpk)RXz>%~erkO{L|n&M1|!Kj|1*+l&k&<1*N_%^!gn?uxA=+1Xtb&W4jD4gWPB zC8M_ZQ?AC)80(L%Daqy|d*_4d9gSc6u(Q7ny9s0(7<%^6z-dJ<*ge4xD8XLe16&BV z&4w@s%;n7P6L8{Da_s?^A&l~tD#J%o4L^zFp^AfiLB}k!vadKjsA{5+SUO;zk(c)ZGd+rh)OA|UxjFZL{SiS>;^8_X^Z?ghJ02i^tFcH_L zbm5F3+og0((6=1pwacumsn{~5d(`cM{KpD%)F8<5=DFk~LB49U{H{#3Z>;daFsZp^ z@jrb|9#r~sMdyV!je7ww?c;X$c|8+A7!#`ovTK9^#Ki4m4=}G3$s~&2z0$;)EZ&tHOocJ7@ zUsda@tfB~~EFVf>7v(=#l-EbM=XXt2eJ7V_?$3c;CpHHbi0l23vEou-6!4p7|NwM%~gxD98awV7= zOyagVie5e*&E`?mLD4y&Xv+aREV@K2YW%_nds|Na@`6_DpF#;X)eg0H{<*k#VS-C9 z0g|#wM~}{cNfnORVbUdHQsc)$JwWqk8aZwC?!-a~qWODhNdC$M2*k@rq@Z|vRfkDu kc$LPsBX*edT`{Tnp1()(_G;rrlebs@12D-Lj*MCW0HX5OlmGw# literal 0 HcmV?d00001 diff --git a/docs/dev/logs/2011-11-16.workflow-example.png b/docs/dev/logs/2011-11-16.workflow-example.png new file mode 100644 index 0000000000000000000000000000000000000000..07a0f12645a58531abd96335cc572aeea49d62ae GIT binary patch literal 20490 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 literal 0 HcmV?d00001 From 33a4f07bb40a2406fddeb41e81c734bc3424d45f Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 4 Dec 2013 15:22:48 +0100 Subject: [PATCH 342/548] in der manpage state parameter besser erlaeutert ... TODO: howto line breaks in html ? --- cdist/conf/type/__zypper_repo/man.text | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__zypper_repo/man.text b/cdist/conf/type/__zypper_repo/man.text index 4f2de508..6ea88f16 100644 --- a/cdist/conf/type/__zypper_repo/man.text +++ b/cdist/conf/type/__zypper_repo/man.text @@ -21,7 +21,12 @@ None OPTIONAL PARAMETERS ------------------- state:: - Either "present" or "absent" or "enabled" or "disabled", defaults to "present" + Either "present" or "absent" or "enabled" or "disabled", defaults to "present" + + #present# - make sure that the repo is aviable, needs repo_uri and repo_desc + + for all following states, the repo can be searched via repo_id or repo_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 + repo_uri:: If supplied, use the uri and not the object id as repo uri. From a37c48ed439ba90c2bc59dcd3c4b9cf37f4e3433 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 4 Dec 2013 15:24:18 +0100 Subject: [PATCH 343/548] bei dem repo_id eine kleine verschoenerung --- cdist/conf/type/__zypper_repo/explorer/repo_id | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__zypper_repo/explorer/repo_id b/cdist/conf/type/__zypper_repo/explorer/repo_id index 8184860d..83a698b7 100644 --- a/cdist/conf/type/__zypper_repo/explorer/repo_id +++ b/cdist/conf/type/__zypper_repo/explorer/repo_id @@ -24,6 +24,6 @@ if [ -f "$__object/parameter/repo_uri" ]; then uri="$(cat "$__object/parameter/repo_uri")" else - uri="/$__object_id" + uri="$__object_id" fi echo $(zypper lr -u | grep -E "\<$uri\>" | cut -d'|' -f 1 | grep -E '^[0-9]' ) From 72bbf932826a94077287cbbdd6cd9985cddddc18 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 4 Dec 2013 15:32:31 +0100 Subject: [PATCH 344/548] korrekte ids, hier werden von zypper keine quotes erwartet, da nur zahlen moeglich sind --- cdist/conf/type/__zypper_repo/gencode-remote | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index 83b05dd0..efe0a8f5 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -74,17 +74,17 @@ case "$state" in ;; absent) if [ ! -z "$act_id" ]; then - echo zypper $zypper_def_opts removerepo "'$act_id'" + echo zypper $zypper_def_opts removerepo "$act_id" fi ;; enabled) if [ ! -z "$act_id" ]; then - echo zypper $zypper_def_opts modifyrepo -e "'$act_id'" + echo zypper $zypper_def_opts modifyrepo -e "$act_id" fi ;; disabled) if [ ! -z "$act_id" ]; then - echo zypper $zypper_def_opts modifyrepo -d "'$act_id'" + echo zypper $zypper_def_opts modifyrepo -d "$act_id" fi ;; *) From 4947b154eecbb5a47add911db0ed35534b327c12 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 21:22:18 +0100 Subject: [PATCH 345/548] update cdist hacker with git workflow Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-hacker.text | 66 ++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/docs/man/man7/cdist-hacker.text b/docs/man/man7/cdist-hacker.text index 9dd52d35..b147808e 100644 --- a/docs/man/man7/cdist-hacker.text +++ b/docs/man/man7/cdist-hacker.text @@ -33,7 +33,6 @@ 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 @@ -75,14 +74,77 @@ 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: + +-------------------------------------------------------------------------------- +# 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 + +# create a new branch for your feature/bugfix +cd cdist # if you haven't done before +git checkout -b documentation_cleanup + +# *hack* +*hack* + +# 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 + +# push the new branch to github +git push github documentation_cleanup + +# (or everything) +git push --mirror github + +# create a pull request at github (use a browser) +# *fixthingsbecausequalityassurancefoundissuesinourpatch* +*hack* + +# push code to github again +git push ... # like above + +# add comment that everything should be green now (use a browser) + +# 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 +-------------------------------------------------------------------------------- + +If at any point you want to go back to the original master branch, you can +use **git stash** to stash your changes away: + +-------------------------------------------------------------------------------- +# 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 +-------------------------------------------------------------------------------- + SEE ALSO -------- - cdist(7) +- git(1) +- git-checkout(1) +- git-stash(1) COPYING ------- -Copyright \(C) 2011-2012 Nico Schottelius. Free use of this software is +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). From 5f5b9f8cc4a79d9296b234d2c1d66f589c11474f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 21:25:10 +0100 Subject: [PATCH 346/548] describe how to develop multiple features at the same time Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-hacker.text | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/man/man7/cdist-hacker.text b/docs/man/man7/cdist-hacker.text index b147808e..2cbf5a8b 100644 --- a/docs/man/man7/cdist-hacker.text +++ b/docs/man/man7/cdist-hacker.text @@ -134,6 +134,20 @@ 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: + +-------------------------------------------------------------------------------- +# 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 +-------------------------------------------------------------------------------- + +(you can repeat the code above for as many features as you want to develop +in parallel) SEE ALSO From a5fc3f5002bd63f9cd9d8ef3323ff1b86dbcff8b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 21:29:56 +0100 Subject: [PATCH 347/548] remove changed attribute of an object - was never used and will never be used Signed-off-by: Nico Schottelius --- cdist/core/cdist_object.py | 1 - cdist/test/cdist_object/__init__.py | 8 -------- 2 files changed, 9 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index e3c1c532..45b5e3ff 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -201,7 +201,6 @@ class CdistObject(object): 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)) - changed = fsproperty.FileBooleanProperty(lambda obj: os.path.join(obj.absolute_path, "changed")) 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)) diff --git a/cdist/test/cdist_object/__init__.py b/cdist/test/cdist_object/__init__.py index ffb2ba79..54ecf637 100644 --- a/cdist/test/cdist_object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -102,7 +102,6 @@ class ObjectTestCase(test.CdistTestCase): self.cdist_object = core.CdistObject(self.cdist_type, object_base_path, 'moon') def tearDown(self): - self.cdist_object.changed = False self.cdist_object.prepared = False self.cdist_object.ran = False self.cdist_object.source = [] @@ -172,13 +171,6 @@ class ObjectTestCase(test.CdistTestCase): expected = [] self.assertEqual(list(self.cdist_object.requirements), expected) - def test_changed(self): - self.assertFalse(self.cdist_object.changed) - - def test_changed_after_changing(self): - self.cdist_object.changed = True - self.assertTrue(self.cdist_object.changed) - def test_state(self): self.assertEqual(self.cdist_object.state, '') From 87dcc6ed52ff7e1322e22f0887c35aa762e0de77 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 4 Dec 2013 21:30:34 +0100 Subject: [PATCH 348/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 577194bf..87b32175 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.0.0: * Core: Messaging support added + * Core: Removed unused "changed" attribute of objects * Type: __iptables_rule: Use default parameter * Type __file: Do not generate code if mode is 0xxx From e1a2ebab5c4d6727cae37fb829c671c1cd0e7f56 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 5 Dec 2013 08:45:12 +0100 Subject: [PATCH 349/548] gencode-remote gibt nur noch befehle aus wenn was zu tun ist ... --- cdist/conf/type/__zypper_repo/gencode-remote | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index efe0a8f5..c93ca229 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -51,8 +51,6 @@ else state="present" fi -all_repo_ids="$(cat "$__object/explorer/all_repo_ids")" -enabled_repo_ids="$(cat "$__object/explorer/enabled_repo_ids")" repo_id="$(cat "$__object/explorer/repo_id")" act_id="" @@ -62,6 +60,13 @@ elif grep -q "$repo_id" "$__object/explorer/all_repo_ids"; then act_id="$repo_id" fi +if grep -q "$act_id" "$__object/explorer/enabled_repo_ids"; then + state="enabled" +else + state="disabled" +fi + + case "$state" in present) if [ -z "$desc" ] || [ -z "$uri" ]; then @@ -78,12 +83,12 @@ case "$state" in fi ;; enabled) - if [ ! -z "$act_id" ]; then + if [ ! -z "$act_id" ] && [ "$state" = "disabled" ]; then echo zypper $zypper_def_opts modifyrepo -e "$act_id" fi ;; disabled) - if [ ! -z "$act_id" ]; then + if [ ! -z "$act_id" ] && [ "$state" = "disabled" ]; then echo zypper $zypper_def_opts modifyrepo -d "$act_id" fi ;; From 512b4100123c649ee4958ba54272e5c3ca055856 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 5 Dec 2013 08:47:57 +0100 Subject: [PATCH 350/548] korrektur eines typos ... --- cdist/conf/type/__zypper_repo/gencode-remote | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index c93ca229..e2cc25e5 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -60,10 +60,9 @@ elif grep -q "$repo_id" "$__object/explorer/all_repo_ids"; then act_id="$repo_id" fi +state="disabled" if grep -q "$act_id" "$__object/explorer/enabled_repo_ids"; then state="enabled" -else - state="disabled" fi @@ -88,7 +87,7 @@ case "$state" in fi ;; disabled) - if [ ! -z "$act_id" ] && [ "$state" = "disabled" ]; then + if [ ! -z "$act_id" ] && [ "$state" = "enabled" ]; then echo zypper $zypper_def_opts modifyrepo -d "$act_id" fi ;; From 59de2afdaaa7b122744dac5c5eab27d36fa07ed4 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 5 Dec 2013 13:14:15 +0100 Subject: [PATCH 351/548] ups, was a variable collision --- cdist/conf/type/__zypper_repo/gencode-remote | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index e2cc25e5..4698582e 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -60,9 +60,9 @@ elif grep -q "$repo_id" "$__object/explorer/all_repo_ids"; then act_id="$repo_id" fi -state="disabled" +repostate="disabled" if grep -q "$act_id" "$__object/explorer/enabled_repo_ids"; then - state="enabled" + repostate="enabled" fi @@ -82,12 +82,12 @@ case "$state" in fi ;; enabled) - if [ ! -z "$act_id" ] && [ "$state" = "disabled" ]; then + if [ ! -z "$act_id" ] && [ "$repostate" = "disabled" ]; then echo zypper $zypper_def_opts modifyrepo -e "$act_id" fi ;; disabled) - if [ ! -z "$act_id" ] && [ "$state" = "enabled" ]; then + if [ ! -z "$act_id" ] && [ "$repostate" = "enabled" ]; then echo zypper $zypper_def_opts modifyrepo -d "$act_id" fi ;; From 367ef21bd8bcf761789db470e8cbd85f1ab01c97 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 6 Dec 2013 13:49:45 +0100 Subject: [PATCH 352/548] make __postfix_* types depend on __postfix Signed-off-by: Steven Armstrong --- cdist/conf/type/__postfix_master/manifest | 3 ++- cdist/conf/type/__postfix_postconf/manifest | 21 +++++++++++++++++++++ cdist/conf/type/__postfix_postmap/manifest | 21 +++++++++++++++++++++ cdist/conf/type/__postfix_reload/manifest | 21 +++++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100755 cdist/conf/type/__postfix_postconf/manifest create mode 100755 cdist/conf/type/__postfix_postmap/manifest create mode 100755 cdist/conf/type/__postfix_reload/manifest diff --git a/cdist/conf/type/__postfix_master/manifest b/cdist/conf/type/__postfix_master/manifest index 1642e91b..87e2329b 100755 --- a/cdist/conf/type/__postfix_master/manifest +++ b/cdist/conf/type/__postfix_master/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2012 - 2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -32,6 +32,7 @@ case "$os" in ;; esac +__postfix # Default to object_id service="$(cat "$__object/parameter/service" 2>/dev/null || echo "$__object_id")" diff --git a/cdist/conf/type/__postfix_postconf/manifest b/cdist/conf/type/__postfix_postconf/manifest new file mode 100755 index 00000000..0dde64e9 --- /dev/null +++ b/cdist/conf/type/__postfix_postconf/manifest @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2012 - 2013 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 . +# + +__postfix diff --git a/cdist/conf/type/__postfix_postmap/manifest b/cdist/conf/type/__postfix_postmap/manifest new file mode 100755 index 00000000..0dde64e9 --- /dev/null +++ b/cdist/conf/type/__postfix_postmap/manifest @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2012 - 2013 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 . +# + +__postfix diff --git a/cdist/conf/type/__postfix_reload/manifest b/cdist/conf/type/__postfix_reload/manifest new file mode 100755 index 00000000..0dde64e9 --- /dev/null +++ b/cdist/conf/type/__postfix_reload/manifest @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2012 - 2013 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 . +# + +__postfix From 2ea2e640c93d5bec4a4c4422c63ac098ec8d2737 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 6 Dec 2013 14:19:36 +0100 Subject: [PATCH 353/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 87b32175..dd0e7dce 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ Changelog * Core: Removed unused "changed" attribute of objects * Type: __iptables_rule: Use default parameter * Type __file: Do not generate code if mode is 0xxx + * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From a271244cfb77aa7a70ac2af836fcdc7aa4fa41c4 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 6 Dec 2013 15:23:09 +0100 Subject: [PATCH 354/548] Die 4 codepaths mit comments erklaert ... --- cdist/conf/type/__zypper_repo/gencode-remote | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index 4698582e..4d834c47 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -73,21 +73,25 @@ case "$state" in exit 4 fi if [ -z "$repo_id" ]; then + # Repo not present, so we need to create it 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" 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" 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" fi ;; From a420ee105d485cb94e9457dbb897816e60aff72e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 6 Dec 2013 23:55:53 +0100 Subject: [PATCH 355/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index dd0e7dce..67ea7e42 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ Changelog 3.0.0: * Core: Messaging support added * Core: Removed unused "changed" attribute of objects + * New Type: __zypper_repo (Daniel Heule) * Type: __iptables_rule: Use default parameter * Type __file: Do not generate code if mode is 0xxx * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) From fe20da65949f5eed385eba7998ffe5ac6c442bf2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 7 Dec 2013 00:13:28 +0100 Subject: [PATCH 356/548] note hint from Axel Beckert for debian prios Signed-off-by: Nico Schottelius --- cdist/conf/type/__package_apt/gencode-remote | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote index 7aba76d5..57339db3 100755 --- a/cdist/conf/type/__package_apt/gencode-remote +++ b/cdist/conf/type/__package_apt/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -42,6 +42,8 @@ case "$state_is" in ;; 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-confold\"" [ "$state_is" = "$state_should" ] && exit 0 From c0da6fcc897c38efe1514be65218200aaaeba87a Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 9 Dec 2013 09:44:40 +0100 Subject: [PATCH 357/548] =?UTF-8?q?Verbesserungen=20am=20=5F=5Fcron=20type?= =?UTF-8?q?=201.=20Filter=20messages=20from=20crontab=20-l=20welche=20das?= =?UTF-8?q?=20ganze=20file=20f=C3=BCllen=202.=20neuer=20parameter=20raw=5F?= =?UTF-8?q?command,=20um=20globale=20variablen=20zu=20setzen=20...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cdist/conf/type/__cron/explorer/entry | 0 cdist/conf/type/__cron/gencode-remote | 9 ++++++--- cdist/conf/type/__cron/man.text | 8 ++++++++ cdist/conf/type/__cron/parameter/boolean | 1 + 4 files changed, 15 insertions(+), 3 deletions(-) mode change 100755 => 100644 cdist/conf/type/__cron/explorer/entry mode change 100755 => 100644 cdist/conf/type/__cron/gencode-remote create mode 100644 cdist/conf/type/__cron/parameter/boolean diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry old mode 100755 new mode 100644 diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote old mode 100755 new mode 100644 index c04a7245..6f1feb90 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -26,6 +26,8 @@ command="$(cat "$__object/parameter/command")" if [ -f "$__object/parameter/raw" ]; then raw="$(cat "$__object/parameter/raw")" entry="$raw $command" +elif [ -f "$__object/parameter/raw_command" ]; then + entry="$command" else minute="$(cat "$__object/parameter/minute" 2>/dev/null || echo "*")" hour="$(cat "$__object/parameter/hour" 2>/dev/null || echo "*")" @@ -55,8 +57,9 @@ 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" cat << DONE -crontab -u $user -l | awk -v prefix="$prefix" -v suffix="$suffix" ' +crontab -u $user -l | grep -v -E "$filter" | awk -v prefix="$prefix" -v suffix="$suffix" ' { if (index(\$0,prefix)) { triggered=1 @@ -75,12 +78,12 @@ DONE case "$state_should" in present) echo "(" - echo "crontab -u $user -l 2>/dev/null || true" + echo "crontab -u $user -l | grep -v -E "$filter" 2>/dev/null || true" echo "echo '$entry'" echo ") | crontab -u $user -" ;; absent) - echo "( crontab -u $user -l 2>/dev/null || true ) | \\" + echo "( crontab -u $user -l | grep -v -E "$filter" 2>/dev/null || true ) | \\" echo "grep -v \"# $name\\$\" | crontab -u $user -" ;; esac diff --git a/cdist/conf/type/__cron/man.text b/cdist/conf/type/__cron/man.text index 22627234..f4e80a08 100644 --- a/cdist/conf/type/__cron/man.text +++ b/cdist/conf/type/__cron/man.text @@ -41,6 +41,10 @@ raw:: 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:: + Take whatever the user has given in the commmand 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. EXAMPLES @@ -57,6 +61,10 @@ __cron some-id --user root --command "/path/to/script" \ # 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 -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__cron/parameter/boolean b/cdist/conf/type/__cron/parameter/boolean new file mode 100644 index 00000000..54cfb0b3 --- /dev/null +++ b/cdist/conf/type/__cron/parameter/boolean @@ -0,0 +1 @@ +raw_command From 02aad6f4ccd114378ae770e125c781c10eca18d2 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 9 Dec 2013 09:57:31 +0100 Subject: [PATCH 358/548] =?UTF-8?q?revert=20vom=20chmod=20der=20aus=20vers?= =?UTF-8?q?ehen=20ge=C3=A4ndert=20wurde=20...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cdist/conf/type/__cron/explorer/entry | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 cdist/conf/type/__cron/explorer/entry diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry old mode 100644 new mode 100755 From e6420a49e88295ae50f265512d6af79389a23c74 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 9 Dec 2013 11:39:44 +0100 Subject: [PATCH 359/548] verhindern dass raw and raw_command zusammen angegeben werden --- cdist/conf/type/__cron/gencode-remote | 1 + cdist/conf/type/__cron/manifest | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 cdist/conf/type/__cron/manifest diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index 6f1feb90..e84cf66a 100644 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -2,6 +2,7 @@ # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Thomas Oettli (otho at sfs.biz) # # This file is part of cdist. # diff --git a/cdist/conf/type/__cron/manifest b/cdist/conf/type/__cron/manifest new file mode 100644 index 00000000..9992df25 --- /dev/null +++ b/cdist/conf/type/__cron/manifest @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2013 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 . +# + +if [ -f "$__object/parameter/raw" ] && [ -f "$__object/parameter/raw_command" ]; then + echo "ERROR: both raw and raw_command specified" >&2 + exit 1 +fi From 6bf235c698ce9f4be0288c7410d7b3fe68f8c073 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 9 Dec 2013 23:17:06 +0100 Subject: [PATCH 360/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 67ea7e42..e4c09e7b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -12,6 +12,7 @@ Changelog * Type: __iptables_rule: Use default parameter * Type __file: Do not generate code if mode is 0xxx * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) + * Type __cron: Add support for raw lines (Daniel Heule) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From d068dfd6218956a9bf07652327dc4e04209d3e95 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 10 Dec 2013 11:02:10 +0100 Subject: [PATCH 361/548] escape and thereby preserve quotes in values Signed-off-by: Steven Armstrong --- cdist/conf/type/__key_value/gencode-remote | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index c1a6bca8..ec91894f 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -26,8 +26,8 @@ state_should=present file="$(cat "$__object/parameter/file")" delimiter="$(cat "$__object/parameter/delimiter")" -value="$(cat "$__object/parameter/value")" - +# escape double quotes, as that is what we use ourself below +value_escaped="$(cat "$__object/parameter/value" | sed -e "s/\([\"]\)/\\\\\1/g")" state_is="$(cat "$__object/explorer/state")" [ "$state_is" = "$state_should" ] && exit 0 @@ -35,20 +35,29 @@ state_is="$(cat "$__object/explorer/state")" case "$state_should" in absent) # remove lines starting with key - echo "sed '/^$key\($delimiter\+\)/d' \"$file\" > \"$file.cdist-tmp\"" - echo "mv \"$file.cdist-tmp\" \"$file\"" + cat << DONE +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) +# preserve ownership and permissions by copying existing file over tmpfile +cp -p "$file" "\$tmpfile" +sed '/^$key\($delimiter\+\)/d' "$file" > "\$tmpfile" +mv -f "\$tmpfile" "$file" +DONE ;; present) case "$state_is" in absent) # add new key and value - echo "echo \"${key}${delimiter}${value}\" >> \"$file\"" + printf 'echo "%s%s%s" >> "%s"' "$key" "$delimiter" "$value_escaped" "$file" ;; wrongvalue) # change exisiting value - printf 'sed "s|^%s\(%s\+\).*|%s\\1%s|" "%s" > "%s.cdist-tmp"\n' \ - "$key" "$delimiter" "$key" "$value" "$file" "$file" - echo "mv \"$file.cdist-tmp\" \"$file\"" + cat << DONE +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) +# preserve ownership and permissions by copying existing file over tmpfile +cp -p "$file" "\$tmpfile" +sed "s|^$key\($delimiter\+\).*|$key\\1$value_escaped|" "$file" > "\$tmpfile" +mv -f "\$tmpfile" "$file" +DONE ;; *) echo "Unknown explorer state: $state_is" >&2 @@ -58,4 +67,4 @@ case "$state_should" in *) echo "Unknown state: $state_should" >&2 exit 1 -esac +esac From 0f1dabb08028b79e7ee373da468291ccc7efb3df Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 10 Dec 2013 11:50:18 +0100 Subject: [PATCH 362/548] inital commit of __zypper_service --- .../type/__zypper_service/explorer/repo_ids | 24 +++++ .../type/__zypper_service/explorer/service_id | 28 ++++++ .../__zypper_service/explorer/service_ids | 23 +++++ .../__zypper_service/explorer/service_uri | 28 ++++++ .../conf/type/__zypper_service/gencode-remote | 94 +++++++++++++++++++ cdist/conf/type/__zypper_service/man.text | 67 +++++++++++++ cdist/conf/type/__zypper_service/manifest | 63 +++++++++++++ .../type/__zypper_service/parameter/boolean | 2 + .../__zypper_service/parameter/default/state | 1 + .../__zypper_service/parameter/default/type | 1 + .../type/__zypper_service/parameter/optional | 3 + .../type/__zypper_service/parameter/required | 1 + 12 files changed, 335 insertions(+) create mode 100644 cdist/conf/type/__zypper_service/explorer/repo_ids create mode 100644 cdist/conf/type/__zypper_service/explorer/service_id create mode 100644 cdist/conf/type/__zypper_service/explorer/service_ids create mode 100644 cdist/conf/type/__zypper_service/explorer/service_uri create mode 100644 cdist/conf/type/__zypper_service/gencode-remote create mode 100644 cdist/conf/type/__zypper_service/man.text create mode 100644 cdist/conf/type/__zypper_service/manifest create mode 100644 cdist/conf/type/__zypper_service/parameter/boolean create mode 100644 cdist/conf/type/__zypper_service/parameter/default/state create mode 100644 cdist/conf/type/__zypper_service/parameter/default/type create mode 100644 cdist/conf/type/__zypper_service/parameter/optional create mode 100644 cdist/conf/type/__zypper_service/parameter/required diff --git a/cdist/conf/type/__zypper_service/explorer/repo_ids b/cdist/conf/type/__zypper_service/explorer/repo_ids new file mode 100644 index 00000000..8c32b40b --- /dev/null +++ b/cdist/conf/type/__zypper_service/explorer/repo_ids @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Manage services with Zypper (mostly suse) +# +# +echo $(zypper lr -u -E | 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 new file mode 100644 index 00000000..b473340c --- /dev/null +++ b/cdist/conf/type/__zypper_service/explorer/service_id @@ -0,0 +1,28 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Manage services with Zypper (mostly suse) +# +if [ -f "$__object/parameter/service_uri" ]; then + uri="$(cat "$__object/parameter/service_uri")" +else + uri="/$__object_id" +fi +echo $(zypper ls -u -E | 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 new file mode 100644 index 00000000..460b2006 --- /dev/null +++ b/cdist/conf/type/__zypper_service/explorer/service_ids @@ -0,0 +1,23 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Manage services with Zypper (mostly suse) +# +echo $(zypper ls -u -E | 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 new file mode 100644 index 00000000..aec93cb2 --- /dev/null +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -0,0 +1,28 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Manage services with Zypper (mostly suse) +# +if [ -f "$__object/parameter/service_uri" ]; then + uri="$(cat "$__object/parameter/service_uri")" +else + uri="/$__object_id" +fi +echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 7 ) diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote new file mode 100644 index 00000000..d11749ae --- /dev/null +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -0,0 +1,94 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Manage services with Zypper (mostly suse) +# + +# Debug +#exec >&2 +#set -x + +zypper_def_opts=" -q " + +if [ -f "$__object/parameter/service_desc" ]; then + desc="$(cat "$__object/parameter/service_desc")" +else + desc="$__object_id" +fi + +if [ -f "$__object/parameter/service_uri" ]; then + uri="$(cat "$__object/parameter/service_uri")" +else + uri="$__object_id" +fi + +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi + +if [ -f "$__object/parameter/type" ]; then + stype="$(cat "$__object/parameter/type")" +else + stype="ris" +fi + +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)" + +if [ "$uri" = "$exp_uri" ] ; then + state_is="present" +else + state_is="absent" +fi + +# remove all other services if needed ... +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" + fi + done + echo zypper $zypper_def_opts refs "&>/dev/null" +fi + + +# Exit if nothing is needed to be done +[ "$state_is" = "$state_should" ] && exit 0 + +case "$state_should" in + present) + echo zypper $zypper_def_opts addservice -t "$stype" "$uri" \"$desc\" + echo zypper $zypper_def_opts refs + ;; + absent) + echo zypper $zypper_def_opts removeservice "$service_id" + echo zypper $zypper_def_opts refs + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__zypper_service/man.text b/cdist/conf/type/__zypper_service/man.text new file mode 100644 index 00000000..3345be60 --- /dev/null +++ b/cdist/conf/type/__zypper_service/man.text @@ -0,0 +1,67 @@ +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 +------------------- +service_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-service:: + 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 SFS_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_uri "http://path/to/your/ris/dir" --remove-all-other-service --remove-all-repos + +# Ensure that internal SLES11 SP3 RIS is in installed, no changes to ohter services or repos +__zypper_service SFS_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_uri "http://path/to/your/ris/dir" + +# Drop service by uri, no changes to ohter services or repos +__zypper_service SFS_SLES11_SP3 --state absent --service_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/manifest b/cdist/conf/type/__zypper_service/manifest new file mode 100644 index 00000000..d8773605 --- /dev/null +++ b/cdist/conf/type/__zypper_service/manifest @@ -0,0 +1,63 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Manage services with Zypper (mostly suse) +# + +# Debug +#exec >&2 +#set -x + +zypper_def_opts=" -q " + +if [ -f "$__object/parameter/service_uri" ]; then + uri="$(cat "$__object/parameter/service_uri")" +else + uri="$__object_id" +fi + +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi + +exp_uri="$(cat "$__object/explorer/service_uri")" + +if [ "$uri" = "$exp_uri" ] ; then + state_is="present" +else + state_is="absent" +fi + + +# Exit if nothing is needed to be done +[ "$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)" + +# boolean parameter +if [ -f "$__object/parameter/remove-all-repos" ]; then + # file exists -> True + for i in $exp_repos; do + __zypper_repo "droprepo${i}" --state absent --repo_id "${i}" + done +fi diff --git a/cdist/conf/type/__zypper_service/parameter/boolean b/cdist/conf/type/__zypper_service/parameter/boolean new file mode 100644 index 00000000..bc6a5629 --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/boolean @@ -0,0 +1,2 @@ +remove-all-other-service +remove-all-repos diff --git a/cdist/conf/type/__zypper_service/parameter/default/state b/cdist/conf/type/__zypper_service/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__zypper_service/parameter/default/type b/cdist/conf/type/__zypper_service/parameter/default/type new file mode 100644 index 00000000..b928830f --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/default/type @@ -0,0 +1 @@ +ris diff --git a/cdist/conf/type/__zypper_service/parameter/optional b/cdist/conf/type/__zypper_service/parameter/optional new file mode 100644 index 00000000..b26c78d8 --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/optional @@ -0,0 +1,3 @@ +service_desc +state +type diff --git a/cdist/conf/type/__zypper_service/parameter/required b/cdist/conf/type/__zypper_service/parameter/required new file mode 100644 index 00000000..2b4645ee --- /dev/null +++ b/cdist/conf/type/__zypper_service/parameter/required @@ -0,0 +1 @@ +service_uri From f7f63aa7a2c44a23f7a2ac22f11285069d2117a2 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 10 Dec 2013 11:54:42 +0100 Subject: [PATCH 363/548] remove SFS from man page text ... --- cdist/conf/type/__zypper_service/man.text | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__zypper_service/man.text b/cdist/conf/type/__zypper_service/man.text index 3345be60..b1717c96 100644 --- a/cdist/conf/type/__zypper_service/man.text +++ b/cdist/conf/type/__zypper_service/man.text @@ -45,13 +45,13 @@ EXAMPLES -------------------------------------------------------------------------------- # Ensure that internal SLES11 SP3 RIS is in installed and all other services and repos are discarded -__zypper_service SFS_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_uri "http://path/to/your/ris/dir" --remove-all-other-service --remove-all-repos +__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_uri "http://path/to/your/ris/dir" --remove-all-other-service --remove-all-repos # Ensure that internal SLES11 SP3 RIS is in installed, no changes to ohter services or repos -__zypper_service SFS_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_uri "http://path/to/your/ris/dir" +__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_uri "http://path/to/your/ris/dir" # Drop service by uri, no changes to ohter services or repos -__zypper_service SFS_SLES11_SP3 --state absent --service_uri "http://path/to/your/ris/dir" +__zypper_service INTERNAL_SLES11_SP3 --state absent --service_uri "http://path/to/your/ris/dir" -------------------------------------------------------------------------------- From a2106f655265e016f679c2d199a5ec2e918dbd1c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 10 Dec 2013 15:39:27 +0100 Subject: [PATCH 364/548] ++changes (3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index e4c09e7b..cdbcc593 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,7 @@ Changelog * Type __file: Do not generate code if mode is 0xxx * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) * Type __cron: Add support for raw lines (Daniel Heule) + * Type __key_value: Fix quoting issue (Steven Armstrong) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From a5d2cdecf474e0276b7b3cb37bd2727e67c8b49b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 10 Dec 2013 15:48:04 +0100 Subject: [PATCH 365/548] ++changes (3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index cdbcc593..023d0749 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * Core: Messaging support added * Core: Removed unused "changed" attribute of objects * New Type: __zypper_repo (Daniel Heule) + * New Type: __zypper_service (Daniel Heule) * Type: __iptables_rule: Use default parameter * Type __file: Do not generate code if mode is 0xxx * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) From e1eae5604ef816114b51c0ad695c44e0a24a0433 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 10 Dec 2013 16:57:02 +0100 Subject: [PATCH 366/548] unlock the whole power of zypper added the ptype parameter (package type of zypper install) --- .../__package_zypper/explorer/pkg_version | 19 +++++++++++++++++-- .../conf/type/__package_zypper/gencode-remote | 11 +++++++++-- cdist/conf/type/__package_zypper/man.text | 6 ++++++ .../__package_zypper/parameter/default/ptype | 1 + .../type/__package_zypper/parameter/optional | 1 + 5 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 cdist/conf/type/__package_zypper/parameter/default/ptype diff --git a/cdist/conf/type/__package_zypper/explorer/pkg_version b/cdist/conf/type/__package_zypper/explorer/pkg_version index 655b464d..64fd64c0 100644 --- a/cdist/conf/type/__package_zypper/explorer/pkg_version +++ b/cdist/conf/type/__package_zypper/explorer/pkg_version @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -18,7 +19,7 @@ # along with cdist. If not, see . # # -# Retrieve the status of a package +# Retrieve the status of a package off different types # if [ -f "$__object/parameter/name" ]; then @@ -27,4 +28,18 @@ else name="$__object_id" fi -rpm -q --whatprovides "$name" | grep -v 'no package provides' || true +if [ -f "$__object/parameter/ptype" ]; then + ptype="$(cat "$__object/parameter/ptype")" +else + ptype="package" +fi + +case "$ptype" in + package|patch|pattern|product|srcpackage) + zypper se --match-exact -i -t "$ptype" "$name" | grep -E '^i' | cut -d " " -f 3 || true + ;; + *) + echo "unknown type in __package_zypper explorer" &>2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote index d1766126..ef3bf029 100644 --- a/cdist/conf/type/__package_zypper/gencode-remote +++ b/cdist/conf/type/__package_zypper/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -39,6 +40,12 @@ else state_should="present" fi +if [ -f "$__object/parameter/ptype" ]; then + ptype="$(cat "$__object/parameter/ptype")" +else + ptype="package" +fi + pkg_version="$(cat "$__object/explorer/pkg_version")" if [ -z "$pkg_version" ]; then state_is="absent" @@ -51,10 +58,10 @@ fi case "$state_should" in present) - echo zypper $globalopts install --auto-agree-with-licenses \"$name\" ">/dev/null" + echo zypper $globalopts install --type \"$ptype\" --auto-agree-with-licenses \"$name\" ">/dev/null" ;; absent) - echo zypper $globalopts remove \"$name\" ">/dev/null" + echo zypper $globalopts remove --type \"$ptype\" \"$name\" ">/dev/null" ;; *) echo "Unknown state: $state_should" >&2 diff --git a/cdist/conf/type/__package_zypper/man.text b/cdist/conf/type/__package_zypper/man.text index e2261d33..465b21be 100644 --- a/cdist/conf/type/__package_zypper/man.text +++ b/cdist/conf/type/__package_zypper/man.text @@ -26,6 +26,9 @@ name:: state:: Either "present" or "absent", defaults to "present" +ptype:: + Either "package", "patch", "pattern", "product" or "srcpackage", defaults to "package". For a description see man zypper. + EXAMPLES -------- @@ -39,6 +42,9 @@ __package_zypper python --state present --name python2 # Remove package __package_zypper cfengine --state absent + +# install all packages which belongs to pattern x11 +__package_zypper x11 --ptype pattern --state present -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__package_zypper/parameter/default/ptype b/cdist/conf/type/__package_zypper/parameter/default/ptype new file mode 100644 index 00000000..ba3bd787 --- /dev/null +++ b/cdist/conf/type/__package_zypper/parameter/default/ptype @@ -0,0 +1 @@ +package diff --git a/cdist/conf/type/__package_zypper/parameter/optional b/cdist/conf/type/__package_zypper/parameter/optional index 1b423dc4..b484bf07 100644 --- a/cdist/conf/type/__package_zypper/parameter/optional +++ b/cdist/conf/type/__package_zypper/parameter/optional @@ -1,2 +1,3 @@ name state +ptype From 0acf3c0118080369d73b7c0992fa68508df2619d Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 10 Dec 2013 17:25:03 +0100 Subject: [PATCH 367/548] type __postfix_postconf is tested and aproved to work on suse (SLES11) --- cdist/conf/type/__postfix_postconf/explorer/value | 2 +- cdist/conf/type/__postfix_postconf/gencode-remote | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__postfix_postconf/explorer/value b/cdist/conf/type/__postfix_postconf/explorer/value index edf48b48..e08c6da6 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) + ubuntu|debian|archlinux|suse) : ;; *) diff --git a/cdist/conf/type/__postfix_postconf/gencode-remote b/cdist/conf/type/__postfix_postconf/gencode-remote index 60143590..43c0482e 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) + ubuntu|debian|archlinux|suse) : ;; *) From b2e39e3dc19f54320f72675ce0103cf31b2d1dda Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 10 Dec 2013 17:51:48 +0100 Subject: [PATCH 368/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 023d0749..06f70c84 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,7 @@ Changelog * Type: __iptables_rule: Use default parameter * Type __file: Do not generate code if mode is 0xxx * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) + * Type __postfix_postconf: Enable support for SuSE (Daniel Heule) * Type __cron: Add support for raw lines (Daniel Heule) * Type __key_value: Fix quoting issue (Steven Armstrong) From 01dc23b00c5a4814c5023ff9aa9d6441e54c89e9 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 11 Dec 2013 13:07:40 +0100 Subject: [PATCH 369/548] postfix install works also on suse (SLES11) --- cdist/conf/type/__postfix/manifest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__postfix/manifest b/cdist/conf/type/__postfix/manifest index 2dc70ce2..52a13919 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) + ubuntu|debian|archlinux|suse) __package postfix --state present ;; *) From 05262ffe390ede87d5b80fd36ea571866918692c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Dec 2013 13:42:12 +0100 Subject: [PATCH 370/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 06f70c84..75182f5f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -14,6 +14,7 @@ Changelog * Type __file: Do not generate code if mode is 0xxx * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) * Type __postfix_postconf: Enable support for SuSE (Daniel Heule) + * Type __postfix: Enable support for SuSE (Daniel Heule) * Type __cron: Add support for raw lines (Daniel Heule) * Type __key_value: Fix quoting issue (Steven Armstrong) From 785e54b3112e96f34ac026cec15385d22574bcc2 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 11 Dec 2013 13:44:01 +0100 Subject: [PATCH 371/548] =?UTF-8?q?vorbereitung=20um=20mit=20zypper=20auch?= =?UTF-8?q?=20spezifische=20versionen=20zu=20unterst=C3=BCtzen=20parameter?= =?UTF-8?q?=20ptype=20auch=20beim=20package=20type=20zulassen,=20analog=20?= =?UTF-8?q?anderer=20parameter=20von=20subtypes=20...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cdist/conf/type/__package/parameter/optional | 1 + cdist/conf/type/__package_zypper/explorer/pkg_version | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__package/parameter/optional b/cdist/conf/type/__package/parameter/optional index 9982507e..5a89ffc6 100644 --- a/cdist/conf/type/__package/parameter/optional +++ b/cdist/conf/type/__package/parameter/optional @@ -3,3 +3,4 @@ version type pkgsite state +pstate diff --git a/cdist/conf/type/__package_zypper/explorer/pkg_version b/cdist/conf/type/__package_zypper/explorer/pkg_version index 64fd64c0..aaa1da89 100644 --- a/cdist/conf/type/__package_zypper/explorer/pkg_version +++ b/cdist/conf/type/__package_zypper/explorer/pkg_version @@ -35,11 +35,14 @@ else fi case "$ptype" in - package|patch|pattern|product|srcpackage) - zypper se --match-exact -i -t "$ptype" "$name" | grep -E '^i' | cut -d " " -f 3 || true + package) + zypper search --details --match-exact --installed-only --type "$ptype" "$name" | grep -E '^i' | cut -d " " -f 3,7 || true + ;; + patch|pattern|product|srcpackage) + zypper search --match-exact --installed-only --type "$ptype" "$name" | grep -E '^i' | cut -d " " -f 3 || true ;; *) - echo "unknown type in __package_zypper explorer" &>2 + echo "unknown ptype in __package_zypper explorer" &>2 exit 1 ;; esac From 5d5b1fdc05411283098874651fceaa7fb7295ee8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Dec 2013 14:43:05 +0100 Subject: [PATCH 372/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 75182f5f..ff480a93 100644 --- a/docs/changelog +++ b/docs/changelog @@ -17,6 +17,7 @@ Changelog * Type __postfix: Enable support for SuSE (Daniel Heule) * Type __cron: Add support for raw lines (Daniel Heule) * Type __key_value: Fix quoting issue (Steven Armstrong) + * Type __package_zypper: Support non packages as well (Daniel Heule) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From 4bb8dc2f5385ff86b12f4f6af60b09eb5ea78e9d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 11 Dec 2013 14:43:35 +0100 Subject: [PATCH 373/548] 2012 -> 2013 Signed-off-by: Nico Schottelius --- cdist/conf/type/__package_zypper/man.text | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package_zypper/man.text b/cdist/conf/type/__package_zypper/man.text index 465b21be..b7cb5582 100644 --- a/cdist/conf/type/__package_zypper/man.text +++ b/cdist/conf/type/__package_zypper/man.text @@ -56,5 +56,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2012 Nico Schottelius. Free use of this software is +Copyright \(C) 2013 Nico Schottelius. Free use of this software is granted under the terms of the GNU General Public License version 3 (GPLv3). From aaa142d76b1e577be629e9ad669b7aa7cbde148b Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 11 Dec 2013 17:11:22 +0100 Subject: [PATCH 374/548] __package_zypper can now handle the version parameter --- .../__package_zypper/explorer/pkg_version | 2 +- .../conf/type/__package_zypper/gencode-remote | 53 ++++++++++++------- cdist/conf/type/__package_zypper/man.text | 17 ++++-- .../type/__package_zypper/parameter/optional | 1 + 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/cdist/conf/type/__package_zypper/explorer/pkg_version b/cdist/conf/type/__package_zypper/explorer/pkg_version index aaa1da89..7f203067 100644 --- a/cdist/conf/type/__package_zypper/explorer/pkg_version +++ b/cdist/conf/type/__package_zypper/explorer/pkg_version @@ -19,7 +19,7 @@ # along with cdist. If not, see . # # -# Retrieve the status of a package off different types +# Retrieve the status of a package of different types # if [ -f "$__object/parameter/name" ]; then diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote index ef3bf029..51713590 100644 --- a/cdist/conf/type/__package_zypper/gencode-remote +++ b/cdist/conf/type/__package_zypper/gencode-remote @@ -29,42 +29,59 @@ globalopts="--quiet --non-interactive" if [ -f "$__object/parameter/name" ]; then - name="$__object/parameter/name" + name="$__object/parameter/name" else - name="$__object_id" + name="$__object_id" fi if [ -f "$__object/parameter/state" ]; then - state_should="$(cat "$__object/parameter/state")" + state_should="$(cat "$__object/parameter/state")" else - state_should="present" + state_should="present" fi if [ -f "$__object/parameter/ptype" ]; then - ptype="$(cat "$__object/parameter/ptype")" + ptype="$(cat "$__object/parameter/ptype")" else - ptype="package" + ptype="package" +fi + +if [ -f "$__object/parameter/version" ]; then + version_should="$(cat "$__object/parameter/version")" + if [ "$ptype" != "package" ]; then + echo "version support only for type package implemented" >&2 + exit 2 + fi +else + version_should="" fi pkg_version="$(cat "$__object/explorer/pkg_version")" if [ -z "$pkg_version" ]; then state_is="absent" + version_is="" else state_is="present" + version_is=${pkg_version##* } fi -# Exit if nothing is needed to be done -[ "$state_is" = "$state_should" ] && exit 0 case "$state_should" in - present) - echo zypper $globalopts install --type \"$ptype\" --auto-agree-with-licenses \"$name\" ">/dev/null" - ;; - absent) - echo zypper $globalopts remove --type \"$ptype\" \"$name\" ">/dev/null" - ;; - *) - echo "Unknown state: $state_should" >&2 - exit 1 - ;; + 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" + 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" + 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 "Unknown state: $state_should" >&2 + exit 1 + ;; esac diff --git a/cdist/conf/type/__package_zypper/man.text b/cdist/conf/type/__package_zypper/man.text index 465b21be..21c5c5bb 100644 --- a/cdist/conf/type/__package_zypper/man.text +++ b/cdist/conf/type/__package_zypper/man.text @@ -1,6 +1,6 @@ cdist-type__package_zypper(7) ============================= -Nico Schottelius +Daniel Heule NAME @@ -26,6 +26,11 @@ name:: state:: Either "present" or "absent", defaults to "present" +version:: + The version of the package to install. Default is to install the version + choosen by the local package manager. For a list of version have a look to + the output of "zypper se -s packagename" + ptype:: Either "package", "patch", "pattern", "product" or "srcpackage", defaults to "package". For a description see man zypper. @@ -34,12 +39,15 @@ EXAMPLES -------- -------------------------------------------------------------------------------- -# Ensure zsh in installed +# Ensure zsh is installed __package_zypper zsh --state present # If you don't want to follow pythonX packages, but always use python __package_zypper python --state present --name python2 +# 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 + # Remove package __package_zypper cfengine --state absent @@ -56,5 +64,6 @@ SEE ALSO 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. +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/__package_zypper/parameter/optional b/cdist/conf/type/__package_zypper/parameter/optional index b484bf07..bc8565fc 100644 --- a/cdist/conf/type/__package_zypper/parameter/optional +++ b/cdist/conf/type/__package_zypper/parameter/optional @@ -1,3 +1,4 @@ name state ptype +version From b12bd82fe21259be88cb310523afe30a2fded300 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 12 Dec 2013 09:29:22 +0100 Subject: [PATCH 375/548] corrected some minor spell misstakes --- cdist/conf/type/__package_zypper/man.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__package_zypper/man.text b/cdist/conf/type/__package_zypper/man.text index 21c5c5bb..104d3a7a 100644 --- a/cdist/conf/type/__package_zypper/man.text +++ b/cdist/conf/type/__package_zypper/man.text @@ -28,8 +28,8 @@ state:: version:: The version of the package to install. Default is to install the version - choosen by the local package manager. For a list of version have a look to - the output of "zypper se -s packagename" + choosen by the local package manager. For a list of available versions, + have a look at the output of "zypper se -s packagename" ptype:: Either "package", "patch", "pattern", "product" or "srcpackage", defaults to "package". For a description see man zypper. From fc8543eab6e32e2fcf9898108447cbf0b6b955b4 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 12 Dec 2013 10:56:15 +0100 Subject: [PATCH 376/548] initial submit of __package_emerge type --- .../__package_emerge/explorer/pkg_version | 35 +++++++++ .../conf/type/__package_emerge/gencode-remote | 72 +++++++++++++++++++ cdist/conf/type/__package_emerge/man.text | 60 ++++++++++++++++ .../type/__package_emerge/parameter/optional | 3 + 4 files changed, 170 insertions(+) create mode 100644 cdist/conf/type/__package_emerge/explorer/pkg_version create mode 100644 cdist/conf/type/__package_emerge/gencode-remote create mode 100644 cdist/conf/type/__package_emerge/man.text create mode 100644 cdist/conf/type/__package_emerge/parameter/optional diff --git a/cdist/conf/type/__package_emerge/explorer/pkg_version b/cdist/conf/type/__package_emerge/explorer/pkg_version new file mode 100644 index 00000000..7053eaff --- /dev/null +++ b/cdist/conf/type/__package_emerge/explorer/pkg_version @@ -0,0 +1,35 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Retrieve the status of a package +# + +if [ ! -x /usr/bin/equery ]; then + echo "gentoolkit not installed!" 1>&2 + exit 1 +fi + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +equery -q l -F '$cp $fullversion' "$name" || true diff --git a/cdist/conf/type/__package_emerge/gencode-remote b/cdist/conf/type/__package_emerge/gencode-remote new file mode 100644 index 00000000..d4cee37e --- /dev/null +++ b/cdist/conf/type/__package_emerge/gencode-remote @@ -0,0 +1,72 @@ +#!/bin/sh +# +# 2013 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 . +# +# +# Manage packages with Portage (mostly gentoo) +# + +if [ -f "$__object/parameter/name" ]; then + name="$__object/parameter/name" +else + name="$__object_id" +fi + +if [ -f "$__object/parameter/state" ]; then + state_should="$(cat "$__object/parameter/state")" +else + state_should="present" +fi + +pkg_version="$(cat "$__object/explorer/pkg_version")" +if [ -z "$pkg_version" ]; then + state_is="absent" +elif [ $(echo "$pkg_version" | wc -l) -gt 1 ]; then + echo "Package name is not unique! The following packages are installed:" + echo "$pkg_version" + exit 1 +else + state_is="present" + installed_version="$(echo "$pkg_version" | cut -d " " -f 2)" +fi + +if [ -f "$__object/parameter/version" ]; then + version="$(cat "$__object/parameter/version")" + if [ ! -z "$version" ]; then + name="=$name-$version" + fi +else + version="" +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 + +case "$state_should" in + present) + echo "emerge \"$name\" &>/dev/null || exit 1" + ;; + absent) + echo "emerge -C \"$name\" &>/dev/null || exit 1" + ;; + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__package_emerge/man.text b/cdist/conf/type/__package_emerge/man.text new file mode 100644 index 00000000..983b49a8 --- /dev/null +++ b/cdist/conf/type/__package_emerge/man.text @@ -0,0 +1,60 @@ +cdist-type__package_emerge(7) +============================= +Thomas Oettli + + +NAME +---- +cdist-type__package_emerge - Manage packages with portage + + +DESCRIPTION +----------- +Portage is usually used on the gentoo distribution to manage packages. +This type requires app-portage/gentoolkit installed on the target host. +cdist-type__package_emerge_dependencies is supposed to install the needed +packages on the target host. + + +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". + +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 + +# 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) + + +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). diff --git a/cdist/conf/type/__package_emerge/parameter/optional b/cdist/conf/type/__package_emerge/parameter/optional new file mode 100644 index 00000000..f5c897df --- /dev/null +++ b/cdist/conf/type/__package_emerge/parameter/optional @@ -0,0 +1,3 @@ +name +state +version From c48f31389f4e739615dca8194d50ab2c153e2b17 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 12 Dec 2013 10:59:45 +0100 Subject: [PATCH 377/548] initial submit of type __package_emerge_dependencies --- .../explorer/flaggie_installed | 7 +++ .../explorer/gentoolkit_installed | 7 +++ .../gencode-remote | 15 ++++++ .../__package_emerge_dependencies/man.text | 48 +++++++++++++++++++ .../__package_emerge_dependencies/singleton | 0 5 files changed, 77 insertions(+) create mode 100644 cdist/conf/type/__package_emerge_dependencies/explorer/flaggie_installed create mode 100644 cdist/conf/type/__package_emerge_dependencies/explorer/gentoolkit_installed create mode 100644 cdist/conf/type/__package_emerge_dependencies/gencode-remote create mode 100644 cdist/conf/type/__package_emerge_dependencies/man.text create mode 100644 cdist/conf/type/__package_emerge_dependencies/singleton diff --git a/cdist/conf/type/__package_emerge_dependencies/explorer/flaggie_installed b/cdist/conf/type/__package_emerge_dependencies/explorer/flaggie_installed new file mode 100644 index 00000000..1652ffc3 --- /dev/null +++ b/cdist/conf/type/__package_emerge_dependencies/explorer/flaggie_installed @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ -x /usr/bin/flaggie ]; then + echo "true" +else + echo "false" +fi diff --git a/cdist/conf/type/__package_emerge_dependencies/explorer/gentoolkit_installed b/cdist/conf/type/__package_emerge_dependencies/explorer/gentoolkit_installed new file mode 100644 index 00000000..74c2378d --- /dev/null +++ b/cdist/conf/type/__package_emerge_dependencies/explorer/gentoolkit_installed @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ -x /usr/bin/q ]; then + echo "true" +else + echo "false" +fi diff --git a/cdist/conf/type/__package_emerge_dependencies/gencode-remote b/cdist/conf/type/__package_emerge_dependencies/gencode-remote new file mode 100644 index 00000000..0c84e53d --- /dev/null +++ b/cdist/conf/type/__package_emerge_dependencies/gencode-remote @@ -0,0 +1,15 @@ +#!/bin/sh + +gentoolkit_installed="$(cat "$__object/explorer/gentoolkit_installed")" +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" +fi + +if [ "${flaggie_installed}" != "true" ]; then + # emerge app-portage/flaggie + echo "emerge app-portage/flaggie &> /dev/null || exit 1" +fi + diff --git a/cdist/conf/type/__package_emerge_dependencies/man.text b/cdist/conf/type/__package_emerge_dependencies/man.text new file mode 100644 index 00000000..0862256b --- /dev/null +++ b/cdist/conf/type/__package_emerge_dependencies/man.text @@ -0,0 +1,48 @@ +cdist-type__package_emerge_dependencies(7) +========================================== +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 + + +REQUIRED PARAMETERS +------------------- +None + + +OPTIONAL PARAMETERS +------------------- +None + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# 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) + + +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). diff --git a/cdist/conf/type/__package_emerge_dependencies/singleton b/cdist/conf/type/__package_emerge_dependencies/singleton new file mode 100644 index 00000000..e69de29b From 8749ce61783359944adb4c291746d0c823509c23 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 12 Dec 2013 18:04:49 +0100 Subject: [PATCH 378/548] +begin of discussion with steven Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-12-12.discussion | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 docs/dev/logs/2013-12-12.discussion diff --git a/docs/dev/logs/2013-12-12.discussion b/docs/dev/logs/2013-12-12.discussion new file mode 100644 index 00000000..58d25517 --- /dev/null +++ b/docs/dev/logs/2013-12-12.discussion @@ -0,0 +1,6 @@ +With Steven + +- Implement environments + - for configuring "anything" including switches + - can disable / use other global explorers +- 98% of our framework is generic and can be used for any applikation From 976ce8c44ee198e0426dc8e1ff3eb79ff3d7a7ba Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 13 Dec 2013 11:42:12 +0100 Subject: [PATCH 379/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index ff480a93..8aebcc3f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -18,6 +18,7 @@ Changelog * Type __cron: Add support for raw lines (Daniel Heule) * Type __key_value: Fix quoting issue (Steven Armstrong) * Type __package_zypper: Support non packages as well (Daniel Heule) + * Type __package_zypper: Support package versions (Daniel Heule) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From f165b5611e83745e2febb05dc916e9db948901a4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 13 Dec 2013 14:33:22 +0100 Subject: [PATCH 380/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 8aebcc3f..a8fe33b4 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,8 @@ Changelog * Core: Removed unused "changed" attribute of objects * New Type: __zypper_repo (Daniel Heule) * New Type: __zypper_service (Daniel Heule) + * New Type: __package_emerge (Daniel Heule) + * New Type: __package_emerge_dependencies (Daniel Heule) * Type: __iptables_rule: Use default parameter * Type __file: Do not generate code if mode is 0xxx * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) From 14dee79a9ba1149a05aea097025ab4fb57f8a54f Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 16 Dec 2013 13:29:43 +0100 Subject: [PATCH 381/548] handle parameter --state explicilty to respect defaults Signed-off-by: Steven Armstrong --- cdist/conf/type/__package/manifest | 8 +++++--- cdist/conf/type/__package/parameter/default/state | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 cdist/conf/type/__package/parameter/default/state diff --git a/cdist/conf/type/__package/manifest b/cdist/conf/type/__package/manifest index 6a84cb7f..0ebf0099 100755 --- a/cdist/conf/type/__package/manifest +++ b/cdist/conf/type/__package/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Steven Armstrong (steven-cdist at armstrong.cc) +# 2011-2013 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -44,10 +44,12 @@ else esac fi -set -- "$@" "$__object_id" +state="$(cat "$__object/parameter/state")" + +set -- "$@" "$__object_id" "--state" "$state" cd "$__object/parameter" for property in $(ls .); do - if [ "$property" != "type" ]; then + if [ "$property" != "type" -a "$property" != "state" ]; then set -- "$@" "--$property" "$(cat "$property")" fi done diff --git a/cdist/conf/type/__package/parameter/default/state b/cdist/conf/type/__package/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__package/parameter/default/state @@ -0,0 +1 @@ +present From aec163262741d9427057e0caeff3e0d6e16c7ef7 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 16 Dec 2013 16:19:27 +0100 Subject: [PATCH 382/548] on older systems, zypper service and zypper repos doesn't know the parameter -E, so we need a way which works on older releases too --- cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids | 4 +++- cdist/conf/type/__zypper_service/explorer/repo_ids | 5 ++++- cdist/conf/type/__zypper_service/explorer/service_id | 4 +++- cdist/conf/type/__zypper_service/explorer/service_ids | 4 +++- cdist/conf/type/__zypper_service/explorer/service_uri | 4 +++- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids index a0d092b1..2dfb946f 100644 --- a/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids +++ b/cdist/conf/type/__zypper_repo/explorer/enabled_repo_ids @@ -21,4 +21,6 @@ # Retrieve all repo id nummbers from enabled repos - parsed zypper output # # -echo $(zypper lr -E | cut -d'|' -f 1 | grep -E '^[0-9]') +# 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) diff --git a/cdist/conf/type/__zypper_service/explorer/repo_ids b/cdist/conf/type/__zypper_service/explorer/repo_ids index 8c32b40b..e831b76c 100644 --- a/cdist/conf/type/__zypper_service/explorer/repo_ids +++ b/cdist/conf/type/__zypper_service/explorer/repo_ids @@ -21,4 +21,7 @@ # Manage services with Zypper (mostly suse) # # -echo $(zypper lr -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') +# 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]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_id b/cdist/conf/type/__zypper_service/explorer/service_id index b473340c..9c3d3a2d 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_id +++ b/cdist/conf/type/__zypper_service/explorer/service_id @@ -25,4 +25,6 @@ if [ -f "$__object/parameter/service_uri" ]; then else uri="/$__object_id" fi -echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 1 ) +# 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 ) diff --git a/cdist/conf/type/__zypper_service/explorer/service_ids b/cdist/conf/type/__zypper_service/explorer/service_ids index 460b2006..0f1f4186 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_ids +++ b/cdist/conf/type/__zypper_service/explorer/service_ids @@ -20,4 +20,6 @@ # # Manage services with Zypper (mostly suse) # -echo $(zypper ls -u -E | cut -d'|' -f 1 | grep -E '^[0-9]') +# 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]') diff --git a/cdist/conf/type/__zypper_service/explorer/service_uri b/cdist/conf/type/__zypper_service/explorer/service_uri index aec93cb2..2f4f8960 100644 --- a/cdist/conf/type/__zypper_service/explorer/service_uri +++ b/cdist/conf/type/__zypper_service/explorer/service_uri @@ -25,4 +25,6 @@ if [ -f "$__object/parameter/service_uri" ]; then else uri="/$__object_id" fi -echo $(zypper ls -u -E | grep -E "\<$uri\>" | cut -d'|' -f 7 ) +# 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 ) From a70d478f9e6b26d86f51615e2087ad4df854e79f Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 16 Dec 2013 17:07:49 +0100 Subject: [PATCH 383/548] fixed a minor type with param remove-all-other-services --- cdist/conf/type/__zypper_service/man.text | 4 ++-- cdist/conf/type/__zypper_service/parameter/boolean | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__zypper_service/man.text b/cdist/conf/type/__zypper_service/man.text index b1717c96..31543d93 100644 --- a/cdist/conf/type/__zypper_service/man.text +++ b/cdist/conf/type/__zypper_service/man.text @@ -33,7 +33,7 @@ type:: BOOLEAN PARAMETERS ------------------ -remove-all-other-service:: +remove-all-other-services:: Drop all other services found on the target host before adding the new one. remove-all-repos:: @@ -45,7 +45,7 @@ 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" --service_uri "http://path/to/your/ris/dir" --remove-all-other-service --remove-all-repos +__zypper_service INTERNAL_SLES11_SP3 --service_desc "Internal SLES11 SP3 RIS" --service_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" --service_uri "http://path/to/your/ris/dir" diff --git a/cdist/conf/type/__zypper_service/parameter/boolean b/cdist/conf/type/__zypper_service/parameter/boolean index bc6a5629..ca711ded 100644 --- a/cdist/conf/type/__zypper_service/parameter/boolean +++ b/cdist/conf/type/__zypper_service/parameter/boolean @@ -1,2 +1,2 @@ -remove-all-other-service +remove-all-other-services remove-all-repos From 138d26e398ae333db032adad78ac608426c2d7e0 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 17 Dec 2013 14:13:20 +0100 Subject: [PATCH 384/548] extended type __user: parameter state, system, remove-home new --- cdist/conf/type/__user/TODO | 2 - cdist/conf/type/__user/explorer/group | 0 cdist/conf/type/__user/explorer/passwd | 0 cdist/conf/type/__user/explorer/shadow | 0 cdist/conf/type/__user/gencode-remote | 153 ++++++++++-------- cdist/conf/type/__user/man.text | 28 +++- cdist/conf/type/__user/parameter/boolean | 2 + .../conf/type/__user/parameter/default/state | 1 + cdist/conf/type/__user/parameter/optional | 1 + 9 files changed, 113 insertions(+), 74 deletions(-) delete mode 100644 cdist/conf/type/__user/TODO mode change 100755 => 100644 cdist/conf/type/__user/explorer/group mode change 100755 => 100644 cdist/conf/type/__user/explorer/passwd mode change 100755 => 100644 cdist/conf/type/__user/explorer/shadow mode change 100755 => 100644 cdist/conf/type/__user/gencode-remote create mode 100644 cdist/conf/type/__user/parameter/default/state diff --git a/cdist/conf/type/__user/TODO b/cdist/conf/type/__user/TODO deleted file mode 100644 index fa6aeee7..00000000 --- a/cdist/conf/type/__user/TODO +++ /dev/null @@ -1,2 +0,0 @@ -- delete users - diff --git a/cdist/conf/type/__user/explorer/group b/cdist/conf/type/__user/explorer/group old mode 100755 new mode 100644 diff --git a/cdist/conf/type/__user/explorer/passwd b/cdist/conf/type/__user/explorer/passwd old mode 100755 new mode 100644 diff --git a/cdist/conf/type/__user/explorer/shadow b/cdist/conf/type/__user/explorer/shadow old mode 100755 new mode 100644 diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote old mode 100755 new mode 100644 index a2cdfd22..de559435 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -2,6 +2,7 @@ # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -21,11 +22,14 @@ # # Manage users. # +#set -x name="$__object_id" os="$(cat "$__global/explorer/os")" +state=$(cat "$__object/parameter/state") + # We need to shorten options for both usermod and useradd since on some # systems (such as *BSD, Darwin) those commands do not handle GNU style long # options. @@ -40,80 +44,97 @@ shorten_property() { shell) ret="-s";; uid) ret="-u";; create-home) ret="-m";; + system) ret="-r";; esac echo "$ret" } -cd "$__object/parameter" -if grep -q "^${name}:" "$__object/explorer/passwd"; then - for property in $(ls .); do - new_value="$(cat "$property")" - unset current_value +if [ "$state" = "present" ]; then + cd "$__object/parameter" + if grep -q "^${name}:" "$__object/explorer/passwd"; then + for property in $(ls .); do + new_value="$(cat "$property")" + unset current_value - file="$__object/explorer/passwd" + file="$__object/explorer/passwd" - case "$property" in - gid) - if $(echo "$new_value" | grep -q '^[0-9][0-9]*$'); then - field=4 + case "$property" in + gid) + if $(echo "$new_value" | grep -q '^[0-9][0-9]*$'); then + field=4 + else + # We were passed a group name. Compare the gid in + # the user's /etc/passwd entry with the gid of the + # group returned by the group explorer. + gid_from_group=$(awk -F: '{ print $3 }' "$__object/explorer/group") + gid_from_passwd=$(awk -F: '{ print $4 }' "$file") + if [ "$gid_from_group" != "$gid_from_passwd" ]; then + current_value="$gid_from_passwd" + else + current_value="$new_value" + fi + fi + ;; + password) + field=2 + file="$__object/explorer/shadow" + ;; + comment) field=5 ;; + home) field=6 ;; + shell) field=7 ;; + uid) field=3 ;; + create-home) continue;; # Does not apply to user modification + system) continue;; # Does not apply to user modification + state) continue;; # Does not apply to user modification + remove-home) continue;; # Does not apply to user modification + esac + + # If we haven't already set $current_value above, pull it from the + # appropriate file/field. + if [ -z "$current_value" ]; then + export field + current_value="$(awk -F: '{ print $ENVIRON["field"] }' < "$file")" + fi + + if [ "$new_value" != "$current_value" ]; then + set -- "$@" "$(shorten_property $property)" \'$new_value\' + fi + done + + if [ $# -gt 0 ]; then + if [ "$os" = "freebsd" ]; then + echo pw usermod "$@" "$name" + else + echo usermod "$@" "$name" + fi + else + true + fi + else + for property in $(ls .); do + [ "$property" = "state" ] && continue + [ "$property" = "remove-home" ] && continue + new_value="$(cat "$property")" + if [ -z "$new_value" ];then # Boolean values have no value + set -- "$@" "$(shorten_property $property)" else - # We were passed a group name. Compare the gid in - # the user's /etc/passwd entry with the gid of the - # group returned by the group explorer. - gid_from_group=$(awk -F: '{ print $3 }' "$__object/explorer/group") - gid_from_passwd=$(awk -F: '{ print $4 }' "$file") - if [ "$gid_from_group" != "$gid_from_passwd" ]; then - current_value="$gid_from_passwd" - else - current_value="$new_value" - fi + set -- "$@" "$(shorten_property $property)" \'$new_value\' fi - ;; - password) - field=2 - file="$__object/explorer/shadow" - ;; - comment) field=5 ;; - home) field=6 ;; - shell) field=7 ;; - uid) field=3 ;; - create-home) continue;; # Does not apply to user modification - esac + done - # If we haven't already set $current_value above, pull it from the - # appropriate file/field. - if [ -z "$current_value" ]; then - export field - current_value="$(awk -F: '{ print $ENVIRON["field"] }' < "$file")" - fi - - if [ "$new_value" != "$current_value" ]; then - set -- "$@" "$(shorten_property $property)" \'$new_value\' - fi - done - - if [ $# -gt 0 ]; then - if [ "$os" = "freebsd" ]; then - echo pw usermod "$@" "$name" - else - echo usermod "$@" "$name" - fi - else - true - fi + if [ "$os" = "freebsd" ]; then + echo pw useradd "$@" "$name" + else + echo useradd "$@" "$name" + fi + fi else - for property in $(ls .); do - new_value="$(cat "$property")" - if [ -z "$new_value" ];then # Boolean values have no value - set -- "$@" "$(shorten_property $property)" - else - set -- "$@" "$(shorten_property $property)" \'$new_value\' - fi - done - - if [ "$os" = "freebsd" ]; then - echo pw useradd "$@" "$name" - else - echo useradd "$@" "$name" - fi + 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}" + else + echo userdel "${name}" + fi + fi fi diff --git a/cdist/conf/type/__user/man.text b/cdist/conf/type/__user/man.text index 9db4a9f0..2536c1bc 100644 --- a/cdist/conf/type/__user/man.text +++ b/cdist/conf/type/__user/man.text @@ -20,19 +20,29 @@ None. OPTIONAL PARAMETERS ------------------- +state:: + absent or present, defaults to present comment:: - see usermod(8) + see usermod(8) home:: - see above + see above gid:: - see above + see above password:: - see above + see above shell:: - see above + see above uid:: - see above + see above +system:: + see above +BOOLEAN PARAMETERS +------------------ +create-home:: + see useradd(8), apply only on user create +remove-home:: + see userdel(8), apply only on user delete EXAMPLES -------- @@ -44,8 +54,14 @@ __user foobar # Same but with a different shell __user foobar --shell /bin/zsh +# Same but for a system account +__user foobar --system + # Set explicit uid and home __user foobar --uid 1001 --shell /bin/zsh --home /home/foobar + +# Drop user if exists +__user foobar --state absent -------------------------------------------------------------------------------- diff --git a/cdist/conf/type/__user/parameter/boolean b/cdist/conf/type/__user/parameter/boolean index e0517c6a..83afdebe 100644 --- a/cdist/conf/type/__user/parameter/boolean +++ b/cdist/conf/type/__user/parameter/boolean @@ -1 +1,3 @@ create-home +remove-home +system diff --git a/cdist/conf/type/__user/parameter/default/state b/cdist/conf/type/__user/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__user/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__user/parameter/optional b/cdist/conf/type/__user/parameter/optional index e3cf52d5..de6c3838 100644 --- a/cdist/conf/type/__user/parameter/optional +++ b/cdist/conf/type/__user/parameter/optional @@ -1,3 +1,4 @@ +state comment home gid From 7d4c11a1860ffc6ef63c897264a19d9fc70507d7 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 17 Dec 2013 14:15:41 +0100 Subject: [PATCH 385/548] reset false mode changes --- cdist/conf/type/__user/explorer/group | 0 cdist/conf/type/__user/explorer/passwd | 0 cdist/conf/type/__user/explorer/shadow | 0 cdist/conf/type/__user/gencode-remote | 0 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 cdist/conf/type/__user/explorer/group mode change 100644 => 100755 cdist/conf/type/__user/explorer/passwd mode change 100644 => 100755 cdist/conf/type/__user/explorer/shadow mode change 100644 => 100755 cdist/conf/type/__user/gencode-remote diff --git a/cdist/conf/type/__user/explorer/group b/cdist/conf/type/__user/explorer/group old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__user/explorer/passwd b/cdist/conf/type/__user/explorer/passwd old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__user/explorer/shadow b/cdist/conf/type/__user/explorer/shadow old mode 100644 new mode 100755 diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote old mode 100644 new mode 100755 From 87336f9b4f3e7f7ed7967bd69342fe466a626ebe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Dec 2013 17:20:30 +0100 Subject: [PATCH 386/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index a8fe33b4..0a6ba0a1 100644 --- a/docs/changelog +++ b/docs/changelog @@ -21,6 +21,7 @@ Changelog * Type __key_value: Fix quoting issue (Steven Armstrong) * Type __package_zypper: Support non packages as well (Daniel Heule) * Type __package_zypper: Support package versions (Daniel Heule) + * Type __package: Use state --present by default (Steven Armstrong) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From 122fb9665411d16ad2b2207d10435d58574d3cd8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Dec 2013 18:09:57 +0100 Subject: [PATCH 387/548] use default parameter for __start_on_boot type Signed-off-by: Nico Schottelius --- cdist/conf/type/__start_on_boot/gencode-remote | 2 +- cdist/conf/type/__start_on_boot/parameter/default/state | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 cdist/conf/type/__start_on_boot/parameter/default/state diff --git a/cdist/conf/type/__start_on_boot/gencode-remote b/cdist/conf/type/__start_on_boot/gencode-remote index 58ff6a4a..a8abebbc 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -19,7 +19,7 @@ # # -state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo present)" +state_should="$(cat "$__object/parameter/state")" state_is=$(cat "$__object/explorer/state") # Short circuit if nothing is to be done diff --git a/cdist/conf/type/__start_on_boot/parameter/default/state b/cdist/conf/type/__start_on_boot/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__start_on_boot/parameter/default/state @@ -0,0 +1 @@ +present From 7d46156fd6becff0d70154ac678d3142d9bf93f9 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 18 Dec 2013 18:13:32 +0100 Subject: [PATCH 388/548] changes for __start_on_boot Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 0a6ba0a1..a8a686dd 100644 --- a/docs/changelog +++ b/docs/changelog @@ -22,6 +22,7 @@ Changelog * Type __package_zypper: Support non packages as well (Daniel Heule) * Type __package_zypper: Support package versions (Daniel Heule) * Type __package: Use state --present by default (Steven Armstrong) + * Type __start_on_boot: Use default parameter state 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From e5253e0330c2e5ad15dd3e38e4f7cfde6af3228f Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 19 Dec 2013 08:14:29 +0100 Subject: [PATCH 389/548] correct man page text of system parameter --- cdist/conf/type/__user/man.text | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__user/man.text b/cdist/conf/type/__user/man.text index 2536c1bc..47e63d3d 100644 --- a/cdist/conf/type/__user/man.text +++ b/cdist/conf/type/__user/man.text @@ -34,11 +34,11 @@ shell:: see above uid:: see above -system:: - see above BOOLEAN PARAMETERS ------------------ +system:: + see useradd(8), apply only on user create create-home:: see useradd(8), apply only on user create remove-home:: From 9d54eb7257a3b27830fc92f0855f6c01d807be8d Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 19 Dec 2013 11:21:26 +0100 Subject: [PATCH 390/548] implement messaging for __group type Signed-off-by: Steven Armstrong --- cdist/conf/type/__group/gencode-remote | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cdist/conf/type/__group/gencode-remote b/cdist/conf/type/__group/gencode-remote index bb6797c2..1cffa8d4 100755 --- a/cdist/conf/type/__group/gencode-remote +++ b/cdist/conf/type/__group/gencode-remote @@ -58,10 +58,12 @@ if grep -q "^${name}:" "$__object/explorer/group"; then if [ "$new_value" != "$current_value" ]; then set -- "$@" "$proparg" \"$new_value\" + echo change $property $new_value $current_value >> "$__messages_out" fi done if [ $# -gt 0 ]; then + echo mod >> "$__messages_out" case $os in freebsd) echo pw group mod "$@" "$name" @@ -72,6 +74,7 @@ if grep -q "^${name}:" "$__object/explorer/group"; then esac fi else + echo add >> "$__messages_out" for property in $(ls .); do new_value="$(cat "$property")" if [ "$os" = "freebsd" ]; then @@ -95,6 +98,7 @@ else fi set -- "$@" "$proparg" \"$new_value\" + echo set $property $new_value >> "$__messages_out" done case $os in From 80fffbad1116d215669d2a716b1bc629f47ef6a5 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 19 Dec 2013 11:21:44 +0100 Subject: [PATCH 391/548] implement messaging for __user type Signed-off-by: Steven Armstrong --- cdist/conf/type/__user/gencode-remote | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cdist/conf/type/__user/gencode-remote b/cdist/conf/type/__user/gencode-remote index a2cdfd22..892bb8e1 100755 --- a/cdist/conf/type/__user/gencode-remote +++ b/cdist/conf/type/__user/gencode-remote @@ -89,10 +89,12 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then if [ "$new_value" != "$current_value" ]; then set -- "$@" "$(shorten_property $property)" \'$new_value\' + echo change $property $new_value $current_value >> "$__messages_out" fi done if [ $# -gt 0 ]; then + echo mod >> "$__messages_out" if [ "$os" = "freebsd" ]; then echo pw usermod "$@" "$name" else @@ -102,12 +104,15 @@ if grep -q "^${name}:" "$__object/explorer/passwd"; then true fi else + echo add >> "$__messages_out" for property in $(ls .); do new_value="$(cat "$property")" if [ -z "$new_value" ];then # Boolean values have no value set -- "$@" "$(shorten_property $property)" + echo set $property >> "$__messages_out" else set -- "$@" "$(shorten_property $property)" \'$new_value\' + echo set $property $new_value >> "$__messages_out" fi done From d6f84d1ef0069c3663f56864626daed5d43370f8 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 19 Dec 2013 13:54:16 +0100 Subject: [PATCH 392/548] __start_on_boot incl. gentoo support --- cdist/conf/type/__start_on_boot/explorer/state | 8 ++++++-- cdist/conf/type/__start_on_boot/gencode-remote | 16 ++++++++-------- cdist/conf/type/__start_on_boot/man.text | 4 +++- .../parameter/default/target_runlevel | 1 + .../conf/type/__start_on_boot/parameter/optional | 1 + 5 files changed, 19 insertions(+), 11 deletions(-) create mode 100644 cdist/conf/type/__start_on_boot/parameter/default/target_runlevel diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 4e0c82c2..62f86332 100755 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -1,6 +1,7 @@ #!/bin/sh # # 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -23,9 +24,9 @@ os=$("$__explorer/os") runlevel=$("$__explorer/runlevel") +target_runlevel="$(cat "$__object/parameter/target_runlevel")" name="$__object_id" - case "$os" in archlinux) state=$(systemctl is-enabled "$name" >/dev/null 2>&1 \ @@ -42,7 +43,10 @@ case "$os" in state=$(chkconfig --level "$runlevel" "$name" || echo absent) [ "$state" ] || state="present" ;; - + gentoo) + state="present" + [ -f "/etc/runlevels/${target_runlevel}/${name}" ] || state="absent" + ;; *) 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 a8abebbc..61b2b9fe 100755 --- a/cdist/conf/type/__start_on_boot/gencode-remote +++ b/cdist/conf/type/__start_on_boot/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -21,6 +22,7 @@ state_should="$(cat "$__object/parameter/state")" state_is=$(cat "$__object/explorer/state") +target_runlevel="$(cat "$__object/parameter/target_runlevel")" # Short circuit if nothing is to be done [ "$state_should" = "$state_is" ] && exit 0 @@ -38,10 +40,9 @@ case "$state_should" in echo "update-rc.d \"$name\" defaults >/dev/null" ;; -# FIXME: Disabled until the explorer is checked -# gentoo) -# echo rc-update add \"$name\" default -# ;; + gentoo) + echo rc-update add \"$name\" \"$target_runlevel\" + ;; amazon|centos|fedora|owl|redhat|suse) echo chkconfig \"$name\" on @@ -70,10 +71,9 @@ case "$state_should" in echo update-rc.d -f \"$name\" remove ;; -# FIXME: Disabled until the explorer is checked -# gentoo) -# echo rc-update del \"$name\" -# ;; + gentoo) + echo rc-update del \"$name\" \"$target_runlevel\" + ;; centos|fedora|owl|redhat|suse) echo chkconfig \"$name\" off diff --git a/cdist/conf/type/__start_on_boot/man.text b/cdist/conf/type/__start_on_boot/man.text index 6d804884..dfada6d8 100644 --- a/cdist/conf/type/__start_on_boot/man.text +++ b/cdist/conf/type/__start_on_boot/man.text @@ -14,7 +14,7 @@ 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. gentoo and *bsd are not implemented). +supported (i.e. *bsd are not implemented). REQUIRED PARAMETERS @@ -25,6 +25,8 @@ OPTIONAL PARAMETERS ------------------- state:: Either "present" or "absent", defaults to "present" +target_runlevel:: + Runlevel which should be modified, defaults to "default" (only used on gentoo systems). EXAMPLES diff --git a/cdist/conf/type/__start_on_boot/parameter/default/target_runlevel b/cdist/conf/type/__start_on_boot/parameter/default/target_runlevel new file mode 100644 index 00000000..4ad96d51 --- /dev/null +++ b/cdist/conf/type/__start_on_boot/parameter/default/target_runlevel @@ -0,0 +1 @@ +default diff --git a/cdist/conf/type/__start_on_boot/parameter/optional b/cdist/conf/type/__start_on_boot/parameter/optional index ff72b5c7..91685caf 100644 --- a/cdist/conf/type/__start_on_boot/parameter/optional +++ b/cdist/conf/type/__start_on_boot/parameter/optional @@ -1 +1,2 @@ state +target_runlevel From 17d36fdfab850739aab0ad4293b3f140afd97b95 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 19 Dec 2013 14:35:36 +0100 Subject: [PATCH 393/548] update changes for 3.0.0 release (5 more days to go) Signed-off-by: Nico Schottelius --- docs/changelog | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/changelog b/docs/changelog index a8a686dd..4c689392 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,23 +6,24 @@ Changelog 3.0.0: - * Core: Messaging support added + * Core: Added messaging support * Core: Removed unused "changed" attribute of objects * New Type: __zypper_repo (Daniel Heule) * New Type: __zypper_service (Daniel Heule) * New Type: __package_emerge (Daniel Heule) * New Type: __package_emerge_dependencies (Daniel Heule) - * Type: __iptables_rule: Use default parameter + * Type __cron: Add support for raw lines (Daniel Heule) * Type __file: Do not generate code if mode is 0xxx + * Type: __iptables_rule: Use default parameter + * Type __key_value: Fix quoting issue (Steven Armstrong) + * Type __package: Use state --present by default (Steven Armstrong) + * Type __package_zypper: Support non packages as well (Daniel Heule) + * Type __package_zypper: Support package versions (Daniel Heule) * Type __postfix_*: Depend on __postfix Type (Steven Armstrong) * Type __postfix_postconf: Enable support for SuSE (Daniel Heule) * Type __postfix: Enable support for SuSE (Daniel Heule) - * Type __cron: Add support for raw lines (Daniel Heule) - * Type __key_value: Fix quoting issue (Steven Armstrong) - * Type __package_zypper: Support non packages as well (Daniel Heule) - * Type __package_zypper: Support package versions (Daniel Heule) - * Type __package: Use state --present by default (Steven Armstrong) * Type __start_on_boot: Use default parameter state + * Type __start_on_boot: Add support for gentoo (Daniel Heule) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From c50925cab5b6a8d5647092a46a5893fff944c4e9 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 19 Dec 2013 14:45:55 +0100 Subject: [PATCH 394/548] bugfix in __cron type, was a wrong quoting --- cdist/conf/type/__cron/explorer/entry | 0 cdist/conf/type/__cron/gencode-remote | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) mode change 100755 => 100644 cdist/conf/type/__cron/explorer/entry mode change 100644 => 100755 cdist/conf/type/__cron/gencode-remote diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry old mode 100755 new mode 100644 diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote old mode 100644 new mode 100755 index e84cf66a..712eb1a1 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -60,7 +60,7 @@ prefix="#cdist:__cron/$__object_id" suffix="#/cdist:__cron/$__object_id" filter="^# DO NOT EDIT THIS FILE|^# \(.* installed on |^# \(Cron version V" cat << DONE -crontab -u $user -l | grep -v -E "$filter" | awk -v prefix="$prefix" -v suffix="$suffix" ' +crontab -u $user -l 2>/dev/null | grep -v -E "$filter" | awk -v prefix="$prefix" -v suffix="$suffix" ' { if (index(\$0,prefix)) { triggered=1 @@ -79,12 +79,12 @@ DONE case "$state_should" in present) echo "(" - echo "crontab -u $user -l | grep -v -E "$filter" 2>/dev/null || true" + echo "crontab -u $user -l 2>/dev/null | grep -v -E \"$filter\" 2>/dev/null || true" echo "echo '$entry'" echo ") | crontab -u $user -" ;; absent) - echo "( crontab -u $user -l | grep -v -E "$filter" 2>/dev/null || true ) | \\" + echo "( crontab -u $user -l 2>/dev/null | grep -v -E \"$filter\" 2>/dev/null || true ) | \\" echo "grep -v \"# $name\\$\" | crontab -u $user -" ;; esac From ad5c105858692fc5dd09fb641a43ae08a438ade0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 19 Dec 2013 15:06:51 +0100 Subject: [PATCH 395/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 4c689392..764386b9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -13,6 +13,8 @@ Changelog * New Type: __package_emerge (Daniel Heule) * New Type: __package_emerge_dependencies (Daniel Heule) * Type __cron: Add support for raw lines (Daniel Heule) + * Type __cron: Suppress stderr output from crontab (Daniel Heule) + * Type __cron: Fix quoting issue (Daniel Heule) * Type __file: Do not generate code if mode is 0xxx * Type: __iptables_rule: Use default parameter * Type __key_value: Fix quoting issue (Steven Armstrong) From 67f61eb7ec12745b9ab7c87eb014ee7fae96a0a7 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 19 Dec 2013 23:33:43 +0100 Subject: [PATCH 396/548] make default values for optional_multiple parameters work Signed-off-by: Steven Armstrong --- cdist/emulator.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index b1cd8f2d..1e530fec 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -37,6 +37,21 @@ class MissingRequiredEnvironmentVariableError(cdist.Error): return self.message +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 + """ + def __copy__(self): + return [] + + @classmethod + def create(cls, initial=None): + if initial: + initial = initial.split('\n') + return cls(initial) + + class Emulator(object): def __init__(self, argv, stdin=sys.stdin.buffer, env=os.environ): self.argv = argv @@ -101,7 +116,7 @@ class Emulator(object): for parameter in self.cdist_type.optional_multiple_parameters: argument = "--" + parameter parser.add_argument(argument, dest=parameter, action='append', required=False, - default=self.cdist_type.parameter_defaults.get(parameter, None)) + default=DefaultList.create(self.cdist_type.parameter_defaults.get(parameter, None))) for parameter in self.cdist_type.boolean_parameters: argument = "--" + parameter parser.add_argument(argument, dest=parameter, action='store_const', const='') From 3c1e001f5e07335e6c2c4f9e79f3b17db751c34b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Dec 2013 08:46:33 +0100 Subject: [PATCH 397/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 764386b9..bc1b894d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -26,6 +26,8 @@ Changelog * Type __postfix: Enable support for SuSE (Daniel Heule) * Type __start_on_boot: Use default parameter state * Type __start_on_boot: Add support for gentoo (Daniel Heule) + * Type __user: Add support for state parameter (Daniel Heule) + * Type __user: Add support for system users (Daniel Heule) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From b99af6663c8c58d70c9b4bda4fe279e0bae102a2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Dec 2013 08:50:45 +0100 Subject: [PATCH 398/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index bc1b894d..abe8626f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ Changelog 3.0.0: * Core: Added messaging support * Core: Removed unused "changed" attribute of objects + * Core: Support default values for multiple parameters (Steven Armstrong) * New Type: __zypper_repo (Daniel Heule) * New Type: __zypper_service (Daniel Heule) * New Type: __package_emerge (Daniel Heule) From e5ab33651da3445572a068f0d3def154f4b0daa5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Dec 2013 08:54:16 +0100 Subject: [PATCH 399/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index abe8626f..a5f5d102 100644 --- a/docs/changelog +++ b/docs/changelog @@ -29,6 +29,7 @@ Changelog * Type __start_on_boot: Add support for gentoo (Daniel Heule) * Type __user: Add support for state parameter (Daniel Heule) * Type __user: Add support for system users (Daniel Heule) + * Type __user: Add messaging support (Steven Armstrong) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From d84a43960ba7c0e17bca917fc0d8b2bc2022b921 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Dec 2013 08:56:23 +0100 Subject: [PATCH 400/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index a5f5d102..c51d38c9 100644 --- a/docs/changelog +++ b/docs/changelog @@ -30,6 +30,7 @@ Changelog * Type __user: Add support for state parameter (Daniel Heule) * Type __user: Add support for system users (Daniel Heule) * Type __user: Add messaging support (Steven Armstrong) + * Type __zypper_service: Support older SuSE releases (Daniel Heule) 2.3.7: 2013-12-02 * Type __file: Secure the file transfer by using mktemp (Steven Armstrong) From 8b0eb5766af4fb4545baa116237690e58ed36dec Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 20 Dec 2013 10:56:46 +0100 Subject: [PATCH 401/548] bugfix: handle non-existent default Signed-off-by: Steven Armstrong --- cdist/emulator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 1e530fec..78597621 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -48,8 +48,8 @@ class DefaultList(list): @classmethod def create(cls, initial=None): if initial: - initial = initial.split('\n') - return cls(initial) + return cls(initial.split('\n')) + return cls() class Emulator(object): From 39f65d2ef7b3756bc7610b10bf136e5e8d97911c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Fri, 20 Dec 2013 11:17:43 +0100 Subject: [PATCH 402/548] leave conversion of list to underlying fsproperty Signed-off-by: Steven Armstrong --- cdist/emulator.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 1e530fec..15728215 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -143,8 +143,6 @@ class Emulator(object): self.parameters = {} for key,value in vars(self.args).items(): if value is not None: - if isinstance(value, list): - value = '\n'.join(value) self.parameters[key] = value if self.cdist_object.exists: From 29ae02565cbdb1b5a190b7caad5ebd3f155b71ac Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 20 Dec 2013 22:57:15 +0100 Subject: [PATCH 403/548] ++changes(3.0.0) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index c51d38c9..7be233dc 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * Core: Added messaging support * Core: Removed unused "changed" attribute of objects * Core: Support default values for multiple parameters (Steven Armstrong) + * Core: Ensure Object Parameter file contains \n (Steven Armstrong) * New Type: __zypper_repo (Daniel Heule) * New Type: __zypper_service (Daniel Heule) * New Type: __package_emerge (Daniel Heule) From 08762330e177729372349b3fdde67e81a9fd3377 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 21 Dec 2013 21:59:47 +0100 Subject: [PATCH 404/548] default to None, not empty list Signed-off-by: Steven Armstrong --- cdist/emulator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index c9ce663a..b70ef956 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -49,7 +49,6 @@ class DefaultList(list): def create(cls, initial=None): if initial: return cls(initial.split('\n')) - return cls() class Emulator(object): From 49bdd83ea1191bf684c3e680b65cf9080d65cb81 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 21 Dec 2013 22:00:57 +0100 Subject: [PATCH 405/548] test for feature instead of type Signed-off-by: Steven Armstrong --- cdist/util/fsproperty.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/util/fsproperty.py b/cdist/util/fsproperty.py index 5814b2b4..797c929b 100644 --- a/cdist/util/fsproperty.py +++ b/cdist/util/fsproperty.py @@ -134,7 +134,11 @@ class DirectoryDict(collections.MutableMapping): def __setitem__(self, key, value): try: with open(os.path.join(self.path, key), "w") as fd: - if type(value) == type([]): + if (not hasattr(value, 'strip') and + hasattr(value, '__getitem__') or + hasattr(value, '__iter__')): + # if it looks like a sequence and quacks like a sequence, + # it is a sequence for v in value: fd.write(str(v) + '\n') else: From 7ab5cd35acafcb8b20a118cc1884e3e90ff0db42 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 21 Dec 2013 22:49:06 +0100 Subject: [PATCH 406/548] missing parens -> matched what we did not want to match Signed-off-by: Steven Armstrong --- cdist/util/fsproperty.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/util/fsproperty.py b/cdist/util/fsproperty.py index 797c929b..49d4a32d 100644 --- a/cdist/util/fsproperty.py +++ b/cdist/util/fsproperty.py @@ -135,8 +135,8 @@ class DirectoryDict(collections.MutableMapping): try: 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, '__getitem__') or + hasattr(value, '__iter__'))): # if it looks like a sequence and quacks like a sequence, # it is a sequence for v in value: From 2b0210b905a285c865c2759edee6e549622c225f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 24 Dec 2013 23:05:56 +0100 Subject: [PATCH 407/548] update releasedate Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 7be233dc..586411fa 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.0.0: +3.0.0: 2013-12-24 * Core: Added messaging support * Core: Removed unused "changed" attribute of objects * Core: Support default values for multiple parameters (Steven Armstrong) From 241d8e6c3ab1817094e4c94e7c8cec51c0bb2ebf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 24 Dec 2013 23:07:43 +0100 Subject: [PATCH 408/548] fix typo Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 586411fa..ee3e4c9c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -18,7 +18,7 @@ Changelog * Type __cron: Suppress stderr output from crontab (Daniel Heule) * Type __cron: Fix quoting issue (Daniel Heule) * Type __file: Do not generate code if mode is 0xxx - * Type: __iptables_rule: Use default parameter + * Type __iptables_rule: Use default parameter * Type __key_value: Fix quoting issue (Steven Armstrong) * Type __package: Use state --present by default (Steven Armstrong) * Type __package_zypper: Support non packages as well (Daniel Heule) From 37e1c95bf0ca2d415d23c1a7b2729947e1249291 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 24 Dec 2013 23:25:54 +0100 Subject: [PATCH 409/548] add link to messaging Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 9e47fccc..338cf9f8 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -55,6 +55,11 @@ To upgrade to the lastet version do ## General Update Instructions +### Updating from 2.3 to 3.0 + +The **changed** attribute of objects has been removed. +Use [messaging](man/3.0.0/man7/cdist-messaging.html) instead. + ### Updating from 2.2 to 2.3 No incompatiblities. From b0b0e46f037882d1bca3b4ca8ba807e8ab94b772 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 24 Dec 2013 23:29:13 +0100 Subject: [PATCH 410/548] update link to messaging Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index 338cf9f8..aea33c08 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -58,7 +58,7 @@ To upgrade to the lastet version do ### Updating from 2.3 to 3.0 The **changed** attribute of objects has been removed. -Use [messaging](man/3.0.0/man7/cdist-messaging.html) instead. +Use [messaging](../man/3.0.0/man7/cdist-messaging.html) instead. ### Updating from 2.2 to 2.3 From 9e153f5c18a6c2afe75cefa2b72f3369a87eb453 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 24 Dec 2013 23:30:33 +0100 Subject: [PATCH 411/548] use absolute links Signed-off-by: Nico Schottelius --- docs/web/cdist/update.mdwn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web/cdist/update.mdwn b/docs/web/cdist/update.mdwn index aea33c08..2e3e9b92 100644 --- a/docs/web/cdist/update.mdwn +++ b/docs/web/cdist/update.mdwn @@ -58,7 +58,7 @@ To upgrade to the lastet version do ### Updating from 2.3 to 3.0 The **changed** attribute of objects has been removed. -Use [messaging](../man/3.0.0/man7/cdist-messaging.html) instead. +Use [messaging](/software/cdist/man/3.0.0/man7/cdist-messaging.html) instead. ### Updating from 2.2 to 2.3 From dc8e9c68552a7a5d418af349800da5b2368a693b Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 7 Jan 2014 13:23:39 +0100 Subject: [PATCH 412/548] fix typo on optional parameter which is only a passthrough to __package_zypper --- cdist/conf/type/__package/parameter/optional | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__package/parameter/optional b/cdist/conf/type/__package/parameter/optional index 5a89ffc6..d674f32e 100644 --- a/cdist/conf/type/__package/parameter/optional +++ b/cdist/conf/type/__package/parameter/optional @@ -3,4 +3,4 @@ version type pkgsite state -pstate +ptype From d2c45717f1172d83d64209cad12d1c84f3e16974 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 7 Jan 2014 16:31:32 +0100 Subject: [PATCH 413/548] install rubygems for ubuntu/debian Signed-off-by: Steven Armstrong --- cdist/conf/type/__package_rubygem/manifest | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 cdist/conf/type/__package_rubygem/manifest diff --git a/cdist/conf/type/__package_rubygem/manifest b/cdist/conf/type/__package_rubygem/manifest new file mode 100755 index 00000000..7199d939 --- /dev/null +++ b/cdist/conf/type/__package_rubygem/manifest @@ -0,0 +1,33 @@ +#!/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 + debian|ubuntu) + __package rubygems + ;; + *) + 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 6dcf3e7c2651f656466bbf80915fd4cc661cf16c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Jan 2014 17:03:14 +0100 Subject: [PATCH 414/548] ++changes(3.0.1) Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index ee3e4c9c..6eebc74e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +3.0.1: + * Type __package: Fix typo in optional parameter ptype (Daniel Heule) + * Type __package_rubygems: Require rubygems prior to use (Steven Armstrong) 3.0.0: 2013-12-24 * Core: Added messaging support From f5cee7a57d419baeb5256300e7a6133ebf0cd796 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 7 Jan 2014 17:31:45 +0100 Subject: [PATCH 415/548] suses chkconfig has the same name, but works different --- cdist/conf/type/__start_on_boot/explorer/state | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__start_on_boot/explorer/state b/cdist/conf/type/__start_on_boot/explorer/state index 62f86332..e9e4318e 100755 --- a/cdist/conf/type/__start_on_boot/explorer/state +++ b/cdist/conf/type/__start_on_boot/explorer/state @@ -39,10 +39,19 @@ case "$os" in [ -f "/etc/rc$runlevel.d/S"??"$name" ] || state="absent" ;; - amazon|centos|fedora|owl|redhat|suse) + 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" From 71e5314ec1b7788bfe74ea3304b769af73bd1b2a Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Jan 2014 20:40:46 +0100 Subject: [PATCH 416/548] ++changes(3.0.1) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 6eebc74e..75a7f329 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.0.1: * Type __package: Fix typo in optional parameter ptype (Daniel Heule) * Type __package_rubygems: Require rubygems prior to use (Steven Armstrong) + * Type __start_on_boot: Fix for SuSE's chkconfig (Daniel Heule) 3.0.0: 2013-12-24 * Core: Added messaging support From f8c36c080e47f4139434658b28c099748fae5f15 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Jan 2014 22:30:59 +0100 Subject: [PATCH 417/548] do not escape \ in --line Signed-off-by: Nico Schottelius --- cdist/conf/type/__line/gencode-remote | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote index 1c46c16c..d4796965 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -49,7 +49,15 @@ case "$state_should" in # Replace all \ so \t and other combinations are not interpreted # - line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g" -e 's/\\/\\\\/g') + + # 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") echo "printf '%s\n' '$line_sanitised' >> $file" ;; From 14ee9c4cc718c771aa6a44b77202996fceb1ce86 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Jan 2014 22:32:08 +0100 Subject: [PATCH 418/548] ++changes(3.0.1) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 75a7f329..d606ba69 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius 3.0.1: + * Type __line: Remove unecessary backslash escape * Type __package: Fix typo in optional parameter ptype (Daniel Heule) * Type __package_rubygems: Require rubygems prior to use (Steven Armstrong) * Type __start_on_boot: Fix for SuSE's chkconfig (Daniel Heule) From 52bcc8bc3b254670715a04ec081122f9ffe765ae Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Jan 2014 23:09:56 +0100 Subject: [PATCH 419/548] add old notifications sketch Signed-off-by: Nico Schottelius --- docs/dev/logs/2013-08-27-notifications.xoj | Bin 0 -> 38786 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/dev/logs/2013-08-27-notifications.xoj diff --git a/docs/dev/logs/2013-08-27-notifications.xoj b/docs/dev/logs/2013-08-27-notifications.xoj new file mode 100644 index 0000000000000000000000000000000000000000..c34c467640b7c303fb0aa160d8108c7aca8d9518 GIT binary patch literal 38786 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 OpZ+gcs}`Jw1Ofob4P%o4 literal 0 HcmV?d00001 From aea95d256fa9e928d6c450e0e31b83bda8bd66a2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Jan 2014 23:13:36 +0100 Subject: [PATCH 420/548] remove unneeded changelog.future Signed-off-by: Nico Schottelius --- docs/changelog.future | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 docs/changelog.future diff --git a/docs/changelog.future b/docs/changelog.future deleted file mode 100644 index 12adf8c3..00000000 --- a/docs/changelog.future +++ /dev/null @@ -1,10 +0,0 @@ -Changelog ---------- - - * Changes are always commented with their author in (braces) - * Exception: No braces means author == Nico Schottelius - -future (maybe 3.x?): - * Type __cron: Dropped support for old internal format - Using this version prior to running cdist 2.1.2 will - break add the cron entries twice. From baad4c3276b1f3923ccf6292dc630df441986443 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 7 Jan 2014 23:14:07 +0100 Subject: [PATCH 421/548] +factsheets Signed-off-by: Nico Schottelius --- docs/dev/factsheet.odt | Bin 0 -> 19072 bytes docs/dev/factsheet.pdf | Bin 0 -> 19974 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/dev/factsheet.odt create mode 100644 docs/dev/factsheet.pdf diff --git a/docs/dev/factsheet.odt b/docs/dev/factsheet.odt new file mode 100644 index 0000000000000000000000000000000000000000..2bb2a84bde5b59e530c628f9c3964d3bdbc9c1d6 GIT binary patch literal 19072 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

    q*M-Z=X+hPd@r8!FLn8{FcK_sWoSW9G-ghmL9yf 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 literal 0 HcmV?d00001 From 3e398b233b4ab56f17b27cb0ddfa72041b55b775 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 8 Jan 2014 09:48:04 +0100 Subject: [PATCH 422/548] fix compare with leading 0 on directory mode --- cdist/conf/type/__directory/gencode-remote | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index 800fc6e4..e206ca63 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -85,7 +85,13 @@ DONE if [ -f "$__object/parameter/$attribute" ]; then value_should="$(cat "$__object/parameter/$attribute")" value_is="$(get_current_value "$attribute" "$value_should")" - if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then + # the compare isn't correct when eg 0700 = 700 so we prefix the value_is to 4 chars + if [ "$attribute" = "mode" ] && [ ${#value_should} != ${#value_is} ]; then + if [ ${#value_is} = 3 ]; then + value_is=0${value_is} + fi + fi + if [ "$set_attributes" = 1 ] || [ "$value_should" != "$value_is" ]; then "set_$attribute" "$value_should" fi fi From 3f08565e592eb0d7300397fff38afa4836652216 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 Jan 2014 11:09:01 +0100 Subject: [PATCH 423/548] Revert "install rubygems for ubuntu/debian" On request by Steven. This reverts commit d2c45717f1172d83d64209cad12d1c84f3e16974. --- cdist/conf/type/__package_rubygem/manifest | 33 ---------------------- 1 file changed, 33 deletions(-) delete mode 100755 cdist/conf/type/__package_rubygem/manifest diff --git a/cdist/conf/type/__package_rubygem/manifest b/cdist/conf/type/__package_rubygem/manifest deleted file mode 100755 index 7199d939..00000000 --- a/cdist/conf/type/__package_rubygem/manifest +++ /dev/null @@ -1,33 +0,0 @@ -#!/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 - debian|ubuntu) - __package rubygems - ;; - *) - 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 de1913049725f9fae6a266e4c66d6bd4ab65ac4d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 Jan 2014 11:09:36 +0100 Subject: [PATCH 424/548] no changes for __package_rubygems Signed-off-by: Nico Schottelius --- docs/changelog | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index d606ba69..06f8a29c 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,7 +7,6 @@ Changelog 3.0.1: * Type __line: Remove unecessary backslash escape * Type __package: Fix typo in optional parameter ptype (Daniel Heule) - * Type __package_rubygems: Require rubygems prior to use (Steven Armstrong) * Type __start_on_boot: Fix for SuSE's chkconfig (Daniel Heule) 3.0.0: 2013-12-24 From afb06b729eab62352c3443cac7bc2e6721e9c415 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 8 Jan 2014 13:10:46 +0100 Subject: [PATCH 425/548] mode and message handling now like __file type --- cdist/conf/type/__directory/gencode-remote | 27 +++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index e206ca63..05c301b3 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -56,15 +56,18 @@ get_current_value() { } set_group() { - echo chgrp $recursive \"$1\" \"$destination\" + echo chgrp $recursive \"$1\" \"$destination\" + echo chgrp $recursive $1 >> "$__messages_out" } set_owner() { - echo chown $recursive \"$1\" \"$destination\" + echo chown $recursive \"$1\" \"$destination\" + echo chown $recursive $1 >> "$__messages_out" } set_mode() { - echo chmod $recursive \"$1\" \"$destination\" + echo chmod $recursive \"$1\" \"$destination\" + echo chmod $recursive $1 >> "$__messages_out" } case "$state_should" in @@ -77,6 +80,7 @@ case "$state_should" in rm -f "$destination" mkdir $mkdiropt "$destination" DONE + echo "remove non directory" >> "$__messages_out" fi # Note: Mode - needs to happen last as a chown/chgrp can alter mode by @@ -85,12 +89,12 @@ DONE if [ -f "$__object/parameter/$attribute" ]; then value_should="$(cat "$__object/parameter/$attribute")" value_is="$(get_current_value "$attribute" "$value_should")" - # the compare isn't correct when eg 0700 = 700 so we prefix the value_is to 4 chars - if [ "$attribute" = "mode" ] && [ ${#value_should} != ${#value_is} ]; then - if [ ${#value_is} = 3 ]; then - value_is=0${value_is} - fi + + # change 0xxx format to xxx format => same as stat returns + if [ "$attribute" = mode ]; then + value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" fi + if [ "$set_attributes" = 1 ] || [ "$value_should" != "$value_is" ]; then "set_$attribute" "$value_should" fi @@ -98,9 +102,10 @@ DONE done ;; absent) - if [ "$type" = "directory" ]; then - echo rm -rf \"$destination\" - fi + if [ "$type" = "directory" ]; then + echo rm -rf \"$destination\" + echo remove >> "$__messages_out" + fi ;; *) echo "Unknown state: $state_should" >&2 From 57b700d11bbeb5cc65a5b203758f40484b3fa578 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 8 Jan 2014 14:54:21 +0100 Subject: [PATCH 426/548] ++changes(3.0.1) Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 06f8a29c..d83552f5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,9 @@ Changelog 3.0.1: * Type __line: Remove unecessary backslash escape + * Type __directory: Add messaging support (Daniel Heule) + * Type __directory: Do not generate code if mode is 0xxx ((Daniel Heule) + * Type __directory: Add messaging support (Daniel Heule) * Type __package: Fix typo in optional parameter ptype (Daniel Heule) * Type __start_on_boot: Fix for SuSE's chkconfig (Daniel Heule) From 547c1f9c865cc39504171677e530add8eb1fcf07 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 8 Jan 2014 23:53:08 +0100 Subject: [PATCH 427/548] copy files instead of directories to give --remote-copy implementation a chance to dereference symlinks also fixes #242 by filtering 'hidden' files (starting with a dot) Signed-off-by: Steven Armstrong --- cdist/exec/remote.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 2c42201a..7c807092 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -23,6 +23,7 @@ import io import os import sys +import glob import subprocess import logging @@ -94,9 +95,17 @@ class Remote(object): """Transfer a file or directory to the remote side.""" self.log.debug("Remote transfer: %s -> %s", source, destination) self.rmdir(destination) - command = self._copy.split() - command.extend(["-r", source, self.target_host + ":" + destination]) - self._run_command(command) + 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(self.target_host, destination)]) + self._run_command(command) + else: + command = self._copy.split() + command.extend([source, '{0}:{1}'.format(self.target_host, destination)]) + self._run_command(command) def run_script(self, script, env=None, return_output=False): """Run the given script with the given environment on the remote side. From 44dbe6f2fe835df58bcc033f984e3b6a571fdf01 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 9 Jan 2014 09:38:46 +0100 Subject: [PATCH 428/548] ++changes(3.0.1) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index d83552f5..45cf35b7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius 3.0.1: + * Core: Copy only files, not directories (Steven Armstrong) * Type __line: Remove unecessary backslash escape * Type __directory: Add messaging support (Daniel Heule) * Type __directory: Do not generate code if mode is 0xxx ((Daniel Heule) From 613d66b7a702950fdec68ec5fd5bdc328092aac3 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 9 Jan 2014 16:09:49 +0100 Subject: [PATCH 429/548] corrected man page and gencode update for correct messages --- cdist/conf/type/__directory/gencode-remote | 16 +++++++++------- cdist/conf/type/__directory/man.text | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote index 05c301b3..aba618ac 100755 --- a/cdist/conf/type/__directory/gencode-remote +++ b/cdist/conf/type/__directory/gencode-remote @@ -2,6 +2,7 @@ # # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2013 Steven Armstrong (steven-cdist armstrong.cc) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -73,14 +74,15 @@ set_mode() { case "$state_should" in present) if [ "$type" != "directory" ]; then - # our destination is not a directory, remove whatever is there - # and then create our directory and set all attributes set_attributes=1 - cat << DONE -rm -f "$destination" -mkdir $mkdiropt "$destination" -DONE - echo "remove non directory" >> "$__messages_out" + 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 "remove non directory" >> "$__messages_out" + fi + echo "mkdir $mkdiropt \"$destination\"" + echo "create" >> "$__messages_out" fi # Note: Mode - needs to happen last as a chown/chgrp can alter mode by diff --git a/cdist/conf/type/__directory/man.text b/cdist/conf/type/__directory/man.text index cc327af2..a0bf8062 100644 --- a/cdist/conf/type/__directory/man.text +++ b/cdist/conf/type/__directory/man.text @@ -46,6 +46,21 @@ recursive:: If supplied the chgrp and chown call will run recursively. This does *not* influence the behaviour of chmod. +MESSAGES +-------- +chgrp :: + Changed group membership +chown :: + Changed owner +chmod :: + Changed mode +create:: + Empty directory was created +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. + EXAMPLES -------- From c130bdf5341769539bfa0daa15de80e34fb94413 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Jan 2014 00:41:17 +0100 Subject: [PATCH 430/548] if hostname is an absolute path, strip alway leading slash Signed-off-by: Nico Schottelius --- cdist/exec/local.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 72c7e70f..4233b874 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -194,7 +194,12 @@ class Local(object): 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.target_host) + 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) self.log.debug("Saving " + self.base_path + " to " + destination) try: From d9de8b1dda29f0408373acfbd15bc49f9579e225 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Jan 2014 00:42:01 +0100 Subject: [PATCH 431/548] ++changes(3.0.1) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 45cf35b7..f75bfa9a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 3.0.1: * Core: Copy only files, not directories (Steven Armstrong) + * Core: Allow hostnames to start with / * Type __line: Remove unecessary backslash escape * Type __directory: Add messaging support (Daniel Heule) * Type __directory: Do not generate code if mode is 0xxx ((Daniel Heule) From 5cb5c3bfdffa74d51ee34c959b92a48a9b3678c4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 10 Jan 2014 11:26:23 +0100 Subject: [PATCH 432/548] update changelog Signed-off-by: Nico Schottelius --- docs/changelog | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index f75bfa9a..c0cb9d65 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,8 +9,7 @@ Changelog * Core: Allow hostnames to start with / * Type __line: Remove unecessary backslash escape * Type __directory: Add messaging support (Daniel Heule) - * Type __directory: Do not generate code if mode is 0xxx ((Daniel Heule) - * 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) * Type __start_on_boot: Fix for SuSE's chkconfig (Daniel Heule) From ef1394f4d1cc6b042057d4f071f6765d09f18c2a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 13 Jan 2014 22:07:05 +0100 Subject: [PATCH 433/548] filter out special/hidden files when iterating over explorers Signed-off-by: Steven Armstrong --- 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 d926552a..14dac9f6 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -79,7 +79,7 @@ class Explorer(object): def list_global_explorer_names(self): """Return a list of global explorer names.""" - return os.listdir(self.local.global_explorer_path) + return glob.glob1(self.local.global_explorer_path, '*') def run_global_explorers(self, out_path): """Run global explorers and save output to files in the given @@ -111,7 +111,7 @@ class Explorer(object): """Return a list of explorer names for the given type.""" source = os.path.join(self.local.type_path, cdist_type.explorer_path) try: - return os.listdir(source) + return glob.glob1(source, '*') except EnvironmentError: return [] From 94aa0df74798e1b5e5d110a66863201a9a8ada81 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 13 Jan 2014 22:09:07 +0100 Subject: [PATCH 434/548] add missing import Signed-off-by: Steven Armstrong --- cdist/core/explorer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/core/explorer.py b/cdist/core/explorer.py index 14dac9f6..41851bd6 100644 --- a/cdist/core/explorer.py +++ b/cdist/core/explorer.py @@ -22,6 +22,7 @@ import logging import os +import glob import cdist From f80501d65c3cad4dbdf899d555fa9c37fb5df2cf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jan 2014 08:44:41 +0100 Subject: [PATCH 435/548] ++changes(3.0.1) Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index c0cb9d65..87f864f6 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -3.0.1: +3.0.1: 2014-01-14 * Core: Copy only files, not directories (Steven Armstrong) * Core: Allow hostnames to start with / * Type __line: Remove unecessary backslash escape From 6afc4b82c2b064a15d1707cf293487fd4544be2f Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 14 Jan 2014 09:47:54 +0100 Subject: [PATCH 436/548] __cron should replace entrys with his id --- cdist/conf/type/__cron/explorer/entry | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry index c3bf02d2..15d9bdba 100644 --- a/cdist/conf/type/__cron/explorer/entry +++ b/cdist/conf/type/__cron/explorer/entry @@ -22,4 +22,4 @@ name="$__object_name" user="$(cat "$__object/parameter/user")" -crontab -u $user -l 2>/dev/null | grep "# $name\$" || true +crontab -u $user -l 2>/dev/null | grep "# $name\$" | head -n 1 || true From 5a114cf6ae50ddc9fa66d5cd140e5ad7ef6f71d5 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 14 Jan 2014 10:11:33 +0100 Subject: [PATCH 437/548] __cron should replace entrys with his id, try 2 --- cdist/conf/type/__cron/explorer/entry | 2 +- cdist/conf/type/__cron/gencode-remote | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__cron/explorer/entry b/cdist/conf/type/__cron/explorer/entry index 15d9bdba..c3bf02d2 100644 --- a/cdist/conf/type/__cron/explorer/entry +++ b/cdist/conf/type/__cron/explorer/entry @@ -22,4 +22,4 @@ name="$__object_name" user="$(cat "$__object/parameter/user")" -crontab -u $user -l 2>/dev/null | grep "# $name\$" | head -n 1 || true +crontab -u $user -l 2>/dev/null | grep "# $name\$" || true diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote index 712eb1a1..77a63b9b 100755 --- a/cdist/conf/type/__cron/gencode-remote +++ b/cdist/conf/type/__cron/gencode-remote @@ -78,8 +78,9 @@ DONE case "$state_should" in present) + # if we insert new entry, filter also all entrys out with the same id echo "(" - echo "crontab -u $user -l 2>/dev/null | grep -v -E \"$filter\" 2>/dev/null || true" + echo "crontab -u $user -l 2>/dev/null | grep -v -E \"$filter\" | grep -v \"# $name\\$\" 2>/dev/null || true" echo "echo '$entry'" echo ") | crontab -u $user -" ;; From 3c0790f08045e1581bcaab93cba24837717f2fc2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jan 2014 10:25:28 +0100 Subject: [PATCH 438/548] ++changes(3.0.2) Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 87f864f6..5271d512 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +3.0.2: + * Type __cron: Replace existing entry when changing it (Daniel Heule) + 3.0.1: 2014-01-14 * Core: Copy only files, not directories (Steven Armstrong) * Core: Allow hostnames to start with / From 746d9ec12bd59c2a4cc43c3354ccf94d9543bcbe Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 14 Jan 2014 11:35:24 +0100 Subject: [PATCH 439/548] do not package .gitignore into pypi package (fixes #255) Signed-off-by: Nico Schottelius --- setup.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup.py b/setup.py index 25fc4820..32d734b8 100644 --- a/setup.py +++ b/setup.py @@ -5,6 +5,11 @@ import os def data_finder(data_dir): entries = [] for name in os.listdir(data_dir): + + # Skip .gitignore files + if name == ".gitignore": + continue + entry = os.path.join(data_dir, name) if os.path.isdir(entry): entries.extend(data_finder(entry)) From 33c8f83fa6e5cfb8b5765d95b6ca4dc396f44506 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 14 Jan 2014 21:39:24 +0100 Subject: [PATCH 440/548] new type to manage mounts, either via fstab or manually Signed-off-by: Steven Armstrong --- cdist/conf/type/__mount/explorer/mounted | 27 +++++++ cdist/conf/type/__mount/gencode-remote | 51 ++++++++++++ cdist/conf/type/__mount/man.text | 80 +++++++++++++++++++ cdist/conf/type/__mount/manifest | 42 ++++++++++ cdist/conf/type/__mount/parameter/boolean | 1 + .../type/__mount/parameter/default/device | 1 + .../conf/type/__mount/parameter/default/dump | 1 + .../conf/type/__mount/parameter/default/pass | 1 + .../conf/type/__mount/parameter/default/state | 1 + cdist/conf/type/__mount/parameter/optional | 7 ++ 10 files changed, 212 insertions(+) create mode 100755 cdist/conf/type/__mount/explorer/mounted create mode 100755 cdist/conf/type/__mount/gencode-remote create mode 100644 cdist/conf/type/__mount/man.text create mode 100755 cdist/conf/type/__mount/manifest create mode 100644 cdist/conf/type/__mount/parameter/boolean create mode 100644 cdist/conf/type/__mount/parameter/default/device create mode 100644 cdist/conf/type/__mount/parameter/default/dump create mode 100644 cdist/conf/type/__mount/parameter/default/pass create mode 100644 cdist/conf/type/__mount/parameter/default/state create mode 100644 cdist/conf/type/__mount/parameter/optional diff --git a/cdist/conf/type/__mount/explorer/mounted b/cdist/conf/type/__mount/explorer/mounted new file mode 100755 index 00000000..81f8e454 --- /dev/null +++ b/cdist/conf/type/__mount/explorer/mounted @@ -0,0 +1,27 @@ +#!/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 . +# + +path="$(cat "$__object/parameter/path" 2>/dev/null || echo "/$__object_id")" + +if mountpoint -q "$path"; then + echo yes +else + echo no +fi diff --git a/cdist/conf/type/__mount/gencode-remote b/cdist/conf/type/__mount/gencode-remote new file mode 100755 index 00000000..2626f3de --- /dev/null +++ b/cdist/conf/type/__mount/gencode-remote @@ -0,0 +1,51 @@ +#!/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 . +# + +path="$(cat "$__object/parameter/path" 2>/dev/null || echo "/$__object_id")" +state_should="$(cat "$__object/parameter/state")" +state_is="$(grep -q -x yes "$__object/explorer/mounted" && echo present || echo absent)" + +if [ "$state_should" = "$state_is" ]; then + # nothing to do + exit 0 +fi + +case "$state_should" in + present) + if [ -f "$__object/parameter/nofstab" ]; then + # mount manually + printf 'mount' + if [ -f "$__object/parameter/type" ]; then + printf ' -t %s' "$(cat "$__object/parameter/type")" + fi + if [ -f "$__object/parameter/options" ]; then + printf ' -o %s' "$(cat "$__object/parameter/options")" + fi + printf ' %s' "$(cat "$__object/parameter/device")" + printf " %s\n" "$path" + else + # mount using existing fstab entry + printf 'mount "%s"\n' "$path" + fi + ;; + absent) + printf 'umount "%s"\n' "$path" + ;; +esac diff --git a/cdist/conf/type/__mount/man.text b/cdist/conf/type/__mount/man.text new file mode 100644 index 00000000..89a7df77 --- /dev/null +++ b/cdist/conf/type/__mount/man.text @@ -0,0 +1,80 @@ +cdist-type__mount(7) +==================== +Steven Armstrong + + +NAME +---- +cdist-type__mount - manage filesystem mounts + + +DESCRIPTION +----------- +Manage filesystem mounts either via /etc/fstab or manually. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +device:: + device to mount at path, defaults to 'none'. see mount(8) + +dump:: + value for the dump field in fstab. see fstab(5) + defaults to 0. + +options:: + comma separated string of options, see mount(8) + +pass:: + value for the pass field in fstab. see fstab(5) + defaults to 0. + +path:: + mount point where to mount the device, see mount(8). + Defaults to __object_id + +state:: + either present or absent. Defaults to present. + +type:: + vfstype, see mount(8) + + +BOOLEAN PARAMETERS +------------------ +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 + +__mount /var/lib/one \ + --device mfsmount \ + --type fuse \ + --options "mfsmaster=mfsmaster.domain.tld,mfssubfolder=/one,nonempty,_netdev" +-------------------------------------------------------------------------------- + + +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/__mount/manifest b/cdist/conf/type/__mount/manifest new file mode 100755 index 00000000..ff891bb8 --- /dev/null +++ b/cdist/conf/type/__mount/manifest @@ -0,0 +1,42 @@ +#!/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 . +# + +path="$(cat "$__object/parameter/path" 2>/dev/null || echo "/$__object_id")" +state="$(cat "$__object/parameter/state")" + +if [ ! -f "$__object/parameter/nofstab" ]; then + # Generate an entry for /etc/fstab + ( +printf "%s" "$(cat "$__object/parameter/device")" +printf " %s" "$path" +type="$(cat "$__object/parameter/type" || echo "auto")" +printf " %s" "$type" +options="$(cat "$__object/parameter/options" || echo "defaults")" +printf " %s" "$options" +printf " %s" "$(cat "$__object/parameter/dump")" +printf " %s\n" "$(cat "$__object/parameter/pass")" +) | \ +__block "$__object_name" \ + --file "/etc/fstab" \ + --prefix "#cdist:$__object_name" \ + --suffix "#/cdist:$__object_name" \ + --state "$state" \ + --text - +fi diff --git a/cdist/conf/type/__mount/parameter/boolean b/cdist/conf/type/__mount/parameter/boolean new file mode 100644 index 00000000..ac6f41a8 --- /dev/null +++ b/cdist/conf/type/__mount/parameter/boolean @@ -0,0 +1 @@ +nofstab diff --git a/cdist/conf/type/__mount/parameter/default/device b/cdist/conf/type/__mount/parameter/default/device new file mode 100644 index 00000000..621e94f0 --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/device @@ -0,0 +1 @@ +none diff --git a/cdist/conf/type/__mount/parameter/default/dump b/cdist/conf/type/__mount/parameter/default/dump new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/dump @@ -0,0 +1 @@ +0 diff --git a/cdist/conf/type/__mount/parameter/default/pass b/cdist/conf/type/__mount/parameter/default/pass new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/pass @@ -0,0 +1 @@ +0 diff --git a/cdist/conf/type/__mount/parameter/default/state b/cdist/conf/type/__mount/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__mount/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__mount/parameter/optional b/cdist/conf/type/__mount/parameter/optional new file mode 100644 index 00000000..29d3e5ef --- /dev/null +++ b/cdist/conf/type/__mount/parameter/optional @@ -0,0 +1,7 @@ +device +dump +options +pass +path +state +type From a787d2b27bb9f0e21f2aab0b9a8f9f09f5abf1f6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 14 Jan 2014 21:43:50 +0100 Subject: [PATCH 441/548] new type to manage a block of text in a file Signed-off-by: Steven Armstrong --- cdist/conf/type/__block/explorer/block | 21 +++++ cdist/conf/type/__block/gencode-remote | 84 +++++++++++++++++++ cdist/conf/type/__block/man.text | 82 ++++++++++++++++++ cdist/conf/type/__block/manifest | 36 ++++++++ .../conf/type/__block/parameter/default/state | 1 + cdist/conf/type/__block/parameter/optional | 4 + cdist/conf/type/__block/parameter/required | 1 + 7 files changed, 229 insertions(+) create mode 100755 cdist/conf/type/__block/explorer/block create mode 100755 cdist/conf/type/__block/gencode-remote create mode 100644 cdist/conf/type/__block/man.text create mode 100755 cdist/conf/type/__block/manifest create mode 100644 cdist/conf/type/__block/parameter/default/state create mode 100644 cdist/conf/type/__block/parameter/optional create mode 100644 cdist/conf/type/__block/parameter/required diff --git a/cdist/conf/type/__block/explorer/block b/cdist/conf/type/__block/explorer/block new file mode 100755 index 00000000..6c35bc46 --- /dev/null +++ b/cdist/conf/type/__block/explorer/block @@ -0,0 +1,21 @@ +#!/bin/sh +# 2013 Steven Armstrong (steven-cdist at armstrong.cc) + +file="$(cat "$__object/parameter/file" 2>/dev/null || echo "/$__object_id")" + +# file does not exist, nothing we could do +[ -f "$file" ] || exit 0 + +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") +awk -v prefix="$prefix" -v suffix="$suffix" '{ + if (index($0,prefix)) { + triggered=1 + } + if (triggered) { + if (index($0,suffix)) { + triggered=0 + } + print + } +}' "$file" diff --git a/cdist/conf/type/__block/gencode-remote b/cdist/conf/type/__block/gencode-remote new file mode 100755 index 00000000..0a5eea18 --- /dev/null +++ b/cdist/conf/type/__block/gencode-remote @@ -0,0 +1,84 @@ +#!/bin/sh +# +# 2013 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 . +# + +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") +suffix=$(cat "$__object/parameter/suffix" 2>/dev/null || echo "#/cdist:__block/$__object_id") + +block="$__object/files/block" +if [ ! -s "$__object/explorer/block" ]; then + state_is='absent' +else + state_is=$(diff -q "$block" "$__object/explorer/block" >/dev/null \ + && echo present \ + || echo changed + ) +fi + +state_should="$(cat "$__object/parameter/state")" +if [ "$state_should" = "$state_is" ]; then + # Nothing to do, move along + exit 0 +fi + +remove_block() { + cat << DONE +tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) +# preserve ownership and permissions of existing file +if [ -f "$file" ]; then + cp -p "$file" "\$tmpfile" +fi +awk -v prefix="$prefix" -v suffix="$suffix" ' +{ + if (index(\$0,prefix)) { + triggered=1 + } + if (triggered) { + if (index(\$0,suffix)) { + triggered=0 + } + } else { + print + } +}' "$file" > "\$tmpfile" +mv -f "\$tmpfile" "$file" +DONE +} + +case "$state_should" in + present) + if [ "$state_is" = "changed" ]; then + echo update >> "$__messages_out" + remove_block + else + echo add >> "$__messages_out" + fi + cat << DONE +cat >> "$file" << ${__type##*/}_DONE +$(cat "$block") +${__type##*/}_DONE +DONE + ;; + absent) + echo remove >> "$__messages_out" + remove_block + ;; +esac diff --git a/cdist/conf/type/__block/man.text b/cdist/conf/type/__block/man.text new file mode 100644 index 00000000..2312d293 --- /dev/null +++ b/cdist/conf/type/__block/man.text @@ -0,0 +1,82 @@ +cdist-type__block(7) +==================== +Steven Armstrong + + +NAME +---- +cdist-type__block - Manage blocks of text in files + + +DESCRIPTION +----------- +Manage a block of text in an existing file. +The block is identified using the prefix and suffix parameters. +Everything between prefix and suffix is considered to be a managed block +of text. + + +REQUIRED PARAMETERS +------------------- +text:: + the text to manage. + If text is '-' (dash), take what was written to stdin as the text. + + +OPTIONAL PARAMETERS +------------------- +file:: + the file in which to manage the text block. + Defaults to object_id. + +prefix:: + the prefix to add before the text. + Defaults to #cdist:__block/$__object_id + +suffix:: + the prefix to add after the text. + Defaults to #/cdist:__block/$__object_id + +state:: + 'present' or 'absent', defaults to 'present' + + +MESSAGES +-------- +add:: + block was added +update:: + block was updated/changed +remove:: + block was removed + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# 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) + + +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). diff --git a/cdist/conf/type/__block/manifest b/cdist/conf/type/__block/manifest new file mode 100755 index 00000000..1fc9ec79 --- /dev/null +++ b/cdist/conf/type/__block/manifest @@ -0,0 +1,36 @@ +#!/bin/sh +# +# 2013-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 . +# + + +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") + +mkdir "$__object/files" +# Generate text block for inclusion in file +block="$__object/files/block" +echo "$prefix" > "$block" +if [ "$text" = "-" ]; then + cat "$__object/stdin" >> "$block" +else + cat "$text" >> "$block" +fi +echo "$suffix" >> "$block" diff --git a/cdist/conf/type/__block/parameter/default/state b/cdist/conf/type/__block/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__block/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__block/parameter/optional b/cdist/conf/type/__block/parameter/optional new file mode 100644 index 00000000..fa3abebf --- /dev/null +++ b/cdist/conf/type/__block/parameter/optional @@ -0,0 +1,4 @@ +file +prefix +state +suffix diff --git a/cdist/conf/type/__block/parameter/required b/cdist/conf/type/__block/parameter/required new file mode 100644 index 00000000..8e27be7d --- /dev/null +++ b/cdist/conf/type/__block/parameter/required @@ -0,0 +1 @@ +text From ad09a9258ec9c3b31d12de43bc061f02e7128509 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Jan 2014 13:25:37 +0100 Subject: [PATCH 442/548] ++changes(3.0.2) Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 5271d512..08f7ff5f 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,8 +5,11 @@ Changelog * Exception: No braces means author == Nico Schottelius 3.0.2: + * New Type: __block (Steven Armstrong) + * New Type: __mount (Steven Armstrong) * Type __cron: Replace existing entry when changing it (Daniel Heule) + 3.0.1: 2014-01-14 * Core: Copy only files, not directories (Steven Armstrong) * Core: Allow hostnames to start with / From 2c30704ba791e38bfc459936dbf1fba62f60f840 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 15 Jan 2014 13:28:41 +0100 Subject: [PATCH 443/548] add hints about ignored parameters Signed-off-by: Nico Schottelius --- cdist/conf/type/__mount/man.text | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cdist/conf/type/__mount/man.text b/cdist/conf/type/__mount/man.text index 89a7df77..7299bdf3 100644 --- a/cdist/conf/type/__mount/man.text +++ b/cdist/conf/type/__mount/man.text @@ -27,6 +27,8 @@ 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:: comma separated string of options, see mount(8) @@ -34,6 +36,8 @@ 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:: mount point where to mount the device, see mount(8). Defaults to __object_id From 095c5335c69a732bc54879a6a42e7162c59311bc Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Jan 2014 11:05:29 +0100 Subject: [PATCH 444/548] use default parameters Signed-off-by: Steven Armstrong --- cdist/conf/type/__ssh_authorized_keys/manifest | 2 +- cdist/conf/type/__ssh_authorized_keys/parameter/default/state | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 cdist/conf/type/__ssh_authorized_keys/parameter/default/state diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 47cdf746..8b299d0a 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -19,7 +19,7 @@ # owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" -state="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" +state="$(cat "$__object/parameter/state" 2>/dev/null)" if [ -f "$__object/parameter/file" ]; then file="$(cat "$__object/parameter/file")" else diff --git a/cdist/conf/type/__ssh_authorized_keys/parameter/default/state b/cdist/conf/type/__ssh_authorized_keys/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__ssh_authorized_keys/parameter/default/state @@ -0,0 +1 @@ +present From 3b072a7abb08bdd4896ad425a0ce98700b73ebb6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Jan 2014 11:09:51 +0100 Subject: [PATCH 445/548] use __block type to manage keys Signed-off-by: Steven Armstrong --- .../type/__ssh_authorized_keys/explorer/entry | 45 ---------- .../type/__ssh_authorized_keys/gencode-remote | 84 ------------------- .../conf/type/__ssh_authorized_keys/manifest | 23 +++-- 3 files changed, 10 insertions(+), 142 deletions(-) delete mode 100755 cdist/conf/type/__ssh_authorized_keys/explorer/entry delete mode 100755 cdist/conf/type/__ssh_authorized_keys/gencode-remote diff --git a/cdist/conf/type/__ssh_authorized_keys/explorer/entry b/cdist/conf/type/__ssh_authorized_keys/explorer/entry deleted file mode 100755 index 9992d32d..00000000 --- a/cdist/conf/type/__ssh_authorized_keys/explorer/entry +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# -# 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 . -# - -owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" -if [ -f "$__object/parameter/file" ]; then - file="$(cat "$__object/parameter/file")" -else - home="$("$__type_explorer/passwd" | cut -d':' -f 6)" - file="$home/.ssh/authorized_keys" -fi - -# no authorized_keys file, nothing we could do -[ -f "$file" ] || exit 0 - -# NOTE: keep variables in sync in manifest/explorer/gencode-* -prefix="#cdist:$__object_name" -suffix="#/cdist:$__object_name" -awk -v prefix="$prefix" -v suffix="$suffix" '{ - if (index($0,prefix)) { - triggered=1 - } - if (triggered) { - if (index($0,suffix)) { - triggered=0 - } - print - } -}' "$file" diff --git a/cdist/conf/type/__ssh_authorized_keys/gencode-remote b/cdist/conf/type/__ssh_authorized_keys/gencode-remote deleted file mode 100755 index 7fcb59c6..00000000 --- a/cdist/conf/type/__ssh_authorized_keys/gencode-remote +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/sh -# -# 2012-2013 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 . -# - -owner="$(cat "$__object/parameter/owner" 2>/dev/null || echo "$__object_id")" -if [ -f "$__object/parameter/file" ]; then - file="$(cat "$__object/parameter/file")" -else - home="$(cut -d':' -f 6 "$__object/explorer/passwd")" - file="$home/.ssh/authorized_keys" -fi - -entry="$__object/files/entry" -if [ ! -s "$__object/explorer/entry" ]; then - state_is='absent' -else - state_is=$(diff -q "$entry" "$__object/explorer/entry" >/dev/null \ - && echo present \ - || echo changed - ) -fi - -state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo present)" -if [ "$state_should" = "$state_is" ]; then - # Nothing to do, move along - exit 0 -fi - -remove_entry() { - # NOTE: keep variables in sync in manifest/explorer/gencode-* - prefix="#cdist:$__object_name" - suffix="#/cdist:$__object_name" - cat << DONE -tmpfile=\$(mktemp ${file}.cdist.XXXXXXXXXX) -# preserve ownership and permissions by copying existing file over tmpfile -cp -p "$file" "\$tmpfile" -awk -v prefix="$prefix" -v suffix="$suffix" ' -{ - if (index(\$0,prefix)) { - triggered=1 - } - if (triggered) { - if (index(\$0,suffix)) { - triggered=0 - } - } else { - print - } -}' "$file" > "\$tmpfile" -mv -f "\$tmpfile" "$file" -DONE -} - -case "$state_should" in - present) - if [ "$state_is" = "changed" ]; then - remove_entry - fi - cat << DONE -cat >> "$file" << ${__type##*/}_DONE -$(cat "$entry") -${__type##*/}_DONE -DONE - ;; - absent) - remove_entry - ;; -esac diff --git a/cdist/conf/type/__ssh_authorized_keys/manifest b/cdist/conf/type/__ssh_authorized_keys/manifest index 8b299d0a..8631d042 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -56,19 +56,16 @@ if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; fi fi -# NOTE: keep variables in sync in manifest/explorer/gencode-* -prefix="#cdist:$__object_name" -suffix="#/cdist:$__object_name" - -mkdir "$__object/files" - # Generate entry for inclusion in authorized_keys file -entry="$__object/files/entry" -echo "$prefix" > "$entry" +( if [ -f "$__object/parameter/comment" ]; then - echo "# $(cat "$__object/parameter/comment")" >> "$entry" + echo "# $(cat "$__object/parameter/comment")" fi -cat "$__object/parameter/key" >> "$entry" -# ensure we have a newline after keys -echo >> "$entry" -echo "$suffix" >> "$entry" +cat "$__object/parameter/key" +) | \ +__block "$__object_name" \ + --file "$file" \ + --prefix "#cdist:$__object_name" \ + --suffix "#/cdist:$__object_name" \ + --state "$state" \ + --text - From 0b7d9babf6f4f13e65f03819887e99d7809309b0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Jan 2014 11:11:00 +0100 Subject: [PATCH 446/548] whitespace-- 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 8631d042..5a9cfbb3 100755 --- a/cdist/conf/type/__ssh_authorized_keys/manifest +++ b/cdist/conf/type/__ssh_authorized_keys/manifest @@ -39,7 +39,7 @@ if [ ! -f "$__object/parameter/noparent" -o ! -f "$__object/parameter/nofile" ]; fi if [ ! -f "$__object/parameter/noparent" ]; then - # Ensure that the directory in which the authorized_keys shall be exists and + # Ensure that the directory in which the authorized_keys shall be exists and # has the right permissions. ssh_directory="${file%/*}" __directory "$ssh_directory" --state present --parents \ From 36a330eb3c185efeedc35b4221ccae483340c027 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 16 Jan 2014 12:00:24 +0100 Subject: [PATCH 447/548] redirect stderr to /dev/null Signed-off-by: Steven Armstrong --- 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 ff891bb8..8a1fa234 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" || echo "auto")" +type="$(cat "$__object/parameter/type" 2>/dev/null || echo "auto")" printf " %s" "$type" -options="$(cat "$__object/parameter/options" || echo "defaults")" +options="$(cat "$__object/parameter/options" 2>/dev/null || echo "defaults")" printf " %s" "$options" printf " %s" "$(cat "$__object/parameter/dump")" printf " %s\n" "$(cat "$__object/parameter/pass")" From 4e94713f07c557aeaf482ee71e7aab85d72fe05c Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 17 Jan 2014 10:27:21 +0100 Subject: [PATCH 448/548] documented all messages which I have found via grep --- cdist/conf/type/__group/man.text | 12 ++++++++++++ cdist/conf/type/__user/man.text | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/cdist/conf/type/__group/man.text b/cdist/conf/type/__group/man.text index c57ae337..def0232f 100644 --- a/cdist/conf/type/__group/man.text +++ b/cdist/conf/type/__group/man.text @@ -26,6 +26,18 @@ password:: see above +MESSAGES +-------- +mod:: + group is modified +add:: + New group added +change :: + Changed group property from current_value to new_value +set :: + set property to new value, property was not set bevore + + EXAMPLES -------- diff --git a/cdist/conf/type/__user/man.text b/cdist/conf/type/__user/man.text index 47e63d3d..be70ec12 100644 --- a/cdist/conf/type/__user/man.text +++ b/cdist/conf/type/__user/man.text @@ -44,6 +44,15 @@ create-home:: remove-home:: see userdel(8), apply only on user delete + +MESSAGES +-------- +mod:: + User is modified +add:: + New user added + + EXAMPLES -------- From f23999c8d378f81bcb5e97604a220ce6d1b19cd1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 17 Jan 2014 10:41:23 +0100 Subject: [PATCH 449/548] ++changes(3.0.2) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 08f7ff5f..a12de32a 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius 3.0.2: + * Documentation: Document all messages sent by types (Daniel Heule) * New Type: __block (Steven Armstrong) * New Type: __mount (Steven Armstrong) * Type __cron: Replace existing entry when changing it (Daniel Heule) From 824381e6cac28acbf3c5cd84d9d9000b3b37249e Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 17 Jan 2014 23:35:02 +0100 Subject: [PATCH 450/548] new special value require="CDIST_HONOR_MANIFEST_ORDER" which tells cdist to execute types in the manifest order --- cdist/emulator.py | 16 ++++++++++++++++ docs/man/man7/cdist-manifest.text | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/cdist/emulator.py b/cdist/emulator.py index b70ef956..fe2af4c1 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -71,6 +71,7 @@ class Emulator(object): raise MissingRequiredEnvironmentVariableError(e.args[0]) 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) @@ -152,6 +153,9 @@ class Emulator(object): else: self.cdist_object.create() self.cdist_object.parameters = self.parameters + # record the created object in typeorder file + with open(self.typeorder_path, 'a') as tofd: + tofd.write(self.cdist_object.name + os.linesep) # Record / Append source self.cdist_object.source.append(self.object_source) @@ -188,6 +192,18 @@ class Emulator(object): # Ignore empty fields - probably the only field anyway if len(requirement) == 0: continue + + if requirement == "CDIST_HONOR_MANIFEST_ORDER": + # load object name created bevor this one from typeorder file ... + with open(self.typeorder_path, 'r') as tofd: + lines = tofd.readlines() + # replace the placeholder with the last created object + try: + requirement = lines[-2].strip() + except IndexError: + # if no second last line, we are on the first object, so do not set a requirement + continue + # Raises an error, if object cannot be created try: cdist_object = self.cdist_object.object_from_name(requirement) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 92d0b897..d2738c2b 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -128,6 +128,22 @@ 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 tell cdist to execute all types in the order in which they are created +in the manifest by setting require to the special value of +"CDIST_HONOR_MANIFEST_ORDER". + +-------------------------------------------------------------------------------- + +# Tells cdist to execute all types in the order in which they are created ... +export require="CDIST_HONOR_MANIFEST_ORDER" +__sample_type 1 +__sample_type 2 +__example_type 23 +# Now this types are executed in the creation order +-------------------------------------------------------------------------------- + + + EXAMPLES -------- From c4140a7c7bc0885f5d8581ba8b1097087494376f Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 18 Jan 2014 15:57:39 +0100 Subject: [PATCH 451/548] ++changes(3.0.2) Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index a12de32a..d9b1db51 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * New Type: __block (Steven Armstrong) * New Type: __mount (Steven Armstrong) * Type __cron: Replace existing entry when changing it (Daniel Heule) + * Type __ssh_authorized_keys: Use new type __block (Steven Armstrong) 3.0.1: 2014-01-14 From 61aec12ba1b0b0f55ec418895b61d46701c56b30 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Sat, 18 Jan 2014 19:23:21 +0100 Subject: [PATCH 452/548] Try2 to make cdist honor the manifest order, this implementation has some more lines of code, but no collision with the require variable. --- cdist/emulator.py | 36 ++++++++++++++++++------------- docs/man/man7/cdist-manifest.text | 22 ++++++++++++++----- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index fe2af4c1..eeb441aa 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -154,8 +154,8 @@ class Emulator(object): self.cdist_object.create() self.cdist_object.parameters = self.parameters # record the created object in typeorder file - with open(self.typeorder_path, 'a') as tofd: - tofd.write(self.cdist_object.name + os.linesep) + with open(self.typeorder_path, 'a') as typeorderfile: + print(self.cdist_object.name, file=typeorderfile) # Record / Append source self.cdist_object.source.append(self.object_source) @@ -184,6 +184,24 @@ class Emulator(object): def record_requirements(self): """record requirements""" + #from pudb import set_trace; set_trace(); + + if "EXECUTE_TYPES_IN_CREATION_ORDER" in self.env and self.env['EXECUTE_TYPES_IN_CREATION_ORDER'] == 'true': + # load object name created bevor this one from typeorder file ... + with open(self.typeorder_path, 'r') as typecreationfile: + typecreationorder = typecreationfile.readlines() + # get the type created bevore this one ... + try: + lastcreatedtype = typecreationorder[-2].strip() + if 'require' in self.env: + self.env['require'] += " " + lastcreatedtype + else: + self.env['require'] = lastcreatedtype + self.log.debug("Injecting require for EXECUTE_TYPES_IN_CREATION_ORDER: %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 + pass + if "require" in self.env: requirements = self.env['require'] @@ -192,18 +210,6 @@ class Emulator(object): # Ignore empty fields - probably the only field anyway if len(requirement) == 0: continue - - if requirement == "CDIST_HONOR_MANIFEST_ORDER": - # load object name created bevor this one from typeorder file ... - with open(self.typeorder_path, 'r') as tofd: - lines = tofd.readlines() - # replace the placeholder with the last created object - try: - requirement = lines[-2].strip() - except IndexError: - # if no second last line, we are on the first object, so do not set a requirement - continue - # Raises an error, if object cannot be created try: cdist_object = self.cdist_object.object_from_name(requirement) @@ -212,7 +218,7 @@ class Emulator(object): raise - self.log.debug("Recording requirement: " + requirement) + self.log.debug("Recording requirement: %s", requirement) # Save the sanitised version, not the user supplied one # (__file//bar => __file/bar) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index d2738c2b..d2f5ba05 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -128,18 +128,30 @@ 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. + +EXECUTE_TYPES_IN_CREATION_ORDER is a EXPERIMENTAL FEATURE ! You can tell cdist to execute all types in the order in which they are created -in the manifest by setting require to the special value of -"CDIST_HONOR_MANIFEST_ORDER". +in the manifest by exporting EXECUTE_TYPES_IN_CREATION_ORDER with the value true. -------------------------------------------------------------------------------- # Tells cdist to execute all types in the order in which they are created ... -export require="CDIST_HONOR_MANIFEST_ORDER" +export EXECUTE_TYPES_IN_CREATION_ORDER=true __sample_type 1 -__sample_type 2 +require="__some_type_somewhere/id" __sample_type 2 __example_type 23 -# Now this types are executed in the creation order +# Now this types are executed in the creation order until the variable is unset +unset EXECUTE_TYPES_IN_CREATION_ORDER +# 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 + -------------------------------------------------------------------------------- From f3b7fc15148058b51cf9f5bbea153123237a12ac Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 19 Jan 2014 21:38:38 +0100 Subject: [PATCH 453/548] release 3.0.2 Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index d9b1db51..ca9cc9cf 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -3.0.2: +3.0.2: 2014-01-19 * Documentation: Document all messages sent by types (Daniel Heule) * New Type: __block (Steven Armstrong) * New Type: __mount (Steven Armstrong) From ce73cef4574dca1ad6dffa59d61c5546732df837 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 19 Jan 2014 23:22:48 +0100 Subject: [PATCH 454/548] explain that a requirement caused the error, otherwise you search until you die Signed-off-by: Nico Schottelius --- cdist/emulator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index b70ef956..899a710f 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -194,7 +194,9 @@ class Emulator(object): except core.cdist_type.NoSuchTypeError as e: self.log.error("%s requires object %s, but type %s does not exist (definded 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), but type %s is not a singleton (definded at %s)" % (self.cdist_object.name, requirement, e.type_name, self.object_source)) + raise self.log.debug("Recording requirement: " + requirement) From ac0c88fe9f477b598b2662b589f7a7337b870cfb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 19 Jan 2014 23:28:45 +0100 Subject: [PATCH 455/548] remove some old typos and omit type details that follow anyway Signed-off-by: Nico Schottelius --- cdist/emulator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 899a710f..63d3bbbc 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -192,10 +192,10 @@ class Emulator(object): 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 (definded at %s)" % (self.cdist_object.name, requirement, e.name, self.object_source)) + 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), but type %s is not a singleton (definded at %s)" % (self.cdist_object.name, requirement, e.type_name, self.object_source)) + 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: " + requirement) From c47abb6af71ed9aa12f0be982f4277a9868e08aa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 19 Jan 2014 23:29:56 +0100 Subject: [PATCH 456/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index ca9cc9cf..a3d5c4fd 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +3.0.3: + * Core: Enhance error message when requirement is missing object id + 3.0.2: 2014-01-19 * Documentation: Document all messages sent by types (Daniel Heule) * New Type: __block (Steven Armstrong) From c790014cd59d65181d83a42d5f7b45ef2d2264c8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 10:11:23 +0100 Subject: [PATCH 457/548] add scaled version of the cdist logo Signed-off-by: Nico Schottelius --- docs/gfx/cdist-logo-1024-scaled.png | Bin 0 -> 2509 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/gfx/cdist-logo-1024-scaled.png diff --git a/docs/gfx/cdist-logo-1024-scaled.png b/docs/gfx/cdist-logo-1024-scaled.png new file mode 100644 index 0000000000000000000000000000000000000000..4be8d4c96a9e6ff645fe08ceef4df9afb3f218c4 GIT binary patch literal 2509 zcmYLLc{tQ-8-9K>%vjEhB}oR2WNT6!A|n|gWN8jUB~6kz31#2slcaD=*_YAaSVESL zl6_8eWC>qnI~o%@(Lwet@{PZ~>w4bnzOVOs{&=4Ey|4Ru9#E}KaYE8U0Dv<$GqwTX z<5846g66^3rHdXsz)&siOnA7nvr{nq`j}nt1rXk|dl1OXmf~Gv{miXQup9(0 zfEACcHn8BOT{Jf~vR`0@|1S*bA;SU zEUC~CIZ*jd!RoBdk4T>ag7T-*J2Ol3aT)?q#Q#TK;%M2HGC%wDxwT==yMxZ2!oKw_ zJ+M9j-Kw9%*aF+31bJ|DOhDVSg<;Mc{hTm@{VD-Hd|Zu}f7Hz35_`5buPn z$VPEJ;Ps#L276|oWQ-*)3Nk|dPKDX>^Melml&K}3ifgcw;}Qnqi}+5C--U|jg!g$# zMQI?c=AAx@a}Xg$PUNnxMW*0R)T)xG!Eat@1N{rax;tCAQ=WcVUjj{&VfEg3QKLT) zhEWmXwTqOzK(ZRK_Nva-61@KJJq3=9aOZLFDOZErZQv-)J@tM|5q2M_w8Em3%oLVQ^9zO5Kc&4bEkc zF2-EewT_3@sHM$T*Uw<3%Ms!hUJuns<@f9(-2%u5^9%ADG)*3j6k^FdY#VsGLsP*3 zGLJcUa7pyhquAIV2m!hhuqBGjidr$B8}A5tn(e|W(BoD&;g9ZZ(y|@c=Fj@~=j(6; z4~C-E)+wsYJ8hgAo#FdJfdr<`hv!jYm(EZeYOg`7|EAi(Ok3%{y4zgg$*k|Ojzg5% zCT>FAhoF!Gzge&z=#Q#E54B?GGT`e;Sytjq$2d(QNyMmAh z@0>#g%m=}py}0AAT@OUp$Uc{aGqXnZm^E9~L8|=EEgQ)CWQ5TETHk{T-d@zQyyxshycRAa0do^P#;*vAa zCAt4zM&2GXbGCE#8I4Ct%za9hhK3qGu!jXg=+*=^uq9%{tJC)bj;VIRrT)SDZkQ5(f#O!S{t~%0WH4`@sAct^CnrP1r4>|gJ zGlrNT3JQP~rrc1O0|_!Ex!w1y6|@*F)FA;(uR>&bB+FsKZA~939*77)iIblQ(oOl@ z)7%e*I8!?r`;zCXnL~$e@6=|$(yF}{$}4|W=8>yCS$3>kR1gHBST8!gm6Yz5t=dN< zMf~xr(yP&{2T`$u4unuB~)zC=q~CtJ^3tFZohrK6@G>0uS-A`ydEIcT>T?Zd}qB z6fkER@UtagFJpO(C?{IbU7KOCy6NA_8D6o{YqTs1OjUy}Xqv;dr%<2xJF^<(y~8s) zgu6KES7XTI6c-e|0KC+~t)_q5E&-mLmi=r(&7zOq(I;w#)c-{wOL`Agug$%ZS&1pd z`iwB`3ifoW(iNwchkZgbIB8H7QJztIis$O0>U-F&{gz0>y>TRKogb25Xf?~PWzMa} zOSTf%d8}nNk5G4`Tfx~<1`Cy1kUv4WQS))-jH7f$i%4I*D6FAk*Y`mxA2)1~`V(Cl z(q+ZYi=<15AuLH{AG$D8gMzq^KEE=lrz%6sGa&O)v6DR1=i=V(Ps6i0 z8Cf}KZY?sIEVBJ@N`QU^Bk*0Di*O}D6a5&^-a4%asqpHub7kLXRl{i)`vSiNSUcb3 zw<@x$uV%**+zf|N)!kZf(otVY?^&`=7czgBeD!Lg;0scI$9G0T)<>9k0?osR$Q0{D zVGLc6`|@7LBFjz}Z=BKK)bm-F)HT75Y4pLyr?*=^mRte1j|K}w@!*}TscxO8t(OU@%=3WSl6IrrYmESN+s}(M$^X-hH#3cTs-3Q7An=* u1T=dD5#pH`1I1ghC=c<5qI`zE;+rD*j_v!NkL&F&ZeVU=ZCrku7WF^fT1X!N literal 0 HcmV?d00001 From 13001924c083f5a61a1060d0ac392edbdb750eff Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 10:52:28 +0100 Subject: [PATCH 458/548] do not touch a visible file during release process Signed-off-by: Nico Schottelius --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5910ab2e..1962c96e 100644 --- a/Makefile +++ b/Makefile @@ -175,10 +175,12 @@ freecode-release: $(FREECODE_FILE) ################################################################################ # pypi # -pypi-release: man $(PYTHON_VERSION) +PYPI_FILE=.pypi-release +$(PYPI_FILE): man $(PYTHON_VERSION) python3 setup.py sdist upload touch $@ +pypi-release: $(PYPI_FILE) ################################################################################ # archlinux # From 5279b7239ce0d34c6d0a504e2ae9dd84c354df29 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 13:47:45 +0100 Subject: [PATCH 459/548] import __hostname - Thanks, Steven! Signed-off-by: Nico Schottelius --- cdist/conf/type/__hostname/gencode-remote | 33 +++++++++++++ cdist/conf/type/__hostname/man.text | 47 +++++++++++++++++++ cdist/conf/type/__hostname/manifest | 42 +++++++++++++++++ cdist/conf/type/__hostname/parameter/optional | 1 + cdist/conf/type/__hostname/singleton | 0 5 files changed, 123 insertions(+) create mode 100755 cdist/conf/type/__hostname/gencode-remote create mode 100644 cdist/conf/type/__hostname/man.text create mode 100755 cdist/conf/type/__hostname/manifest create mode 100644 cdist/conf/type/__hostname/parameter/optional create mode 100644 cdist/conf/type/__hostname/singleton diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote new file mode 100755 index 00000000..88ee069a --- /dev/null +++ b/cdist/conf/type/__hostname/gencode-remote @@ -0,0 +1,33 @@ +#!/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 . +# + +name="$(cat "$__object/parameter/name")" +os=$(cat "$__global/explorer/os") + +echo "printf '%s\n' '$name' > /etc/hostname" + +case "$os" in + debian|ubuntu) + echo "hostname \"$name\"" + ;; + archlinux) + echo "hostnamectl set-hostname \"$name\"" + ;; +esac diff --git a/cdist/conf/type/__hostname/man.text b/cdist/conf/type/__hostname/man.text new file mode 100644 index 00000000..07ec1083 --- /dev/null +++ b/cdist/conf/type/__hostname/man.text @@ -0,0 +1,47 @@ +cdist-type__hostname(7) +======================= +Steven Armstrong + + +NAME +---- +cdist-type__hostname - set the hostname + + +DESCRIPTION +----------- +Set's the hostname on various operating systems. + + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +name:: + The hostname to set. Defaults to the first segment of __target_host + (${__target_host%%.*}) + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +# take hostname from __target_host +__hostname + +# set hostname explicitly +__hostname --name some-static-hostname +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) + + +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). diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest new file mode 100755 index 00000000..3aa6de45 --- /dev/null +++ b/cdist/conf/type/__hostname/manifest @@ -0,0 +1,42 @@ +#!/bin/sh +# +# 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 . +# + +# set defaults +name="$(cat "$__object/parameter/name" 2>/dev/null \ + || echo "${__target_host%%.*}" | tee "$__object/parameter/name")" + +os=$(cat "$__global/explorer/os") + +not_supported() { + 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 +} + +case "$os" in + archlinux|debian|ubuntu) + # handled in gencode-remote + # FIXED: hostname setup in archlinuz via rc.local ist outdated + : + ;; + *) + not_supported + ;; +esac diff --git a/cdist/conf/type/__hostname/parameter/optional b/cdist/conf/type/__hostname/parameter/optional new file mode 100644 index 00000000..f121bdbf --- /dev/null +++ b/cdist/conf/type/__hostname/parameter/optional @@ -0,0 +1 @@ +name diff --git a/cdist/conf/type/__hostname/singleton b/cdist/conf/type/__hostname/singleton new file mode 100644 index 00000000..e69de29b From 29d4f910bcc61c9e16aa11d879fc3471bf93dffc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 13:50:42 +0100 Subject: [PATCH 460/548] do not change parameters Signed-off-by: Nico Schottelius --- cdist/conf/type/__hostname/gencode-remote | 8 +++++++- cdist/conf/type/__hostname/manifest | 6 +----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 88ee069a..ef8eda51 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,7 +19,12 @@ # along with cdist. If not, see . # -name="$(cat "$__object/parameter/name")" +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__target_host" +fi + os=$(cat "$__global/explorer/os") echo "printf '%s\n' '$name' > /etc/hostname" diff --git a/cdist/conf/type/__hostname/manifest b/cdist/conf/type/__hostname/manifest index 3aa6de45..0544a6f9 100755 --- a/cdist/conf/type/__hostname/manifest +++ b/cdist/conf/type/__hostname/manifest @@ -1,6 +1,7 @@ #!/bin/sh # # 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -18,10 +19,6 @@ # along with cdist. If not, see . # -# set defaults -name="$(cat "$__object/parameter/name" 2>/dev/null \ - || echo "${__target_host%%.*}" | tee "$__object/parameter/name")" - os=$(cat "$__global/explorer/os") not_supported() { @@ -33,7 +30,6 @@ not_supported() { case "$os" in archlinux|debian|ubuntu) # handled in gencode-remote - # FIXED: hostname setup in archlinuz via rc.local ist outdated : ;; *) From 9123940255d2dd0ceb908e47c63a0fdbcf439fc4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 13:51:48 +0100 Subject: [PATCH 461/548] port selection of first part into gencode-remote Signed-off-by: Nico Schottelius --- cdist/conf/type/__hostname/gencode-remote | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index ef8eda51..6760507f 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="$(cat "$__object/parameter/name")" else - name="$__target_host" + name="$(echo "${__target_host%%.*}")" fi os=$(cat "$__global/explorer/os") From cd6abf379ac10588a0e21949545d60c3d2a2b021 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 13:52:49 +0100 Subject: [PATCH 462/548] allow hostname -f to fail and return empty output Signed-off-by: Nico Schottelius --- cdist/conf/explorer/hostname | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/explorer/hostname b/cdist/conf/explorer/hostname index 881c910a..e1017227 100755 --- a/cdist/conf/explorer/hostname +++ b/cdist/conf/explorer/hostname @@ -1,6 +1,6 @@ #!/bin/sh # -# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2010-2014 Nico Schottelius (nico-cdist at schottelius.org) # 2012 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. @@ -21,5 +21,5 @@ # if command -v hostname >/dev/null; then - hostname -f + hostname -f 2>/dev/null || true fi From aee97cffd662ac21991517b6933a84409ca900b0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Mon, 20 Jan 2014 14:01:29 +0100 Subject: [PATCH 463/548] install proper packages Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_ppa/man.text | 7 +++++-- cdist/conf/type/__apt_ppa/manifest | 6 +++--- cdist/conf/type/__apt_ppa/parameter/default/state | 1 + cdist/conf/type/__apt_ppa/parameter/{required => optional} | 0 4 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 cdist/conf/type/__apt_ppa/parameter/default/state rename cdist/conf/type/__apt_ppa/parameter/{required => optional} (100%) diff --git a/cdist/conf/type/__apt_ppa/man.text b/cdist/conf/type/__apt_ppa/man.text index 6a5990d5..da18e9f0 100644 --- a/cdist/conf/type/__apt_ppa/man.text +++ b/cdist/conf/type/__apt_ppa/man.text @@ -16,7 +16,8 @@ This cdist type allows manage ubuntu ppa repositories. REQUIRED PARAMETERS ------------------- state:: - The state the ppa should be in, either "present" or "absent". + The state the ppa should be in, either 'present' or 'absent'. + Defaults to 'present' OPTIONAL PARAMETERS @@ -29,6 +30,8 @@ EXAMPLES -------------------------------------------------------------------------------- # 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 @@ -43,5 +46,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011 Steven Armstrong. Free use of this software is +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). diff --git a/cdist/conf/type/__apt_ppa/manifest b/cdist/conf/type/__apt_ppa/manifest index e7ad0c26..2d91942b 100755 --- a/cdist/conf/type/__apt_ppa/manifest +++ b/cdist/conf/type/__apt_ppa/manifest @@ -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. # @@ -20,9 +20,9 @@ name="$__object_id" -__package python-software-properties --state present +__package software-properties-common -require="__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/cdist/conf/type/__apt_ppa/parameter/default/state b/cdist/conf/type/__apt_ppa/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__apt_ppa/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__apt_ppa/parameter/required b/cdist/conf/type/__apt_ppa/parameter/optional similarity index 100% rename from cdist/conf/type/__apt_ppa/parameter/required rename to cdist/conf/type/__apt_ppa/parameter/optional From 8d5357107bda2b34b1ef55725bc0666d56ce6231 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:07:31 +0100 Subject: [PATCH 464/548] use uname -n in hostname explorer Signed-off-by: Nico Schottelius --- cdist/conf/explorer/hostname | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/explorer/hostname b/cdist/conf/explorer/hostname index e1017227..7715c6b0 100755 --- a/cdist/conf/explorer/hostname +++ b/cdist/conf/explorer/hostname @@ -20,6 +20,6 @@ # # -if command -v hostname >/dev/null; then - hostname -f 2>/dev/null || true +if command -v uname >/dev/null; then + uname -n fi From b6bae508a8641ee6a6bba0751bf57b2d8113b4bf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:26:22 +0100 Subject: [PATCH 465/548] use hostnamectl, if available, else use /etc/hostname and hostname Signed-off-by: Nico Schottelius --- .../type/__hostname/explorer/has_hostnamectl | 24 ++++++++++++++ .../type/__hostname/explorer/hostname_file | 26 +++++++++++++++ cdist/conf/type/__hostname/gencode-remote | 33 ++++++++++++------- cdist/conf/type/__hostname/man.text | 5 +++ 4 files changed, 77 insertions(+), 11 deletions(-) create mode 100755 cdist/conf/type/__hostname/explorer/has_hostnamectl create mode 100755 cdist/conf/type/__hostname/explorer/hostname_file diff --git a/cdist/conf/type/__hostname/explorer/has_hostnamectl b/cdist/conf/type/__hostname/explorer/has_hostnamectl new file mode 100755 index 00000000..9040023d --- /dev/null +++ b/cdist/conf/type/__hostname/explorer/has_hostnamectl @@ -0,0 +1,24 @@ +#!/bin/sh +# +# 2014 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 . +# +# +# Check whether system has hostnamectl +# + +command -v hostnamectl || true diff --git a/cdist/conf/type/__hostname/explorer/hostname_file b/cdist/conf/type/__hostname/explorer/hostname_file new file mode 100755 index 00000000..ed28c8a8 --- /dev/null +++ b/cdist/conf/type/__hostname/explorer/hostname_file @@ -0,0 +1,26 @@ +#!/bin/sh +# +# 2014 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 contents of /etc/hostname +# + +if [ -f /etc/hostname ]; then + cat /etc/hostname +fi diff --git a/cdist/conf/type/__hostname/gencode-remote b/cdist/conf/type/__hostname/gencode-remote index 6760507f..3d208cbe 100755 --- a/cdist/conf/type/__hostname/gencode-remote +++ b/cdist/conf/type/__hostname/gencode-remote @@ -20,20 +20,31 @@ # if [ -f "$__object/parameter/name" ]; then - name="$(cat "$__object/parameter/name")" + name_should="$(cat "$__object/parameter/name")" else - name="$(echo "${__target_host%%.*}")" + name_should="$(echo "${__target_host%%.*}")" fi os=$(cat "$__global/explorer/os") +name_running=$(cat "$__global/explorer/hostname") +name_config=$(cat "$__object/explorer/hostname_file") +has_hostnamectl=$(cat "$__object/explorer/has_hostnamectl") -echo "printf '%s\n' '$name' > /etc/hostname" +################################################################################ +# If everything is ok -> exit +# +if [ "$name_config" = "$name_should" -a "$name_running" = "$name_should" ]; then + exit 0 +fi -case "$os" in - debian|ubuntu) - echo "hostname \"$name\"" - ;; - archlinux) - echo "hostnamectl set-hostname \"$name\"" - ;; -esac +################################################################################ +# Setup hostname +# +echo changed >> "$__messages_out" + +if [ "$has_hostnamectl" ]; then + echo "hostnamectl set-hostname '$name_should'" +else + echo "hostname '$name_should'" + echo "printf '%s\n' '$name_should' > /etc/hostname" +fi diff --git a/cdist/conf/type/__hostname/man.text b/cdist/conf/type/__hostname/man.text index 07ec1083..ac44d426 100644 --- a/cdist/conf/type/__hostname/man.text +++ b/cdist/conf/type/__hostname/man.text @@ -24,6 +24,11 @@ name:: (${__target_host%%.*}) +MESSAGES +-------- +changed:: + Changed the hostname + EXAMPLES -------- From f7c44378732ff98954ae94a8c8fe74cf632f91ed Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:27:26 +0100 Subject: [PATCH 466/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index a3d5c4fd..f43131a1 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,8 @@ Changelog 3.0.3: * Core: Enhance error message when requirement is missing object id + * Explorer hostname: Return host name by using uname -n + * New Type: __hostname (Steven Armstrong) 3.0.2: 2014-01-19 * Documentation: Document all messages sent by types (Daniel Heule) From e40fde92fc95bed5e97e0715413b6a21f5780a42 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:40:54 +0100 Subject: [PATCH 467/548] allow releases from non-master branch, if the person knows what he does Signed-off-by: Nico Schottelius --- bin/build-helper | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/build-helper b/bin/build-helper index b97528f1..389e7696 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -207,7 +207,13 @@ eof # Ensure we are on the master branch if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ]; then echo "Releases are happening from the master branch, aborting" - exit 1 + + echo "Enter the magic word to release anyway" + read magicword + + if [ "$magicword" != "iknowwhatido" ]; then + exit 1 + fi fi # Ensure version branch exists From f034ed60279370314fe4d2c063a45e59f5ca3c34 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:43:48 +0100 Subject: [PATCH 468/548] do not merge, if not coming from the master branch Signed-off-by: Nico Schottelius --- bin/build-helper | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 389e7696..6210b907 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -205,25 +205,30 @@ eof 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 + if [ "$magicword" = "iknowwhatido" ]; then + masterbranch=no + else exit 1 fi fi - # Ensure version branch exists - if ! git rev-parse --verify refs/heads/$target_branch 2>/dev/null; then - git branch "$target_branch" - 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 + # Merge master branch into version branch + git checkout "$target_branch" + git merge master + fi # Verify that after the merge everything works "$0" check-date From 8ed5f85f9d5559f55ea41357d61217d3405c0610 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:48:05 +0100 Subject: [PATCH 469/548] do not change to the masterbranch... Signed-off-by: Nico Schottelius --- bin/build-helper | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/build-helper b/bin/build-helper index 6210b907..bfd7d31c 100755 --- a/bin/build-helper +++ b/bin/build-helper @@ -247,8 +247,10 @@ eof "$0" release-git-tag # Also merge back the version branch - git checkout master - git merge "$target_branch" + if [ "$masterbranch" = yes ]; then + git checkout master + git merge "$target_branch" + fi # Publish git changes make pub From 7eabdc3cf9af4552cca183c5c4cc4e540b7a1494 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 14:56:41 +0100 Subject: [PATCH 470/548] ignore pypi-release marker Signed-off-by: Nico Schottelius --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 63f8076a..baf9b6f2 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ build .lock-* .git-current-branch .lock* +.pypi-release From 4bd6158260f21b3da8b355edeb5cb2a8c7e19022 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 20 Jan 2014 16:19:41 +0100 Subject: [PATCH 471/548] add log from today Signed-off-by: Nico Schottelius --- docs/dev/logs/2014-01-20.environments | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/dev/logs/2014-01-20.environments diff --git a/docs/dev/logs/2014-01-20.environments b/docs/dev/logs/2014-01-20.environments new file mode 100644 index 00000000..88fe42b9 --- /dev/null +++ b/docs/dev/logs/2014-01-20.environments @@ -0,0 +1,44 @@ +raw quote from irc + +16:00 < sar> telmich: btw, ich denke nicht dass man install schon zu gross bewerben + sollte +16:00 < telmich> sar: ack +16:00 < sar> telmich: imho sollten wir erst die cdist environments implementieren, + install waere dann eines davon +16:00 < sar> config ein anderes +16:01 < sar> foobar noch ein anderes +16:01 < sar> es macht einfach keinen sinn auf type ebene install vs nicht-install zu + unterscheiden +16:02 < telmich> sar: environments sind bei mir noch nicht ganz im gehirn (ganicht?) + angelangt - hast du (nochmal?) kurz eine idee, was du damit meinst? +16:02 < sar> telmich: wenn man cdist anschaut, dann macht es eigentlich folgendes: +16:03 < sar> - definiere objekte mit hilfe von types +16:03 < sar> - deps zwischen objekten +16:03 < sar> - queue von objekten abarbeiten und auf $etwas anwenden +16:03 < sar> das ist alles +16:04 < sar> telmich: das ist eigentlich ziemlich generisch +16:04 < sar> telmich: fuer mich wuerde es sich hier anbieten das auch so zu + abstrahieren +16:05 < sar> telmich: ein environment (nenn das mal so weil kein besserer name zzt) + koennte das wie $objekt auf $etwas bestimmen +16:05 < sar> telmich: und auch was fuer types es in diesem environment gibt +16:06 < telmich> sar: klingt gut +16:06 < sar> telmich: e.g. es gibt ein environment fuer config -> was wir jetzt haben +16:06 < sar> eins fuer install -> += was im install branch ist (nur die types), den + python code brauchts nacher nicht mehr +16:07 < sar> eins fuer cisco-switch -> hat types um mit cisco zu spielen +16:07 < sar> usw +16:07 < sar> ein environment hat auch eigene remote-{exec,copy} scripte +16:08 < sar> und vielleicht globale explorer, vielleicht auch nicht +16:08 < sar> ein enviroment ist ein cconfig style directory +16:09 < sar> wo man cdist drueber laufen laesst +16:09 < sar> so was in der art +16:13 < telmich> sar: hmmja...klingt gut +16:15 < telmich> vielleicht etwas für cdist 4 oder cdist 5 :-) +16:15 < telmich> aber ich denke auf jeden fall als grundgedanke behaltbar +16:16 < telmich> ok für dich, wenn ich den chat ins docs/dev/logs kopiere als + erinnerungs +16:16 < telmich> s/s$/?/? +16:16 < telmich> s/?$// +16:20 < sar> klar + From 64f4cff3cb60eccb05eb385ec7e6b09f2292ff20 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 20 Jan 2014 20:30:37 +0100 Subject: [PATCH 472/548] Shell selection support via ENV CDIST_LOCAL_SHELL for local scripts CDIST_REMOTE_SHELL for remote scripts --- cdist/exec/local.py | 2 +- cdist/exec/remote.py | 2 +- cdist/shell.py | 5 +---- docs/man/man1/cdist.text | 14 ++++++++++---- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cdist/exec/local.py b/cdist/exec/local.py index 4233b874..2f75ffd4 100644 --- a/cdist/exec/local.py +++ b/cdist/exec/local.py @@ -188,7 +188,7 @@ class Local(object): Return the output as a string. """ - command = ["/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) diff --git a/cdist/exec/remote.py b/cdist/exec/remote.py index 7c807092..9b7d5d1c 100644 --- a/cdist/exec/remote.py +++ b/cdist/exec/remote.py @@ -113,7 +113,7 @@ class Remote(object): """ - command = ["/bin/sh", "-e"] + command = [ os.environ.get('CDIST_REMOTE_SHELL',"/bin/sh") , "-e"] command.append(script) return self.run(command, env, return_output) diff --git a/cdist/shell.py b/cdist/shell.py index ebf9f434..8ca68115 100644 --- a/cdist/shell.py +++ b/cdist/shell.py @@ -45,10 +45,7 @@ class Shell(object): """Select shell to execute, if not specified by user""" if not self.shell: - if 'SHELL' in os.environ: - self.shell = os.environ['SHELL'] - else: - self.shell = "/bin/sh" + self.shell = os.environ.get('SHELL',"/bin/sh") def _init_files_dirs(self): self.local.create_files_dirs() diff --git a/docs/man/man1/cdist.text b/docs/man/man1/cdist.text index de50a4ce..e8c12991 100644 --- a/docs/man/man1/cdist.text +++ b/docs/man/man1/cdist.text @@ -127,10 +127,16 @@ usage: __git --source SOURCE [--state STATE] [--branch BRANCH] ENVIRONMENT ----------- 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. + 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:: + Selects shell for local script execution, defaults to /bin/sh + +CDIST_REMOTE_SHELL:: + Selects shell for remote scirpt execution, defaults to /bin/sh EXIT STATUS From 6746ba827911b20e0f841ac53127ee4458b80d2c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 21 Jan 2014 09:16:45 +0100 Subject: [PATCH 473/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index f43131a1..74220980 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 3.0.3: * Core: Enhance error message when requirement is missing object id + * Core: Add environment variable to select shell for executing scripts (Daniel Heule) * Explorer hostname: Return host name by using uname -n * New Type: __hostname (Steven Armstrong) From 51c96624750a39c3498bc742b67d4ede5ac3cf18 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 21 Jan 2014 16:41:34 +0100 Subject: [PATCH 474/548] DO NOT USE ECHO WHEN SOMETHING MAY CONTAIN A B-A-C-K-S-L-A-S-H Signed-off-by: Nico Schottelius --- 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 d4796965..1fadf454 100755 --- a/cdist/conf/type/__line/gencode-remote +++ b/cdist/conf/type/__line/gencode-remote @@ -58,7 +58,7 @@ case "$state_should" in # Only replace ' with '"'"' and keep \ as they are line_sanitised=$(cat "$__object/parameter/line" | sed -e "s/'/'\"'\"'/g") - echo "printf '%s\n' '$line_sanitised' >> $file" + printf '%s' "printf '%s\n' '$line_sanitised' >> $file" ;; absent) From 520bcc29a79b7173dcd5c505e94a3a3a173210cb Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 21 Jan 2014 16:43:02 +0100 Subject: [PATCH 475/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 74220980..242f92b0 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,6 +9,7 @@ Changelog * Core: Add environment variable to select shell for executing scripts (Daniel Heule) * Explorer hostname: Return host name by using uname -n * New Type: __hostname (Steven Armstrong) + * Type __line: Use printf instead of echo for printing user input 3.0.2: 2014-01-19 * Documentation: Document all messages sent by types (Daniel Heule) From 92e67182a65c9421dc1a65e5de545c18bca46606 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 21 Jan 2014 22:24:35 +0100 Subject: [PATCH 476/548] parameter default handling in __cdist type corrected --- cdist/conf/type/__cdist/manifest | 18 +++--------------- .../conf/type/__cdist/parameter/default/branch | 1 + .../conf/type/__cdist/parameter/default/source | 1 + .../type/__cdist/parameter/default/username | 1 + 4 files changed, 6 insertions(+), 15 deletions(-) create mode 100644 cdist/conf/type/__cdist/parameter/default/branch create mode 100644 cdist/conf/type/__cdist/parameter/default/source create mode 100644 cdist/conf/type/__cdist/parameter/default/username diff --git a/cdist/conf/type/__cdist/manifest b/cdist/conf/type/__cdist/manifest index 44d62f6c..7c0ae60e 100755 --- a/cdist/conf/type/__cdist/manifest +++ b/cdist/conf/type/__cdist/manifest @@ -27,23 +27,11 @@ else shell="" fi -if [ -f "$__object/parameter/username" ]; then - username="$(cat "$__object/parameter/username")" -else - username="cdist" -fi +username="$(cat "$__object/parameter/username")" -if [ -f "$__object/parameter/branch" ]; then - branch="$(cat "$__object/parameter/branch")" -else - branch="master" -fi +branch="$(cat "$__object/parameter/branch")" -if [ -f "$__object/parameter/source" ]; then - source="$(cat "$__object/parameter/source")" -else - source="git://github.com/telmich/cdist.git" -fi +source="$(cat "$__object/parameter/source")" # Currently hardcoded - if anyone cares, make a parameter # out of it diff --git a/cdist/conf/type/__cdist/parameter/default/branch b/cdist/conf/type/__cdist/parameter/default/branch new file mode 100644 index 00000000..1f7391f9 --- /dev/null +++ b/cdist/conf/type/__cdist/parameter/default/branch @@ -0,0 +1 @@ +master diff --git a/cdist/conf/type/__cdist/parameter/default/source b/cdist/conf/type/__cdist/parameter/default/source new file mode 100644 index 00000000..d669308f --- /dev/null +++ b/cdist/conf/type/__cdist/parameter/default/source @@ -0,0 +1 @@ +git://github.com/telmich/cdist.git diff --git a/cdist/conf/type/__cdist/parameter/default/username b/cdist/conf/type/__cdist/parameter/default/username new file mode 100644 index 00000000..a585e141 --- /dev/null +++ b/cdist/conf/type/__cdist/parameter/default/username @@ -0,0 +1 @@ +cdist From 02c3fe49887d75d28d581221cf51eeaf00e66379 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 21 Jan 2014 22:33:10 +0100 Subject: [PATCH 477/548] parameter default handling in __qemu_img type corrected --- cdist/conf/type/__qemu_img/gencode-remote | 6 ++---- cdist/conf/type/__qemu_img/manifest | 6 ++---- cdist/conf/type/__qemu_img/parameter/default/format | 1 + cdist/conf/type/__qemu_img/parameter/default/state | 1 + cdist/conf/type/__qemu_img/parameter/optional | 1 + 5 files changed, 7 insertions(+), 8 deletions(-) create mode 100644 cdist/conf/type/__qemu_img/parameter/default/format create mode 100644 cdist/conf/type/__qemu_img/parameter/default/state diff --git a/cdist/conf/type/__qemu_img/gencode-remote b/cdist/conf/type/__qemu_img/gencode-remote index 2a76cf8f..6e4bb4d0 100644 --- a/cdist/conf/type/__qemu_img/gencode-remote +++ b/cdist/conf/type/__qemu_img/gencode-remote @@ -2,8 +2,7 @@ # State: absent is handled by manifest - we need only to do stuff if image is # not existing and state != absent # -state="present" -[ -f "$__object/parameter/state" ] && state="$(cat "$__object/parameter/state")" +state="$(cat "$__object/parameter/state")" [ "$state" = "absent" ] && exit 0 exists="$(cat "$__object/explorer/exists")" @@ -13,8 +12,7 @@ exists="$(cat "$__object/explorer/exists")" # Still there? Create image # -format=qcow2 -[ -f "$__object/parameter/format" ] && format="$(cat "$__object/parameter/format")" +format="$(cat "$__object/parameter/format")" size="$(cat "$__object/parameter/size")" diskimage="/$__object_id" diff --git a/cdist/conf/type/__qemu_img/manifest b/cdist/conf/type/__qemu_img/manifest index b835301d..6d50037f 100644 --- a/cdist/conf/type/__qemu_img/manifest +++ b/cdist/conf/type/__qemu_img/manifest @@ -2,10 +2,8 @@ # Default settings # -format=qcow2 -state=present -[ -f "$__object/parameter/format" ] && format="$(cat "$__object/parameter/format")" -[ -f "$__object/parameter/state" ] && state="$(cat "$__object/parameter/state")" +format="$(cat "$__object/parameter/format")" +state="$(cat "$__object/parameter/state")" diskimage="/$__object_id" diff --git a/cdist/conf/type/__qemu_img/parameter/default/format b/cdist/conf/type/__qemu_img/parameter/default/format new file mode 100644 index 00000000..e0a90ab9 --- /dev/null +++ b/cdist/conf/type/__qemu_img/parameter/default/format @@ -0,0 +1 @@ +qcow2 diff --git a/cdist/conf/type/__qemu_img/parameter/default/state b/cdist/conf/type/__qemu_img/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__qemu_img/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__qemu_img/parameter/optional b/cdist/conf/type/__qemu_img/parameter/optional index 0e8469e7..71b9a32b 100644 --- a/cdist/conf/type/__qemu_img/parameter/optional +++ b/cdist/conf/type/__qemu_img/parameter/optional @@ -1 +1,2 @@ format +state From 08b8270739b7a17778d5e5427d6635b65ba1484a Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 21 Jan 2014 22:45:35 +0100 Subject: [PATCH 478/548] parameter default handling in __zypper_service type corrected --- cdist/conf/type/__zypper_service/gencode-remote | 13 ++----------- cdist/conf/type/__zypper_service/manifest | 6 +----- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/cdist/conf/type/__zypper_service/gencode-remote b/cdist/conf/type/__zypper_service/gencode-remote index d11749ae..df8d1660 100644 --- a/cdist/conf/type/__zypper_service/gencode-remote +++ b/cdist/conf/type/__zypper_service/gencode-remote @@ -39,17 +39,8 @@ else uri="$__object_id" fi -if [ -f "$__object/parameter/state" ]; then - state_should="$(cat "$__object/parameter/state")" -else - state_should="present" -fi - -if [ -f "$__object/parameter/type" ]; then - stype="$(cat "$__object/parameter/type")" -else - stype="ris" -fi +state_should="$(cat "$__object/parameter/state")" +stype="$(cat "$__object/parameter/type")" exp_uri="$(cat "$__object/explorer/service_uri")" exp_id="$(cat "$__object/explorer/service_id")" diff --git a/cdist/conf/type/__zypper_service/manifest b/cdist/conf/type/__zypper_service/manifest index d8773605..aa4a39a3 100644 --- a/cdist/conf/type/__zypper_service/manifest +++ b/cdist/conf/type/__zypper_service/manifest @@ -33,11 +33,7 @@ else uri="$__object_id" fi -if [ -f "$__object/parameter/state" ]; then - state_should="$(cat "$__object/parameter/state")" -else - state_should="present" -fi +state_should="$(cat "$__object/parameter/state")" exp_uri="$(cat "$__object/explorer/service_uri")" From 360b42e89219d088b4bfb24db610672111f7b9bd Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 21 Jan 2014 22:57:06 +0100 Subject: [PATCH 479/548] parameter default handling in __zypper_repo type corrected --- cdist/conf/type/__zypper_repo/gencode-remote | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cdist/conf/type/__zypper_repo/gencode-remote b/cdist/conf/type/__zypper_repo/gencode-remote index 4d834c47..f678552b 100644 --- a/cdist/conf/type/__zypper_repo/gencode-remote +++ b/cdist/conf/type/__zypper_repo/gencode-remote @@ -45,11 +45,7 @@ else id="$__object_id" fi -if [ -f "$__object/parameter/state" ]; then - state="$(cat "$__object/parameter/state")" -else - state="present" -fi +state="$(cat "$__object/parameter/state")" repo_id="$(cat "$__object/explorer/repo_id")" From b75481a4d41cb45c25cccdf2bfb053a10e7b9ede Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 21 Jan 2014 23:18:10 +0100 Subject: [PATCH 480/548] parameter default handling in __key_value type corrected --- cdist/conf/type/__key_value/gencode-remote | 4 ++-- cdist/conf/type/__key_value/manifest | 3 +-- cdist/conf/type/__key_value/parameter/default/state | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 cdist/conf/type/__key_value/parameter/default/state diff --git a/cdist/conf/type/__key_value/gencode-remote b/cdist/conf/type/__key_value/gencode-remote index ec91894f..b79d9688 100755 --- a/cdist/conf/type/__key_value/gencode-remote +++ b/cdist/conf/type/__key_value/gencode-remote @@ -21,8 +21,8 @@ key="$__object_id" [ -f "$__object/parameter/key" ] && key="$(cat "$__object/parameter/key")" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" + +state_should="$(cat "$__object/parameter/state")" file="$(cat "$__object/parameter/file")" delimiter="$(cat "$__object/parameter/delimiter")" diff --git a/cdist/conf/type/__key_value/manifest b/cdist/conf/type/__key_value/manifest index 8ed9cc9c..56f4c874 100755 --- a/cdist/conf/type/__key_value/manifest +++ b/cdist/conf/type/__key_value/manifest @@ -19,8 +19,7 @@ # along with cdist. If not, see . # -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" if [ "$state_should" = "present" -a ! -f "$__object/parameter/value" ]; then echo "Missing required parameter 'value'" >&2 diff --git a/cdist/conf/type/__key_value/parameter/default/state b/cdist/conf/type/__key_value/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__key_value/parameter/default/state @@ -0,0 +1 @@ +present From 0e49ccbf4369acc66b351b984685ad35a064de3e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 22 Jan 2014 00:44:56 +0100 Subject: [PATCH 481/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog b/docs/changelog index 242f92b0..4addc772 100644 --- a/docs/changelog +++ b/docs/changelog @@ -9,7 +9,12 @@ Changelog * Core: Add environment variable to select shell for executing scripts (Daniel Heule) * Explorer hostname: Return host name by using uname -n * New Type: __hostname (Steven Armstrong) + * Type __cdist: Use default paremeters (Daniel Heule) + * Type __key_value: Use default paremeters (Daniel Heule) * Type __line: Use printf instead of echo for printing user input + * Type __qemu_img: Use default paremeters (Daniel Heule) + * Type __zypper_repo: Use default paremeters (Daniel Heule) + * Type __zypper_service: Use default paremeters (Daniel Heule) 3.0.2: 2014-01-19 * Documentation: Document all messages sent by types (Daniel Heule) From 87d72dfc1a7b6c4a8c2d0bbd77c6188dac8555fa Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 22 Jan 2014 00:46:35 +0100 Subject: [PATCH 482/548] release: 3.0.3 Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 4addc772..d4100898 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,7 +4,7 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -3.0.3: +3.0.3: 2014-01-22 * Core: Enhance error message when requirement is missing object id * Core: Add environment variable to select shell for executing scripts (Daniel Heule) * Explorer hostname: Return host name by using uname -n From 7a0b3cd7b7d416d16ff34f03402110b6327cf8a0 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 22 Jan 2014 21:21:34 +0100 Subject: [PATCH 483/548] python-software-properties still needed for older ubuntu versions Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_ppa/manifest | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_ppa/manifest b/cdist/conf/type/__apt_ppa/manifest index 2d91942b..1d90e9c4 100755 --- a/cdist/conf/type/__apt_ppa/manifest +++ b/cdist/conf/type/__apt_ppa/manifest @@ -21,8 +21,9 @@ name="$__object_id" __package software-properties-common +__package python-software-properties -require="__package/software-properties-common" \ +require="__package/software-properties-common __package/python-software-properties" \ __file /usr/local/bin/remove-apt-repository \ --source "$__type/files/remove-apt-repository" \ --mode 0755 From a62e4aade352cc4786a1240ef8b5912234e1c856 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 22 Jan 2014 22:07:12 +0100 Subject: [PATCH 484/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index d4100898..d8af2cf3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,9 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +3.0.4: + * Type __apt_ppa: Install required software (Steven Armstrong) + 3.0.3: 2014-01-22 * Core: Enhance error message when requirement is missing object id * Core: Add environment variable to select shell for executing scripts (Daniel Heule) From 78be159eb789dfef83421cff5703d0b54f25c904 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 27 Jan 2014 14:15:41 +0100 Subject: [PATCH 485/548] update reference: we also do not touch 'files' in the object Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index a72452eb..5c9f603c 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -131,7 +131,8 @@ confdir/type//explorer:: confdir/type//files:: This directory is reserved for user data and will not be used - by cdist at any time + 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 @@ -175,9 +176,16 @@ 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 excuted (either remote or local) +stdin:: + This file exists and contains data, if data was provided on stdin + when the type was called. ENVIRONMENT VARIABLES From 9049a1421cfd5b5e8f4ee72e79178ab90dce681c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 27 Jan 2014 14:17:51 +0100 Subject: [PATCH 486/548] support --file - in __debconf_set_selections Signed-off-by: Nico Schottelius --- .../conf/type/__debconf_set_selections/gencode-remote | 10 ++++++++-- cdist/conf/type/__debconf_set_selections/man.text | 7 ++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__debconf_set_selections/gencode-remote b/cdist/conf/type/__debconf_set_selections/gencode-remote index 62be6a12..4892ec25 100755 --- a/cdist/conf/type/__debconf_set_selections/gencode-remote +++ b/cdist/conf/type/__debconf_set_selections/gencode-remote @@ -1,6 +1,6 @@ #!/bin/sh # -# 2011 Nico Schottelius (nico-cdist at schottelius.org) +# 2011-2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -21,6 +21,12 @@ # Setup selections # +filename"$(cat "$__object/parameter/file")" + +if [ "$filename" = "-" ]; then + filename="$__object/stdin" +fi + echo "debconf-set-selections << __file-eof" -cat "$(cat "$__object/parameter/file")" +cat "$(cat "$filename")" echo "__file-eof" diff --git a/cdist/conf/type/__debconf_set_selections/man.text b/cdist/conf/type/__debconf_set_selections/man.text index f1e13a8e..e36ebaa3 100644 --- a/cdist/conf/type/__debconf_set_selections/man.text +++ b/cdist/conf/type/__debconf_set_selections/man.text @@ -18,6 +18,7 @@ REQUIRED PARAMETERS ------------------- file:: Use the given filename as input for debconf-set-selections(1) + If filename is "-", read from stdin. EXAMPLES @@ -29,6 +30,10 @@ __debconf_set_selections nslcd --file /path/to/file # 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 -------------------------------------------------------------------------------- @@ -41,5 +46,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is +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). From 565e11b16dc53c0d887c4060940c7bffb2e581d5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 27 Jan 2014 14:18:56 +0100 Subject: [PATCH 487/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index d8af2cf3..d9c2c8b5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,10 @@ Changelog * Exception: No braces means author == Nico Schottelius 3.0.4: + * Documentation: Update reference (files path in object space) * Type __apt_ppa: Install required software (Steven Armstrong) + * Type __debconf_set_selections: Support --file - to read from stdin + 3.0.3: 2014-01-22 * Core: Enhance error message when requirement is missing object id @@ -19,6 +22,7 @@ Changelog * Type __zypper_repo: Use default paremeters (Daniel Heule) * Type __zypper_service: Use default paremeters (Daniel Heule) + 3.0.2: 2014-01-19 * Documentation: Document all messages sent by types (Daniel Heule) * New Type: __block (Steven Armstrong) From 4ef55ef13f9172ab6bb045d5a6bfb7acec982758 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 27 Jan 2014 16:19:01 +0100 Subject: [PATCH 488/548] allow object overrides with CDIST_ALLOW_OVERRIDE=true --- cdist/core/cdist_object.py | 6 ++++-- cdist/emulator.py | 5 ++++- docs/man/man7/cdist-manifest.text | 24 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 45b5e3ff..9ead71c7 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -2,6 +2,7 @@ # # 2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -215,9 +216,10 @@ class CdistObject(object): """Create this cdist object on the filesystem. """ try: - os.makedirs(self.absolute_path, exist_ok=False) + cdexist_ok = True if os.environ.get('CDIST_ALLOW_OVERRIDE',"false") == 'true' else False + os.makedirs(self.absolute_path, exist_ok=cdexist_ok) absolute_parameter_path = os.path.join(self.base_path, self.parameter_path) - os.makedirs(absolute_parameter_path, exist_ok=False) + os.makedirs(absolute_parameter_path, exist_ok=cdexist_ok) except EnvironmentError as error: raise cdist.Error('Error creating directories for cdist object: %s: %s' % (self, error)) diff --git a/cdist/emulator.py b/cdist/emulator.py index 63d3bbbc..0693eb35 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -2,6 +2,7 @@ # # 2011-2013 Nico Schottelius (nico-cdist at schottelius.org) # 2012 Steven Armstrong (steven-cdist at armstrong.cc) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -144,12 +145,14 @@ class Emulator(object): if value is not None: self.parameters[key] = value - if self.cdist_object.exists: + if self.cdist_object.exists and os.environ.get('CDIST_ALLOW_OVERRIDE',"false") != 'true': 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) ) else: + if self.cdist_object.exists: + self.log.debug('Object %s override forced with CDIST_ALLOW_OVERRIDE=true',self.cdist_object.name) self.cdist_object.create() self.cdist_object.parameters = self.parameters diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 92d0b897..84dc36ae 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -161,6 +161,30 @@ __package lighttpd --state present require="__package/lighttpd" __package munin --state present -------------------------------------------------------------------------------- +OVERRIDES +--------- +In some special cases, you would like to create an allready defined object +with different parameters. In normal situations this leads to an error in cdist. +If you whish, you can mark this second definition of an object with +CDIST_ALLOW_OVERRIDE=true to tell cdist, that this object override is +wanted and should be accepted. + +-------------------------------------------------------------------------------- +# for example in the inial manifest + +# reate user account foobar with some hash for password +__user foobar --password 'some_fancy_hash' + +# ... many statements and includes in the manifest later ... +# somewhere in a conditionaly sourced manifest +# (e.g. for example only sourced if a special application is on the target host) + +# 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_ALLOW_OVERRIDE=true __user foobar --password 'some_other_hash' +-------------------------------------------------------------------------------- SEE ALSO From 723be34bca37e97cb7cf3d94367d5e224ec7b325 Mon Sep 17 00:00:00 2001 From: Jake Guffey Date: Mon, 27 Jan 2014 13:22:03 -0500 Subject: [PATCH 489/548] Fixed typo Was assigning jaildir=$object/parameter/name, fixed to $object/parameter/jaildir --- cdist/conf/type/__jail/gencode-local | 2 +- cdist/conf/type/__jail/gencode-remote | 2 +- cdist/conf/type/__jail/manifest | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__jail/gencode-local b/cdist/conf/type/__jail/gencode-local index 075a6ef1..d6384156 100755 --- a/cdist/conf/type/__jail/gencode-local +++ b/cdist/conf/type/__jail/gencode-local @@ -23,7 +23,7 @@ # if [ -f "$__object/parameter/jaildir" ]; then - jaildir="$(cat "$__object/parameter/name")" + jaildir="$(cat "$__object/parameter/jaildir")" else jaildir="/usr/jail" fi diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote index b044e4b0..afbb81a5 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail/gencode-remote @@ -85,7 +85,7 @@ if [ -f "$__object/parameter/onboot" ]; then fi if [ -f "$__object/parameter/jaildir" ]; then - jaildir="$(cat "$__object/parameter/name")" + jaildir="$(cat "$__object/parameter/jaildir")" else jaildir="/usr/jail" fi diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index 0570d62d..cf5b7938 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -34,7 +34,7 @@ if [ ! "$os" = "freebsd" ]; then fi if [ -f "$__object/parameter/jaildir" ]; then - jaildir="$(cat "$__object/parameter/name")" + jaildir="$(cat "$__object/parameter/jaildir")" else jaildir="/usr/jail" fi From e52a059adfbb2152d33f0cb9e7c1516db9e00188 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 27 Jan 2014 19:38:26 +0100 Subject: [PATCH 490/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index d9c2c8b5..34e44913 100644 --- a/docs/changelog +++ b/docs/changelog @@ -8,6 +8,7 @@ Changelog * Documentation: Update reference (files path in object space) * Type __apt_ppa: Install required software (Steven Armstrong) * Type __debconf_set_selections: Support --file - to read from stdin + * Type __jail: Fix jaildir parameter handling (Jake Guffey) 3.0.3: 2014-01-22 From aa3e92f07b9ff91b298064ba8b6173ad0a1dcea6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 29 Jan 2014 21:08:22 +0100 Subject: [PATCH 491/548] use directory files/, not templates Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-best-practice.text | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/man/man7/cdist-best-practice.text b/docs/man/man7/cdist-best-practice.text index e6685cad..a818be60 100644 --- a/docs/man/man7/cdist-best-practice.text +++ b/docs/man/man7/cdist-best-practice.text @@ -164,8 +164,8 @@ For more details consult sudoers(5) TEMPLATING ---------- -* create directory templates/ in your type (convention) -* create the template as an executable file like templates/basic.conf.sh, it will output text using shell variables for the values +* 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 @@ -191,7 +191,7 @@ EOF export ROOT='/var/www/test' # render the template mkdir -p "$__object/files" - "$__type/templates/basic.conf.sh" > "$__object/files/basic.conf" + "$__type/files/basic.conf.sh" > "$__object/files/basic.conf" # send the rendered template __file /etc/nginx/sites-available/test.conf \ --state present From 16d51b3cf11b445b24189bf225d2c9b37013a4a5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 29 Jan 2014 22:40:59 +0100 Subject: [PATCH 492/548] backport ignoring install types in config mode from install_integration branch Signed-off-by: Nico Schottelius --- cdist/config.py | 6 +++++- cdist/core/cdist_type.py | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/cdist/config.py b/cdist/config.py index 3f8a7fc6..73ba4710 100644 --- a/cdist/config.py +++ b/cdist/config.py @@ -163,7 +163,11 @@ class Config(object): """Short name for object list retrieval""" for cdist_object in core.CdistObject.list_objects(self.local.object_path, self.local.type_path): - yield cdist_object + if cdist_object.cdist_type.is_install: + self.log.debug("Running in config mode, ignoring install object: {0}".format(cdist_object)) + else: + yield cdist_object + def iterate_once(self): """ diff --git a/cdist/core/cdist_type.py b/cdist/core/cdist_type.py index 46e126f9..ff1ebaec 100644 --- a/cdist/core/cdist_type.py +++ b/cdist/core/cdist_type.py @@ -101,6 +101,11 @@ class CdistType(object): """Check whether a type is a singleton.""" return os.path.isfile(os.path.join(self.absolute_path, "singleton")) + @property + def is_install(self): + """Check whether a type is used for installation (if not: for configuration)""" + return os.path.isfile(os.path.join(self.absolute_path, "install")) + @property def explorers(self): """Return a list of available explorers""" From 228ed4dbd2608fc39a9dd878b44faed3b8cb5b58 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 29 Jan 2014 23:19:07 +0100 Subject: [PATCH 493/548] fix typos in __debconf_set_selections Signed-off-by: Nico Schottelius --- cdist/conf/type/__debconf_set_selections/gencode-remote | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__debconf_set_selections/gencode-remote b/cdist/conf/type/__debconf_set_selections/gencode-remote index 4892ec25..bb719c46 100755 --- a/cdist/conf/type/__debconf_set_selections/gencode-remote +++ b/cdist/conf/type/__debconf_set_selections/gencode-remote @@ -21,12 +21,12 @@ # Setup selections # -filename"$(cat "$__object/parameter/file")" +filename="$(cat "$__object/parameter/file")" if [ "$filename" = "-" ]; then filename="$__object/stdin" fi echo "debconf-set-selections << __file-eof" -cat "$(cat "$filename")" +cat "$filename" echo "__file-eof" From d5f04b26c8e2f8f9a64a0a362695f3685a4c9b4d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 29 Jan 2014 23:19:18 +0100 Subject: [PATCH 494/548] ++changes(3.0.4) Signed-off-by: Nico Schottelius --- docs/changelog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 34e44913..32b4e42e 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,8 +4,10 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -3.0.4: +3.0.4: 2014-01-29 + * Core: Ignore install types in config mode * Documentation: Update reference (files path in object space) + * Documentation: Update best practise: Replaces templates/ with files/ * Type __apt_ppa: Install required software (Steven Armstrong) * Type __debconf_set_selections: Support --file - to read from stdin * Type __jail: Fix jaildir parameter handling (Jake Guffey) From 197fabf40ac3c84f8bed89e3576b82672496bb61 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 31 Jan 2014 17:56:55 +0100 Subject: [PATCH 495/548] added some ideas from asteven and a bit more description about the order in the manpage --- cdist/core/cdist_object.py | 7 +++---- cdist/emulator.py | 4 +++- docs/man/man7/cdist-manifest.text | 5 ++++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index 9ead71c7..b17bd339 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -212,14 +212,13 @@ class CdistObject(object): """Checks wether this cdist object exists on the file systems.""" return os.path.exists(self.absolute_path) - def create(self): + def create(self, allow_overwrite=False): """Create this cdist object on the filesystem. """ try: - cdexist_ok = True if os.environ.get('CDIST_ALLOW_OVERRIDE',"false") == 'true' else False - os.makedirs(self.absolute_path, exist_ok=cdexist_ok) + 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=cdexist_ok) + 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)) diff --git a/cdist/emulator.py b/cdist/emulator.py index 0693eb35..e32f12e0 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -153,7 +153,9 @@ class Emulator(object): else: if self.cdist_object.exists: self.log.debug('Object %s override forced with CDIST_ALLOW_OVERRIDE=true',self.cdist_object.name) - self.cdist_object.create() + self.cdist_object.create(True) + else + self.cdist_object.create() self.cdist_object.parameters = self.parameters # Record / Append source diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 84dc36ae..d9bcb893 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -163,11 +163,14 @@ require="__package/lighttpd" __package munin --state present OVERRIDES --------- -In some special cases, you would like to create an allready defined object +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 mark this second definition of an object with CDIST_ALLOW_OVERRIDE=true 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 encounter the affected objects, otherwhise this results +into an undefined situation. -------------------------------------------------------------------------------- # for example in the inial manifest From 5fbac8d0baa85197216ed1e3cb3fa7262415fb40 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 31 Jan 2014 17:59:56 +0100 Subject: [PATCH 496/548] forgot the : after the else ... --- cdist/emulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index e32f12e0..ed846e6d 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -154,7 +154,7 @@ class Emulator(object): if self.cdist_object.exists: self.log.debug('Object %s override forced with CDIST_ALLOW_OVERRIDE=true',self.cdist_object.name) self.cdist_object.create(True) - else + else: self.cdist_object.create() self.cdist_object.parameters = self.parameters From 99dedc493349f25dbc6ca191c78d395472a779c8 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 31 Jan 2014 21:48:09 +0100 Subject: [PATCH 497/548] examples are always the last section Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-manifest.text | 58 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index d9bcb893..af86b7ee 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -129,6 +129,35 @@ from the type that is calling them. This is called "autorequirement" in cdist jargon. +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 mark this second definition of an object with +CDIST_ALLOW_OVERRIDE=true 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 encounter the affected objects, otherwhise this results +into an undefined situation. + +-------------------------------------------------------------------------------- +# for example in the inial manifest + +# reate user account foobar with some hash for password +__user foobar --password 'some_fancy_hash' + +# ... many statements and includes in the manifest later ... +# somewhere in a conditionaly sourced manifest +# (e.g. for example only sourced if a special application is on the target host) + +# 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_ALLOW_OVERRIDE=true __user foobar --password 'some_other_hash' +-------------------------------------------------------------------------------- + + EXAMPLES -------- The initial manifest may for instance contain the following code: @@ -161,35 +190,6 @@ __package lighttpd --state present require="__package/lighttpd" __package munin --state present -------------------------------------------------------------------------------- -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 mark this second definition of an object with -CDIST_ALLOW_OVERRIDE=true 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 encounter the affected objects, otherwhise this results -into an undefined situation. - --------------------------------------------------------------------------------- -# for example in the inial manifest - -# reate user account foobar with some hash for password -__user foobar --password 'some_fancy_hash' - -# ... many statements and includes in the manifest later ... -# somewhere in a conditionaly sourced manifest -# (e.g. for example only sourced if a special application is on the target host) - -# 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_ALLOW_OVERRIDE=true __user foobar --password 'some_other_hash' --------------------------------------------------------------------------------- - - SEE ALSO -------- - cdist-tutorial(7) From dc1a5dfd6dff5fbaeb544680e511246d653a792d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 31 Jan 2014 21:50:32 +0100 Subject: [PATCH 498/548] update override documentation Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-manifest.text | 38 +++++++++++++++++-------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index af86b7ee..7292a64f 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -140,23 +140,7 @@ ATTENTION: Only use this feature if you are 100% sure in which order cdist encounter the affected objects, otherwhise this results into an undefined situation. --------------------------------------------------------------------------------- -# for example in the inial manifest - -# reate user account foobar with some hash for password -__user foobar --password 'some_fancy_hash' - -# ... many statements and includes in the manifest later ... -# somewhere in a conditionaly sourced manifest -# (e.g. for example only sourced if a special application is on the target host) - -# 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_ALLOW_OVERRIDE=true __user foobar --password 'some_other_hash' --------------------------------------------------------------------------------- - +THIS IS A BETA FEATURE AND MAY BE REMOVED AT ANY TIME. EXAMPLES -------- @@ -190,6 +174,26 @@ __package lighttpd --state present require="__package/lighttpd" __package munin --state present -------------------------------------------------------------------------------- +How to override objects: + +-------------------------------------------------------------------------------- +# for example in the inital manifest + +# reate user account foobar with some hash for password +__user foobar --password 'some_fancy_hash' + +# ... many statements and includes in the manifest later ... +# somewhere in a conditionaly sourced manifest +# (e.g. for example only sourced if a special application is on the target host) + +# 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_ALLOW_OVERRIDE=true __user foobar --password 'some_other_hash' +-------------------------------------------------------------------------------- + + SEE ALSO -------- - cdist-tutorial(7) From ab3b15191884428689b6dd7379bea4278dd13ccd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 31 Jan 2014 21:52:43 +0100 Subject: [PATCH 499/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog b/docs/changelog index 32b4e42e..bd52bd78 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,6 +4,10 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius +3.0.5: + * Core: Introduce override concept (Daniel Heule) + + 3.0.4: 2014-01-29 * Core: Ignore install types in config mode * Documentation: Update reference (files path in object space) From 3a57367e7e895d3d4fe9fd761f0264df80aed0e3 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Sat, 1 Feb 2014 22:46:36 +0100 Subject: [PATCH 500/548] bugfix: make type actually work with --state absent Signed-off-by: Steven Armstrong --- cdist/conf/type/__process/gencode-remote | 17 +++++++---------- .../conf/type/__process/parameter/default/state | 1 + 2 files changed, 8 insertions(+), 10 deletions(-) create mode 100644 cdist/conf/type/__process/parameter/default/state diff --git a/cdist/conf/type/__process/gencode-remote b/cdist/conf/type/__process/gencode-remote index 41bc5381..639940d9 100755 --- a/cdist/conf/type/__process/gencode-remote +++ b/cdist/conf/type/__process/gencode-remote @@ -1,6 +1,7 @@ #!/bin/sh # # 2011-2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) # # This file is part of cdist. # @@ -17,7 +18,6 @@ # 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")" @@ -25,21 +25,18 @@ else name="$__object_id" fi -parameter_state="$__object/parameter/state" -if [ -f "$_parameter_state" ]; then - state_should=$(cat "$__object/parameter/state") -else - state_should="present" -fi +state_should="$(cat "$__object/parameter/state")" -runs="$(cat "$__object/explorer/runs")" -if [ "$runs" ]; then +if [ -s "$__object/explorer/runs" ]; then state_is="present" else state_is="absent" fi -[ "$state_is" = "$state_should" ] && exit 0 +if [ "$state_is" = "$state_should" ]; then + # nothing to do + exit 0 +fi case "$state_should" in present) diff --git a/cdist/conf/type/__process/parameter/default/state b/cdist/conf/type/__process/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__process/parameter/default/state @@ -0,0 +1 @@ +present From 1b455e810b449aa2dc3771595f90cfcd298ac501 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Sun, 2 Feb 2014 20:29:41 +0100 Subject: [PATCH 501/548] clarify in the example that override don't touch parameter witch are not present in the 2nd call --- docs/man/man7/cdist-manifest.text | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 7292a64f..aa146267 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -180,7 +180,7 @@ How to override objects: # for example in the inital manifest # reate user account foobar with some hash for password -__user foobar --password 'some_fancy_hash' +__user foobar --password 'some_fancy_hash' --home /home/foobarexample # ... many statements and includes in the manifest later ... # somewhere in a conditionaly sourced manifest @@ -191,6 +191,8 @@ __user foobar --password 'some_other_hash' # this tells cdist, that you know that this is an override and should be accepted CDIST_ALLOW_OVERRIDE=true __user foobar --password 'some_other_hash' +# its only an override, means the parameter --home is not touched +# and stay at the original value of /home/foobarexample -------------------------------------------------------------------------------- From 3c52710763a3f8537f732e716e53439d1b6af494 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Mon, 3 Feb 2014 21:43:39 +0100 Subject: [PATCH 502/548] little changes for using default parameters correctly --- cdist/conf/type/__git/gencode-remote | 15 +++++---------- cdist/conf/type/__git/manifest | 3 +-- cdist/conf/type/__git/parameter/default/branch | 1 + cdist/conf/type/__git/parameter/default/group | 1 + cdist/conf/type/__git/parameter/default/mode | 1 + cdist/conf/type/__git/parameter/default/owner | 1 + cdist/conf/type/__git/parameter/default/state | 1 + cdist/conf/type/__jail/gencode-local | 12 ++---------- cdist/conf/type/__jail/gencode-remote | 13 +++---------- cdist/conf/type/__jail/manifest | 6 +----- .../type/__jail/parameter/default/devfs-ruleset | 1 + cdist/conf/type/__jail/parameter/default/jailbase | 1 + cdist/conf/type/__jail/parameter/default/jaildir | 1 + cdist/conf/type/__package_yum/gencode-remote | 6 +----- .../type/__package_yum/parameter/default/state | 1 + cdist/conf/type/__package_zypper/gencode-remote | 13 ++----------- .../type/__package_zypper/parameter/default/state | 1 + cdist/conf/type/__user_groups/gencode-remote | 2 +- .../type/__user_groups/parameter/default/state | 1 + 19 files changed, 27 insertions(+), 54 deletions(-) create mode 100644 cdist/conf/type/__git/parameter/default/branch create mode 100644 cdist/conf/type/__git/parameter/default/group create mode 100644 cdist/conf/type/__git/parameter/default/mode create mode 100644 cdist/conf/type/__git/parameter/default/owner create mode 100644 cdist/conf/type/__git/parameter/default/state create mode 100644 cdist/conf/type/__jail/parameter/default/devfs-ruleset create mode 100644 cdist/conf/type/__jail/parameter/default/jailbase create mode 100644 cdist/conf/type/__jail/parameter/default/jaildir create mode 100644 cdist/conf/type/__package_yum/parameter/default/state create mode 100644 cdist/conf/type/__package_zypper/parameter/default/state create mode 100644 cdist/conf/type/__user_groups/parameter/default/state diff --git a/cdist/conf/type/__git/gencode-remote b/cdist/conf/type/__git/gencode-remote index d719a492..c4fc1ef2 100644 --- a/cdist/conf/type/__git/gencode-remote +++ b/cdist/conf/type/__git/gencode-remote @@ -23,22 +23,17 @@ state_is="$(cat "$__object/explorer/state")" owner_is="$(cat "$__object/explorer/owner")" group_is="$(cat "$__object/explorer/group")" -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" -branch=master -[ -f "$__object/parameter/branch" ] && branch="$(cat "$__object/parameter/branch")" +branch="$(cat "$__object/parameter/branch")" source="$(cat "$__object/parameter/source")" destination="/$__object_id" -owner="" -[ -f "$__object/parameter/owner" ] && owner="$(cat "$__object/parameter/owner")" -group="" -[ -f "$__object/parameter/group" ] && group="$(cat "$__object/parameter/group")" -mode="" -[ -f "$__object/parameter/mode" ] && mode="$(cat "$__object/parameter/mode")" +owner="$(cat "$__object/parameter/owner")" +group="$(cat "$__object/parameter/group")" +mode="$(cat "$__object/parameter/mode")" [ "$state_should" = "$state_is" -a \ "$owner" = "$owner_is" -a \ diff --git a/cdist/conf/type/__git/manifest b/cdist/conf/type/__git/manifest index 8d6a29e4..7f6fee84 100644 --- a/cdist/conf/type/__git/manifest +++ b/cdist/conf/type/__git/manifest @@ -23,8 +23,7 @@ __package git --state present -state_should=present -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" # Let __directory handle removal of git repos diff --git a/cdist/conf/type/__git/parameter/default/branch b/cdist/conf/type/__git/parameter/default/branch new file mode 100644 index 00000000..1f7391f9 --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/branch @@ -0,0 +1 @@ +master diff --git a/cdist/conf/type/__git/parameter/default/group b/cdist/conf/type/__git/parameter/default/group new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/group @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__git/parameter/default/mode b/cdist/conf/type/__git/parameter/default/mode new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/mode @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__git/parameter/default/owner b/cdist/conf/type/__git/parameter/default/owner new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/owner @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__git/parameter/default/state b/cdist/conf/type/__git/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__git/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__jail/gencode-local b/cdist/conf/type/__jail/gencode-local index d6384156..08c7b7bf 100755 --- a/cdist/conf/type/__jail/gencode-local +++ b/cdist/conf/type/__jail/gencode-local @@ -22,17 +22,9 @@ # virtual machines. # -if [ -f "$__object/parameter/jaildir" ]; then - jaildir="$(cat "$__object/parameter/jaildir")" -else - jaildir="/usr/jail" -fi +jaildir="$(cat "$__object/parameter/jaildir")" -if [ -f "$__object/parameter/jailbase" ]; then - jailbase="$(cat "$__object/parameter/jailbase")" -else - jailbase="" -fi +jailbase="$(cat "$__object/parameter/jailbase")" state="$(cat "$__object/parameter/state")" diff --git a/cdist/conf/type/__jail/gencode-remote b/cdist/conf/type/__jail/gencode-remote index afbb81a5..141c8150 100755 --- a/cdist/conf/type/__jail/gencode-remote +++ b/cdist/conf/type/__jail/gencode-remote @@ -66,11 +66,7 @@ else devfsenable="true" fi -if [ -f "$__object/parameter/devfs-ruleset" ]; then - devfsruleset="$(cat "$__object/parameter/devfs-ruleset")" -else - devfsruleset="jailrules" -fi +devfsruleset="$(cat "$__object/parameter/devfs-ruleset")" # devfs_ruleset being defined without devfs_enable being true # is pointless. Treat this as an error. @@ -84,14 +80,11 @@ if [ -f "$__object/parameter/onboot" ]; then onboot="true" fi -if [ -f "$__object/parameter/jaildir" ]; then - jaildir="$(cat "$__object/parameter/jaildir")" -else - jaildir="/usr/jail" -fi +jaildir="$(cat "$__object/parameter/jaildir")" present="$(cat "$__object/explorer/present")" status="$(cat "$__object/explorer/status")" + # Handle ip="iface|addr, iface|addr" format 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 diff --git a/cdist/conf/type/__jail/manifest b/cdist/conf/type/__jail/manifest index cf5b7938..6a953241 100755 --- a/cdist/conf/type/__jail/manifest +++ b/cdist/conf/type/__jail/manifest @@ -33,11 +33,7 @@ if [ ! "$os" = "freebsd" ]; then exit 1 fi -if [ -f "$__object/parameter/jaildir" ]; then - jaildir="$(cat "$__object/parameter/jaildir")" -else - jaildir="/usr/jail" -fi +jaildir="$(cat "$__object/parameter/jaildir")" __directory ${jaildir} --parents diff --git a/cdist/conf/type/__jail/parameter/default/devfs-ruleset b/cdist/conf/type/__jail/parameter/default/devfs-ruleset new file mode 100644 index 00000000..f602aa0a --- /dev/null +++ b/cdist/conf/type/__jail/parameter/default/devfs-ruleset @@ -0,0 +1 @@ +jailrules diff --git a/cdist/conf/type/__jail/parameter/default/jailbase b/cdist/conf/type/__jail/parameter/default/jailbase new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/cdist/conf/type/__jail/parameter/default/jailbase @@ -0,0 +1 @@ + diff --git a/cdist/conf/type/__jail/parameter/default/jaildir b/cdist/conf/type/__jail/parameter/default/jaildir new file mode 100644 index 00000000..ec7d86c6 --- /dev/null +++ b/cdist/conf/type/__jail/parameter/default/jaildir @@ -0,0 +1 @@ +/usr/jail diff --git a/cdist/conf/type/__package_yum/gencode-remote b/cdist/conf/type/__package_yum/gencode-remote index 9c98c257..5f0e8ac8 100755 --- a/cdist/conf/type/__package_yum/gencode-remote +++ b/cdist/conf/type/__package_yum/gencode-remote @@ -27,11 +27,7 @@ else name="$__object_id" fi -if [ -f "$__object/parameter/state" ]; then - state_should="$(cat "$__object/parameter/state")" -else - state_should="present" -fi +state_should="$(cat "$__object/parameter/state")" if grep -q -E "(centos|redhat|amazon)" "$__global/explorer/os"; then opts="-y --quiet" diff --git a/cdist/conf/type/__package_yum/parameter/default/state b/cdist/conf/type/__package_yum/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__package_yum/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__package_zypper/gencode-remote b/cdist/conf/type/__package_zypper/gencode-remote index 51713590..d9f16f8d 100644 --- a/cdist/conf/type/__package_zypper/gencode-remote +++ b/cdist/conf/type/__package_zypper/gencode-remote @@ -34,17 +34,8 @@ else name="$__object_id" fi -if [ -f "$__object/parameter/state" ]; then - state_should="$(cat "$__object/parameter/state")" -else - state_should="present" -fi - -if [ -f "$__object/parameter/ptype" ]; then - ptype="$(cat "$__object/parameter/ptype")" -else - ptype="package" -fi +state_should="$(cat "$__object/parameter/state")" +ptype="$(cat "$__object/parameter/ptype")" if [ -f "$__object/parameter/version" ]; then version_should="$(cat "$__object/parameter/version")" diff --git a/cdist/conf/type/__package_zypper/parameter/default/state b/cdist/conf/type/__package_zypper/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__package_zypper/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__user_groups/gencode-remote b/cdist/conf/type/__user_groups/gencode-remote index c5e4a35e..9f11dd16 100755 --- a/cdist/conf/type/__user_groups/gencode-remote +++ b/cdist/conf/type/__user_groups/gencode-remote @@ -19,7 +19,7 @@ # user="$(cat "$__object/parameter/user" 2>/dev/null || echo "$__object_id")" -state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")" +state_should="$(cat "$__object/parameter/state")" mkdir "$__object/files" # file has to be sorted for comparison with `comm` diff --git a/cdist/conf/type/__user_groups/parameter/default/state b/cdist/conf/type/__user_groups/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__user_groups/parameter/default/state @@ -0,0 +1 @@ +present From 03ce5a28286eaf1c7bb876b0a11b51280ad6357c Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Tue, 4 Feb 2014 12:24:10 +0100 Subject: [PATCH 503/548] import __apt_* types from private repo Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_key/explorer/state | 32 +++++++++ cdist/conf/type/__apt_key/gencode-remote | 42 +++++++++++ cdist/conf/type/__apt_key/man.text | 60 ++++++++++++++++ .../__apt_key/parameter/default/keyserver | 1 + .../type/__apt_key/parameter/default/state | 1 + cdist/conf/type/__apt_key/parameter/optional | 3 + cdist/conf/type/__apt_key_uri/explorer/state | 32 +++++++++ cdist/conf/type/__apt_key_uri/gencode-remote | 45 ++++++++++++ cdist/conf/type/__apt_key_uri/man.text | 51 ++++++++++++++ cdist/conf/type/__apt_key_uri/manifest | 21 ++++++ .../__apt_key_uri/parameter/default/state | 1 + .../type/__apt_key_uri/parameter/optional | 2 + .../type/__apt_key_uri/parameter/required | 1 + cdist/conf/type/__apt_norecommends/man.text | 42 +++++++++++ cdist/conf/type/__apt_norecommends/manifest | 40 +++++++++++ cdist/conf/type/__apt_norecommends/singleton | 0 .../__apt_source/files/source.list.template | 15 ++++ cdist/conf/type/__apt_source/man.text | 69 +++++++++++++++++++ cdist/conf/type/__apt_source/manifest | 58 ++++++++++++++++ .../conf/type/__apt_source/parameter/boolean | 1 + .../type/__apt_source/parameter/default/state | 1 + .../conf/type/__apt_source/parameter/optional | 4 ++ .../conf/type/__apt_source/parameter/required | 1 + 23 files changed, 523 insertions(+) create mode 100755 cdist/conf/type/__apt_key/explorer/state create mode 100755 cdist/conf/type/__apt_key/gencode-remote create mode 100644 cdist/conf/type/__apt_key/man.text create mode 100644 cdist/conf/type/__apt_key/parameter/default/keyserver create mode 100644 cdist/conf/type/__apt_key/parameter/default/state create mode 100644 cdist/conf/type/__apt_key/parameter/optional create mode 100755 cdist/conf/type/__apt_key_uri/explorer/state create mode 100755 cdist/conf/type/__apt_key_uri/gencode-remote create mode 100644 cdist/conf/type/__apt_key_uri/man.text create mode 100755 cdist/conf/type/__apt_key_uri/manifest create mode 100644 cdist/conf/type/__apt_key_uri/parameter/default/state create mode 100644 cdist/conf/type/__apt_key_uri/parameter/optional create mode 100644 cdist/conf/type/__apt_key_uri/parameter/required create mode 100644 cdist/conf/type/__apt_norecommends/man.text create mode 100755 cdist/conf/type/__apt_norecommends/manifest create mode 100644 cdist/conf/type/__apt_norecommends/singleton create mode 100755 cdist/conf/type/__apt_source/files/source.list.template create mode 100644 cdist/conf/type/__apt_source/man.text create mode 100755 cdist/conf/type/__apt_source/manifest create mode 100644 cdist/conf/type/__apt_source/parameter/boolean create mode 100644 cdist/conf/type/__apt_source/parameter/default/state create mode 100644 cdist/conf/type/__apt_source/parameter/optional create mode 100644 cdist/conf/type/__apt_source/parameter/required diff --git a/cdist/conf/type/__apt_key/explorer/state b/cdist/conf/type/__apt_key/explorer/state new file mode 100755 index 00000000..f7940741 --- /dev/null +++ b/cdist/conf/type/__apt_key/explorer/state @@ -0,0 +1,32 @@ +#!/bin/sh +# +# 2011-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 state of the apt key. +# + +if [ -f "$__object/parameter/keyid" ]; then + keyid="$(cat "$__object/parameter/keyid")" +else + keyid="$__object_id" +fi + +apt-key export "$keyid" | head -n 1 | grep -Fqe "BEGIN PGP PUBLIC KEY BLOCK" \ + && echo present \ + || echo absent diff --git a/cdist/conf/type/__apt_key/gencode-remote b/cdist/conf/type/__apt_key/gencode-remote new file mode 100755 index 00000000..c6ead91c --- /dev/null +++ b/cdist/conf/type/__apt_key/gencode-remote @@ -0,0 +1,42 @@ +#!/bin/sh +# +# 2011-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 . +# + +if [ -f "$__object/parameter/keyid" ]; then + keyid="$(cat "$__object/parameter/keyid")" +else + keyid="$__object_id" +fi +state_should="$(cat "$__object/parameter/state")" +state_is="$(cat "$__object/explorer/state")" + +if [ "$state_should" = "$state_is" ]; then + # nothing to do + exit 0 +fi + +case "$state_should" in + present) + keyserver="$(cat "$__object/parameter/keyserver")" + echo "apt-key adv --keyserver \"$keyserver\" --recv-keys \"$keyid\"" + ;; + absent) + echo "apt-key del \"$keyid\"" + ;; +esac diff --git a/cdist/conf/type/__apt_key/man.text b/cdist/conf/type/__apt_key/man.text new file mode 100644 index 00000000..d571a633 --- /dev/null +++ b/cdist/conf/type/__apt_key/man.text @@ -0,0 +1,60 @@ +cdist-type__apt_key(7) +====================== +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. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent'. Defaults to 'present' + +keyid:: + the id of the key to add. Defaults to __object_id + +keyserver:: + the keyserver from which to fetch the key. If omitted a sane default is used. + + +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 + +# 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) + + +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). diff --git a/cdist/conf/type/__apt_key/parameter/default/keyserver b/cdist/conf/type/__apt_key/parameter/default/keyserver new file mode 100644 index 00000000..f851282c --- /dev/null +++ b/cdist/conf/type/__apt_key/parameter/default/keyserver @@ -0,0 +1 @@ +subkeys.pgp.net diff --git a/cdist/conf/type/__apt_key/parameter/default/state b/cdist/conf/type/__apt_key/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__apt_key/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__apt_key/parameter/optional b/cdist/conf/type/__apt_key/parameter/optional new file mode 100644 index 00000000..18cf2586 --- /dev/null +++ b/cdist/conf/type/__apt_key/parameter/optional @@ -0,0 +1,3 @@ +state +keyid +keyserver diff --git a/cdist/conf/type/__apt_key_uri/explorer/state b/cdist/conf/type/__apt_key_uri/explorer/state new file mode 100755 index 00000000..15d6e653 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/explorer/state @@ -0,0 +1,32 @@ +#!/bin/sh +# +# 2011-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 state of the apt key. +# + +if [ -f "$__object/parameter/name" ]; then + name="$(cat "$__object/parameter/name")" +else + name="$__object_id" +fi + +apt-key list | grep -Fqe "$name" \ + && echo present \ + || echo absent diff --git a/cdist/conf/type/__apt_key_uri/gencode-remote b/cdist/conf/type/__apt_key_uri/gencode-remote new file mode 100755 index 00000000..07af92ac --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/gencode-remote @@ -0,0 +1,45 @@ +#!/bin/sh +# +# 2011-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 . +# + +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")" + +if [ "$state_should" = "$state_is" ]; then + # nothing to do + exit 0 +fi + +case "$state_should" in + present) + uri="$(cat "$__object/parameter/uri")" + echo "wget -q \"$uri\" -O - | apt-key add -" + ;; + absent) + cat << DONE +keyid=\$(apt-key list | grep -B1 "$name" | awk '/pub/ { print \$2 }' | cut -d'/' -f 2) +apt-key del \$keyid +DONE + ;; +esac diff --git a/cdist/conf/type/__apt_key_uri/man.text b/cdist/conf/type/__apt_key_uri/man.text new file mode 100644 index 00000000..fe9c3a25 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/man.text @@ -0,0 +1,51 @@ +cdist-type__apt_key_uri(7) +========================== +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. + + +REQUIRED PARAMETERS +------------------- +uri:: + the uri from which to download the key + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to 'present' + +name:: + a name for this key, used when testing if it is already installed. + Defaults to __object_id + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__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) + + +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). diff --git a/cdist/conf/type/__apt_key_uri/manifest b/cdist/conf/type/__apt_key_uri/manifest new file mode 100755 index 00000000..5dae37a7 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/manifest @@ -0,0 +1,21 @@ +#!/bin/sh +# +# 2013-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 . +# + +__package wget diff --git a/cdist/conf/type/__apt_key_uri/parameter/default/state b/cdist/conf/type/__apt_key_uri/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__apt_key_uri/parameter/optional b/cdist/conf/type/__apt_key_uri/parameter/optional new file mode 100644 index 00000000..72c84b88 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/parameter/optional @@ -0,0 +1,2 @@ +state +name diff --git a/cdist/conf/type/__apt_key_uri/parameter/required b/cdist/conf/type/__apt_key_uri/parameter/required new file mode 100644 index 00000000..c7954952 --- /dev/null +++ b/cdist/conf/type/__apt_key_uri/parameter/required @@ -0,0 +1 @@ +uri diff --git a/cdist/conf/type/__apt_norecommends/man.text b/cdist/conf/type/__apt_norecommends/man.text new file mode 100644 index 00000000..3b65e72f --- /dev/null +++ b/cdist/conf/type/__apt_norecommends/man.text @@ -0,0 +1,42 @@ +cdist-type__apt_norecommends(7) +=============================== +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. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +None. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__apt_norecommends +-------------------------------------------------------------------------------- + + +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/__apt_norecommends/manifest b/cdist/conf/type/__apt_norecommends/manifest new file mode 100755 index 00000000..8058d52e --- /dev/null +++ b/cdist/conf/type/__apt_norecommends/manifest @@ -0,0 +1,40 @@ +#!/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 + ubuntu|debian) + # 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 \ + --owner root --group root --mode 644 \ + --source - << DONE +APT::Install-Recommends "0"; +APT::Install-Suggests "0"; +DONE + ;; + *) + echo "This type (${__type##*/}) makes no sense on your operating system ($os)." >&2 + echo "If you think otherwise please submit a patch." >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__apt_norecommends/singleton b/cdist/conf/type/__apt_norecommends/singleton new file mode 100644 index 00000000..e69de29b diff --git a/cdist/conf/type/__apt_source/files/source.list.template b/cdist/conf/type/__apt_source/files/source.list.template new file mode 100755 index 00000000..d4420e96 --- /dev/null +++ b/cdist/conf/type/__apt_source/files/source.list.template @@ -0,0 +1,15 @@ +#!/bin/sh +set -u + +entry="$uri $distribution $component" +cat << DONE +# Created by cdist ${__type##*/} +# Do not change. Changes will be overwritten. +# + +# $name +deb ${forcedarch} $entry +DONE +if [ -f "$__object/parameter/include-src" ]; then + echo "deb-src $entry" +fi diff --git a/cdist/conf/type/__apt_source/man.text b/cdist/conf/type/__apt_source/man.text new file mode 100644 index 00000000..fe40a91e --- /dev/null +++ b/cdist/conf/type/__apt_source/man.text @@ -0,0 +1,69 @@ +cdist-type__apt_source(7) +========================= +Steven Armstrong + + +NAME +---- +cdist-type__apt_source - manage apt sources + + +DESCRIPTION +----------- +This cdist type allows you to manage apt sources. + + +REQUIRED PARAMETERS +------------------- +uri:: + the uri to the apt repository + + +OPTIONAL PARAMETERS +------------------- +arch:: + set this if you need to force and specific arch (ubuntu specific) + +state:: + 'present' or 'absent', defaults to 'present' + +distribution:: + the distribution codename to use. Defaults to DISTRIB_CODENAME from + the targets /etc/lsb-release + +component:: + space delimited list of components to enable. Defaults to 'main'. + + +BOOLEAN PARAMETERS +------------------ +include-src:: + include deb-src entries + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__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) + + +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). diff --git a/cdist/conf/type/__apt_source/manifest b/cdist/conf/type/__apt_source/manifest new file mode 100755 index 00000000..b4d72a71 --- /dev/null +++ b/cdist/conf/type/__apt_source/manifest @@ -0,0 +1,58 @@ +#!/bin/sh +# +# 2011-2013 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" +state="$(cat "$__object/parameter/state")" +uri="$(cat "$__object/parameter/uri")" + +if [ -f "$__object/parameter/distribution" ]; then + distribution="$(cat "$__object/parameter/distribution")" +else + distribution="$(cat "$__global/explorer/lsb_codename")" +fi +if [ -f "$__object/parameter/component" ]; then + component="$(cat "$__object/parameter/component")" +else + # FIXME: nead to omit this for http://stat.ethz.ch/CRAN//bin/linux/ubuntu, investigate side-effects + #component="main" + component="" +fi +if [ -f "$__object/parameter/arch" ]; then + forcedarch="[arch=$(cat "$__object/parameter/arch")]" +else + forcedarch="" +fi + +# export variables for use in template +export name +export uri +export distribution +export component +export forcedarch + +# generate file from template +mkdir "$__object/files" +"$__type/files/source.list.template" > "$__object/files/source.list" +__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 diff --git a/cdist/conf/type/__apt_source/parameter/boolean b/cdist/conf/type/__apt_source/parameter/boolean new file mode 100644 index 00000000..8fa49177 --- /dev/null +++ b/cdist/conf/type/__apt_source/parameter/boolean @@ -0,0 +1 @@ +include-src diff --git a/cdist/conf/type/__apt_source/parameter/default/state b/cdist/conf/type/__apt_source/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__apt_source/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__apt_source/parameter/optional b/cdist/conf/type/__apt_source/parameter/optional new file mode 100644 index 00000000..87537335 --- /dev/null +++ b/cdist/conf/type/__apt_source/parameter/optional @@ -0,0 +1,4 @@ +state +distribution +component +arch \ No newline at end of file diff --git a/cdist/conf/type/__apt_source/parameter/required b/cdist/conf/type/__apt_source/parameter/required new file mode 100644 index 00000000..c7954952 --- /dev/null +++ b/cdist/conf/type/__apt_source/parameter/required @@ -0,0 +1 @@ +uri From 2363cdda47289fbefbcb9647af549829ddbc28d0 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Feb 2014 20:50:23 +0100 Subject: [PATCH 504/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index bd52bd78..f638f2a5 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,6 +6,7 @@ Changelog 3.0.5: * Core: Introduce override concept (Daniel Heule) + * Type __process: Make --state absent work (Steven Armstrong) 3.0.4: 2014-01-29 From d1cc8a69999cafbce9dc91cbb81399c0f324abf5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Feb 2014 20:50:59 +0100 Subject: [PATCH 505/548] document environment variables that influence cdist Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 5c9f603c..4b1906b4 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -188,8 +188,10 @@ stdin:: when the type was called. -ENVIRONMENT VARIABLES ---------------------- +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 @@ -227,6 +229,12 @@ __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: + +CDIST_ALLOW_OVERRIDE:: + Allow overwriting type parameters (see cdist-manifest(7)) SEE ALSO -------- From 65b3f6c75ab7c28c725c741c403682cfb15e86f1 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Feb 2014 20:52:35 +0100 Subject: [PATCH 506/548] also document require variable Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 4b1906b4..5de59eab 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -233,6 +233,9 @@ ENVIRONMENT VARIABLES (FOR WRITING) ----------------------------------- The following environment variables influence the behaviour of cdist: +require:: + Setup dependencies between objects (see cdist-manifest(7)) + CDIST_ALLOW_OVERRIDE:: Allow overwriting type parameters (see cdist-manifest(7)) From f928072f746ed12125b20acd87251852e4366d86 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 5 Feb 2014 21:07:33 +0100 Subject: [PATCH 507/548] let the user decide what is sane and what not Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_key/man.text | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cdist/conf/type/__apt_key/man.text b/cdist/conf/type/__apt_key/man.text index d571a633..1a33e732 100644 --- a/cdist/conf/type/__apt_key/man.text +++ b/cdist/conf/type/__apt_key/man.text @@ -27,7 +27,8 @@ keyid:: the id of the key to add. Defaults to __object_id keyserver:: - the keyserver from which to fetch the key. If omitted a sane default is used. + the keyserver from which to fetch the key. If omitted the default set in + ./parameter/default/keyserver is used. EXAMPLES From 34f2f7f0389b32c1c46763eda556bd7c98abcbff Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Feb 2014 21:09:24 +0100 Subject: [PATCH 508/548] setting up CDIST_ALLOW_OVERRIDE to any value is ok - do not depend on true/yes/ja Signed-off-by: Nico Schottelius --- cdist/emulator.py | 4 ++-- docs/changelog | 1 + docs/man/man7/cdist-manifest.text | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index ed846e6d..4f91cd8e 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -145,14 +145,14 @@ class Emulator(object): if value is not None: self.parameters[key] = value - if self.cdist_object.exists and os.environ.get('CDIST_ALLOW_OVERRIDE',"false") != 'true': + if self.cdist_object.exists and not 'CDIST_ALLOW_OVERRIDE' in os.environ: 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) ) else: if self.cdist_object.exists: - self.log.debug('Object %s override forced with CDIST_ALLOW_OVERRIDE=true',self.cdist_object.name) + self.log.debug('Object %s override forced with CDIST_ALLOW_OVERRIDE',self.cdist_object.name) self.cdist_object.create(True) else: self.cdist_object.create() diff --git a/docs/changelog b/docs/changelog index f638f2a5..14e34b3d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.0.5: * Core: Introduce override concept (Daniel Heule) * Type __process: Make --state absent work (Steven Armstrong) + * Documentation: Add documentation for influencing variables 3.0.4: 2014-01-29 diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index aa146267..7f1b95dc 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -133,8 +133,8 @@ 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 mark this second definition of an object with -CDIST_ALLOW_OVERRIDE=true to tell cdist, that this object override is +If you whish, you can setup the environment variable CDIST_ALLOW_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 encounter the affected objects, otherwhise this results @@ -190,7 +190,7 @@ __user foobar --password 'some_fancy_hash' --home /home/foobarexample __user foobar --password 'some_other_hash' # this tells cdist, that you know that this is an override and should be accepted -CDIST_ALLOW_OVERRIDE=true __user foobar --password 'some_other_hash' +CDIST_ALLOW_OVERRIDE=yes __user foobar --password 'some_other_hash' # its only an override, means the parameter --home is not touched # and stay at the original value of /home/foobarexample -------------------------------------------------------------------------------- From 14a112fcce283d38a43cd9a94575f61e68aa195a Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 5 Feb 2014 21:12:22 +0100 Subject: [PATCH 509/548] /wget/curl/ Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_key_uri/gencode-remote | 2 +- cdist/conf/type/__apt_key_uri/manifest | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__apt_key_uri/gencode-remote b/cdist/conf/type/__apt_key_uri/gencode-remote index 07af92ac..078b8695 100755 --- a/cdist/conf/type/__apt_key_uri/gencode-remote +++ b/cdist/conf/type/__apt_key_uri/gencode-remote @@ -34,7 +34,7 @@ fi case "$state_should" in present) uri="$(cat "$__object/parameter/uri")" - echo "wget -q \"$uri\" -O - | apt-key add -" + printf 'curl -s -L "%s" | apt-key add -\n' "$uri" ;; absent) cat << DONE diff --git a/cdist/conf/type/__apt_key_uri/manifest b/cdist/conf/type/__apt_key_uri/manifest index 5dae37a7..8dddde56 100755 --- a/cdist/conf/type/__apt_key_uri/manifest +++ b/cdist/conf/type/__apt_key_uri/manifest @@ -18,4 +18,4 @@ # along with cdist. If not, see . # -__package wget +__package curl From 7686a5ac5e14f4368b81a7d00b7dc5b46f21ae10 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 5 Feb 2014 21:17:15 +0100 Subject: [PATCH 510/548] be nice to them users Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_norecommends/manifest | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cdist/conf/type/__apt_norecommends/manifest b/cdist/conf/type/__apt_norecommends/manifest index 8058d52e..881c2427 100755 --- a/cdist/conf/type/__apt_norecommends/manifest +++ b/cdist/conf/type/__apt_norecommends/manifest @@ -33,8 +33,10 @@ APT::Install-Suggests "0"; DONE ;; *) - echo "This type (${__type##*/}) makes no sense on your operating system ($os)." >&2 - echo "If you think otherwise please submit a patch." >&2 + 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 From 6f0459f3c57607bb4b37ca6ae579f54ffd83c419 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Wed, 5 Feb 2014 21:18:47 +0100 Subject: [PATCH 511/548] remove legacy FIXME Signed-off-by: Steven Armstrong --- cdist/conf/type/__apt_source/man.text | 2 +- cdist/conf/type/__apt_source/manifest | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cdist/conf/type/__apt_source/man.text b/cdist/conf/type/__apt_source/man.text index fe40a91e..03b2b311 100644 --- a/cdist/conf/type/__apt_source/man.text +++ b/cdist/conf/type/__apt_source/man.text @@ -32,7 +32,7 @@ distribution:: the targets /etc/lsb-release component:: - space delimited list of components to enable. Defaults to 'main'. + space delimited list of components to enable. Defaults to an empty string. BOOLEAN PARAMETERS diff --git a/cdist/conf/type/__apt_source/manifest b/cdist/conf/type/__apt_source/manifest index b4d72a71..0e782716 100755 --- a/cdist/conf/type/__apt_source/manifest +++ b/cdist/conf/type/__apt_source/manifest @@ -30,8 +30,6 @@ fi if [ -f "$__object/parameter/component" ]; then component="$(cat "$__object/parameter/component")" else - # FIXME: nead to omit this for http://stat.ethz.ch/CRAN//bin/linux/ubuntu, investigate side-effects - #component="main" component="" fi if [ -f "$__object/parameter/arch" ]; then From c663d87ba6e8db478b86478193b48364dc349428 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Feb 2014 22:53:45 +0100 Subject: [PATCH 512/548] release 3.0.5 Signed-off-by: Nico Schottelius --- docs/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 14e34b3d..5ce2e288 100644 --- a/docs/changelog +++ b/docs/changelog @@ -4,10 +4,11 @@ Changelog * Changes are always commented with their author in (braces) * Exception: No braces means author == Nico Schottelius -3.0.5: + +3.0.5: 2014-02-05 * Core: Introduce override concept (Daniel Heule) * Type __process: Make --state absent work (Steven Armstrong) - * Documentation: Add documentation for influencing variables + * Documentation: Update documentation for environment variables 3.0.4: 2014-01-29 From 2e6a8275130a1cb7657c0ed21b8651776e1006b6 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 5 Feb 2014 23:15:56 +0100 Subject: [PATCH 513/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/changelog b/docs/changelog index 5ce2e288..9c222384 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,13 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.0.6: + * New Type: __apt_key (Steven Armstrong) + * New Type: __apt_key_uri (Steven Armstrong) + * New Type: __apt_norecommends (Steven Armstrong) + * New Type: __apt_source (Steven Armstrong) + + 3.0.5: 2014-02-05 * Core: Introduce override concept (Daniel Heule) * Type __process: Make --state absent work (Steven Armstrong) From 294285c164fdb212ea2fc6277c97fc877e889cb2 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Feb 2014 00:08:40 +0100 Subject: [PATCH 514/548] import __ccollect_source type Signed-off-by: Nico Schottelius --- .../type/__ccollect_source/explorer/cksum | 34 +++++++ .../conf/type/__ccollect_source/explorer/stat | 47 ++++++++++ .../conf/type/__ccollect_source/explorer/type | 33 +++++++ .../type/__ccollect_source/gencode-remote | 93 +++++++++++++++++++ cdist/conf/type/__ccollect_source/man.text | 64 +++++++++++++ cdist/conf/type/__ccollect_source/manifest | 53 +++++++++++ .../type/__ccollect_source/parameter/boolean | 1 + .../parameter/default/ccollectconf | 1 + .../__ccollect_source/parameter/default/state | 1 + .../type/__ccollect_source/parameter/optional | 2 + .../parameter/optional_multiple | 1 + .../type/__ccollect_source/parameter/required | 2 + 12 files changed, 332 insertions(+) create mode 100755 cdist/conf/type/__ccollect_source/explorer/cksum create mode 100755 cdist/conf/type/__ccollect_source/explorer/stat create mode 100755 cdist/conf/type/__ccollect_source/explorer/type create mode 100755 cdist/conf/type/__ccollect_source/gencode-remote create mode 100644 cdist/conf/type/__ccollect_source/man.text create mode 100755 cdist/conf/type/__ccollect_source/manifest create mode 100644 cdist/conf/type/__ccollect_source/parameter/boolean create mode 100644 cdist/conf/type/__ccollect_source/parameter/default/ccollectconf create mode 100644 cdist/conf/type/__ccollect_source/parameter/default/state create mode 100644 cdist/conf/type/__ccollect_source/parameter/optional create mode 100644 cdist/conf/type/__ccollect_source/parameter/optional_multiple create mode 100644 cdist/conf/type/__ccollect_source/parameter/required diff --git a/cdist/conf/type/__ccollect_source/explorer/cksum b/cdist/conf/type/__ccollect_source/explorer/cksum new file mode 100755 index 00000000..335e4e7a --- /dev/null +++ b/cdist/conf/type/__ccollect_source/explorer/cksum @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 2011-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 . +# +# +# Retrieve the md5sum of a file to be created, if it is already existing. +# + +destination="/$__object_id" + +if [ -e "$destination" ]; then + if [ -f "$destination" ]; then + cksum < "$destination" + else + echo "NO REGULAR FILE" + fi +else + echo "NO FILE FOUND, NO CHECKSUM CALCULATED." +fi diff --git a/cdist/conf/type/__ccollect_source/explorer/stat b/cdist/conf/type/__ccollect_source/explorer/stat new file mode 100755 index 00000000..298221b7 --- /dev/null +++ b/cdist/conf/type/__ccollect_source/explorer/stat @@ -0,0 +1,47 @@ +#!/bin/sh +# +# 2013 Steven Armstrong (steven-cdist 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 . +# + +destination="/$__object_id" + +# nothing to work with, nothing we could do +[ -e "$destination" ] || exit 0 + +os=$("$__explorer/os") +case "$os" in + "freebsd") + # 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" + ;; + *) + stat --printf="type: %F +owner: %u %U +group: %g %G +mode: %a %A +size: %s +links: %h +" "$destination" + ;; +esac diff --git a/cdist/conf/type/__ccollect_source/explorer/type b/cdist/conf/type/__ccollect_source/explorer/type new file mode 100755 index 00000000..e723047c --- /dev/null +++ b/cdist/conf/type/__ccollect_source/explorer/type @@ -0,0 +1,33 @@ +#!/bin/sh +# +# 2013 Steven Armstrong (steven-cdist 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 . +# + +destination="/$__object_id" + +if [ ! -e "$destination" ]; then + echo none +elif [ -h "$destination" ]; then + echo symlink +elif [ -f "$destination" ]; then + echo file +elif [ -d "$destination" ]; then + echo directory +else + echo unknown +fi diff --git a/cdist/conf/type/__ccollect_source/gencode-remote b/cdist/conf/type/__ccollect_source/gencode-remote new file mode 100755 index 00000000..c41b5179 --- /dev/null +++ b/cdist/conf/type/__ccollect_source/gencode-remote @@ -0,0 +1,93 @@ +#!/bin/sh +# +# 2014 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" +state_should="$(cat "$__object/parameter/state")" +type="$(cat "$__object/explorer/type")" +stat_file="$__object/explorer/stat" + + +get_current_value() { + if [ -s "$stat_file" ]; then + _name="$1" + _value="$2" + case "$_value" in + [0-9]*) + _index=2 + ;; + *) + _index=3 + ;; + esac + awk '/'"$_name"':/ { print $'$_index' }' "$stat_file" + unset _name _value _index + fi +} + +set_group() { + echo chgrp \"$1\" \"$destination\" + echo chgrp $1 >> "$__messages_out" +} + +set_owner() { + echo chown \"$1\" \"$destination\" + echo chown $1 >> "$__messages_out" +} + +set_mode() { + echo chmod \"$1\" \"$destination\" + 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 + # clearing S_ISUID and S_ISGID bits (see chown(2)) + for attribute in group owner mode; do + if [ -f "$__object/parameter/$attribute" ]; then + value_should="$(cat "$__object/parameter/$attribute")" + + # change 0xxx format to xxx format => same as stat returns + if [ "$attribute" = mode ]; then + value_should="$(echo $value_should | sed 's/^0\(...\)/\1/')" + fi + + value_is="$(get_current_value "$attribute" "$value_should")" + if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then + "set_$attribute" "$value_should" + fi + fi + done + + ;; + + absent) + if [ "$type" = "file" ]; then + echo rm -f \"$destination\" + echo remove >> "$__messages_out" + fi + ;; + + *) + echo "Unknown state: $state_should" >&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__ccollect_source/man.text b/cdist/conf/type/__ccollect_source/man.text new file mode 100644 index 00000000..32a7467e --- /dev/null +++ b/cdist/conf/type/__ccollect_source/man.text @@ -0,0 +1,64 @@ +cdist-type__ccollect_source(7) +============================== +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:: + The source from which to backup +destination:: + The destination directory + + +OPTIONAL PARAMETERS +------------------- +state:: + 'present' or 'absent', defaults to 'present' +ccollectconf:: + The CCOLLECT_CONF directory. Defaults to /etc/ccollect. + + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- +exclude:: + Paths to exclude of backup + +BOOLEAN PARAMETERS +------------------ +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 + +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- ccollect(1) +- http://www.nico.schottelius.org/software/ccollect/ + + +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). diff --git a/cdist/conf/type/__ccollect_source/manifest b/cdist/conf/type/__ccollect_source/manifest new file mode 100755 index 00000000..89c2ef2b --- /dev/null +++ b/cdist/conf/type/__ccollect_source/manifest @@ -0,0 +1,53 @@ +#!/bin/sh +# +# 2014 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 . +# + +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,/$,,')" + +sourcedir="$ccollectconf/sources" +basedir="$sourcedir/$name" + +destination_file="$basedir/destination" +source_file="$basedir/source" +exclude_file="$basedir/exclude" +verbose_file="$basedir/verbose" + +__directory "$basedir" --state "$state" + +export require="__directory$basedir" +echo "$destination" | __file "$destination_file" --source - --state "$state" +echo "$source" | __file "$source_file" --source - --state "$state" + +################################################################################ +# Booleans +if [ -f "$__object/parameter/verbose" ]; then + verbosestate="present" +else + verbosestate="absent" +fi +__file "$verbose_file" --state "$verbosestate" + +if [ -f "$__object/parameter/exclude" ]; then + __file "$exclude_file" --source - --state "$state" \ + < "$__object/parameter/exclude" +fi diff --git a/cdist/conf/type/__ccollect_source/parameter/boolean b/cdist/conf/type/__ccollect_source/parameter/boolean new file mode 100644 index 00000000..c00ee94a --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/boolean @@ -0,0 +1 @@ +verbose diff --git a/cdist/conf/type/__ccollect_source/parameter/default/ccollectconf b/cdist/conf/type/__ccollect_source/parameter/default/ccollectconf new file mode 100644 index 00000000..a9fda009 --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/default/ccollectconf @@ -0,0 +1 @@ +/etc/ccollect diff --git a/cdist/conf/type/__ccollect_source/parameter/default/state b/cdist/conf/type/__ccollect_source/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__ccollect_source/parameter/optional b/cdist/conf/type/__ccollect_source/parameter/optional new file mode 100644 index 00000000..0249d11e --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/optional @@ -0,0 +1,2 @@ +ccollectconf +state diff --git a/cdist/conf/type/__ccollect_source/parameter/optional_multiple b/cdist/conf/type/__ccollect_source/parameter/optional_multiple new file mode 100644 index 00000000..9ba870ea --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/optional_multiple @@ -0,0 +1 @@ +exclude diff --git a/cdist/conf/type/__ccollect_source/parameter/required b/cdist/conf/type/__ccollect_source/parameter/required new file mode 100644 index 00000000..9239646e --- /dev/null +++ b/cdist/conf/type/__ccollect_source/parameter/required @@ -0,0 +1,2 @@ +source +destination From c1d2ceefc2ed2d294927f18335f47ab14ef6b154 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Feb 2014 00:10:02 +0100 Subject: [PATCH 515/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 9c222384..7d693496 100644 --- a/docs/changelog +++ b/docs/changelog @@ -10,6 +10,7 @@ Changelog * New Type: __apt_key_uri (Steven Armstrong) * New Type: __apt_norecommends (Steven Armstrong) * New Type: __apt_source (Steven Armstrong) + * New Type: __ccollect_source 3.0.5: 2014-02-05 From 98e7b7644cd9ae031b89c6ed604ac589e2adc0cd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Feb 2014 11:35:45 +0100 Subject: [PATCH 516/548] release 3.0.6 Signed-off-by: Nico Schottelius --- docs/changelog | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 7d693496..e07f14ff 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,12 +5,17 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.0.6: +3.0.6: 2014-02-06 * New Type: __apt_key (Steven Armstrong) * New Type: __apt_key_uri (Steven Armstrong) * New Type: __apt_norecommends (Steven Armstrong) * New Type: __apt_source (Steven Armstrong) * New Type: __ccollect_source + * Type __git: Use default parameters (Daniel Heule) + * Type __jail: Use default parameters (Daniel Heule) + * Type __package_yum: Use default parameters (Daniel Heule) + * Type __package_zypper: Use default parameters (Daniel Heule) + * Type __user_groups: Use default parameters (Daniel Heule) 3.0.5: 2014-02-05 From 51afca5336464dc65ed183bf83c21e718d167db0 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 6 Feb 2014 15:26:17 +0100 Subject: [PATCH 517/548] Implement lastest suggestions from nico, rename ENV Variable to CDIST_ORDER_DEPENDENCY --- cdist/emulator.py | 5 ++--- docs/man/man7/cdist-manifest.text | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 2c3c12a4..203c97e5 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -189,9 +189,8 @@ class Emulator(object): def record_requirements(self): """record requirements""" - #from pudb import set_trace; set_trace(); - if "EXECUTE_TYPES_IN_CREATION_ORDER" in self.env and self.env['EXECUTE_TYPES_IN_CREATION_ORDER'] == 'true': + if "CDIST_ORDER_DEPENDENCY" in self.env: # load object name created bevor this one from typeorder file ... with open(self.typeorder_path, 'r') as typecreationfile: typecreationorder = typecreationfile.readlines() @@ -202,7 +201,7 @@ class Emulator(object): self.env['require'] += " " + lastcreatedtype else: self.env['require'] = lastcreatedtype - self.log.debug("Injecting require for EXECUTE_TYPES_IN_CREATION_ORDER: %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 pass diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 8ae8f966..66a4cd2a 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -142,19 +142,19 @@ into an undefined situation. THIS IS A BETA FEATURE AND MAY BE REMOVED AT ANY TIME. -EXECUTE_TYPES_IN_CREATION_ORDER is a EXPERIMENTAL FEATURE ! +CDIST_ORDER_DEPENDENCY is a EXPERIMENTAL FEATURE ! You can tell cdist to execute all types in the order in which they are created -in the manifest by exporting EXECUTE_TYPES_IN_CREATION_ORDER with the value true. +in the manifest by exporting CDIST_ORDER_DEPENDENCY. -------------------------------------------------------------------------------- # Tells cdist to execute all types in the order in which they are created ... -export EXECUTE_TYPES_IN_CREATION_ORDER=true +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 EXECUTE_TYPES_IN_CREATION_ORDER +unset CDIST_ORDER_DEPENDENCY # all now following types cdist makes the order .. __not_in_order_type 42 From 724385fcf38a0ee94009250e434c02dc941530d4 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Feb 2014 15:55:41 +0100 Subject: [PATCH 518/548] update manifest document for in order execution Signed-off-by: Nico Schottelius --- docs/man/man7/cdist-manifest.text | 67 ++++++++++++++++++------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 66a4cd2a..fbdab849 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -128,6 +128,19 @@ 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. +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. +When cdist sees that this variable is setup, 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 IS A BETA FEATURE AND MAY BE REMOVED OR CHANGED AT ANY TIME. + + OVERRIDES --------- In some special cases, you would like to create an already defined object @@ -139,33 +152,7 @@ ATTENTION: Only use this feature if you are 100% sure in which order cdist encounter the affected objects, otherwhise this results into an undefined situation. -THIS IS A BETA FEATURE AND MAY BE REMOVED AT ANY TIME. - - -CDIST_ORDER_DEPENDENCY is a EXPERIMENTAL FEATURE ! -You can tell cdist to execute all types in the order in which they are created -in the manifest by exporting CDIST_ORDER_DEPENDENCY. - --------------------------------------------------------------------------------- - -# 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 - --------------------------------------------------------------------------------- +THIS IS A BETA FEATURE AND MAY BE REMOVED OR CHANGED AT ANY TIME. @@ -223,6 +210,30 @@ CDIST_ALLOW_OVERRIDE=yes __user foobar --password 'some_other_hash' # and stay at the original value of /home/foobarexample -------------------------------------------------------------------------------- +Dependencies defined by execution order work as following: + +-------------------------------------------------------------------------------- + +# 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 -------- @@ -232,5 +243,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2010-2012 Nico Schottelius. Free use of this software is +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). From 49764ae5c77953273e801b928bdb126b01320eec Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Feb 2014 15:58:25 +0100 Subject: [PATCH 519/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/changelog b/docs/changelog index e07f14ff..120d8e87 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.0.7: + * Core: Add support for in order execution (Daniel Heule) + 3.0.6: 2014-02-06 * New Type: __apt_key (Steven Armstrong) * New Type: __apt_key_uri (Steven Armstrong) @@ -17,13 +20,11 @@ Changelog * Type __package_zypper: Use default parameters (Daniel Heule) * Type __user_groups: Use default parameters (Daniel Heule) - 3.0.5: 2014-02-05 * Core: Introduce override concept (Daniel Heule) * Type __process: Make --state absent work (Steven Armstrong) * Documentation: Update documentation for environment variables - 3.0.4: 2014-01-29 * Core: Ignore install types in config mode * Documentation: Update reference (files path in object space) @@ -32,7 +33,6 @@ Changelog * Type __debconf_set_selections: Support --file - to read from stdin * Type __jail: Fix jaildir parameter handling (Jake Guffey) - 3.0.3: 2014-01-22 * Core: Enhance error message when requirement is missing object id * Core: Add environment variable to select shell for executing scripts (Daniel Heule) @@ -45,7 +45,6 @@ Changelog * Type __zypper_repo: Use default paremeters (Daniel Heule) * Type __zypper_service: Use default paremeters (Daniel Heule) - 3.0.2: 2014-01-19 * Documentation: Document all messages sent by types (Daniel Heule) * New Type: __block (Steven Armstrong) @@ -53,7 +52,6 @@ Changelog * Type __cron: Replace existing entry when changing it (Daniel Heule) * Type __ssh_authorized_keys: Use new type __block (Steven Armstrong) - 3.0.1: 2014-01-14 * Core: Copy only files, not directories (Steven Armstrong) * Core: Allow hostnames to start with / From 52e2017d8feedfd035838a6c186c119fa713cf88 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Thu, 6 Feb 2014 16:03:07 +0100 Subject: [PATCH 520/548] CDIST_ALLOW_OVERRIDE -> CDIST_OVERRIDE as requested by nico --- cdist/emulator.py | 4 ++-- docs/man/man7/cdist-manifest.text | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 4f91cd8e..1e8701cf 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -145,14 +145,14 @@ class Emulator(object): if value is not None: self.parameters[key] = value - if self.cdist_object.exists and not 'CDIST_ALLOW_OVERRIDE' in os.environ: + if self.cdist_object.exists and not 'CDIST_OVERRIDE' in os.environ: 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) ) else: if self.cdist_object.exists: - self.log.debug('Object %s override forced with CDIST_ALLOW_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() diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 7f1b95dc..cfbd8bea 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -133,7 +133,7 @@ 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_ALLOW_OVERRIDE +If you whish, 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 @@ -190,7 +190,7 @@ __user foobar --password 'some_fancy_hash' --home /home/foobarexample __user foobar --password 'some_other_hash' # this tells cdist, that you know that this is an override and should be accepted -CDIST_ALLOW_OVERRIDE=yes __user foobar --password 'some_other_hash' +CDIST_OVERRIDE=yes __user foobar --password 'some_other_hash' # its only an override, means the parameter --home is not touched # and stay at the original value of /home/foobarexample -------------------------------------------------------------------------------- From 2fa174f6ead4c4fb81af2b8618f9c668723f2789 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 6 Feb 2014 17:02:14 +0100 Subject: [PATCH 521/548] update link to ungleich Signed-off-by: Nico Schottelius --- 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 7515070d..39388c5a 100644 --- a/docs/web/cdist/support.mdwn +++ b/docs/web/cdist/support.mdwn @@ -20,6 +20,6 @@ you can join the ### Commercial support You can request commercial support for cdist from -[my company](http://firma.schottelius.org/english/). +[my company](http://www.ungleich.ch/english/). [[!tag cdist unix]] From 717e21da6c6a93fa77c3da65641b217718d464bd Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 7 Feb 2014 00:28:02 +0100 Subject: [PATCH 522/548] initial update for override unittests --- cdist/test/emulator/__init__.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 8c2dcd72..d2bf4cf2 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -100,6 +100,7 @@ class EmulatorTestCase(test.CdistTestCase): argv = ['__file', '/tmp/foobar'] self.env['require'] = '__file/etc/*' emu = emulator.Emulator(argv, env=self.env) + emu.run() # if we get here all is fine @@ -129,6 +130,33 @@ class AutoRequireEmulatorTestCase(test.CdistTestCase): expected = ['__planet/Saturn', '__moon/Prometheus'] self.assertEqual(sorted(cdist_object.autorequire), sorted(expected)) +class OverrideTestCase(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) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_override(self): + argv = ['__file', '/tmp/foobar'] + self.env['require'] = '__file/etc/*' + emu = emulator.Emulator(argv, env=self.env) + # if we get here all is fine + class ArgumentsTestCase(test.CdistTestCase): @@ -182,7 +210,7 @@ class ArgumentsTestCase(test.CdistTestCase): object_id = 'some-id' value = 'some value' argv = [type_name, object_id, '--required1', value, '--required2', value] - print(self.env) +# print(self.env) os.environ.update(self.env) emu = emulator.Emulator(argv) emu.run() From f163b327205949f584cb90730be1276e0f1d2265 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 7 Feb 2014 13:28:22 +0100 Subject: [PATCH 523/548] first try of a test --- cdist/test/emulator/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index d2bf4cf2..57874f9d 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -100,7 +100,6 @@ class EmulatorTestCase(test.CdistTestCase): argv = ['__file', '/tmp/foobar'] self.env['require'] = '__file/etc/*' emu = emulator.Emulator(argv, env=self.env) - emu.run() # if we get here all is fine @@ -155,6 +154,11 @@ class OverrideTestCase(test.CdistTestCase): argv = ['__file', '/tmp/foobar'] self.env['require'] = '__file/etc/*' emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__file', '/tmp/foobar'] + self.env['require'] = '__file/etc/*' + emu = emulator.Emulator(argv, env=self.env) + emu.run() # if we get here all is fine From 60c53e213c6961ea7d19731df2a0309095d5897c Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Fri, 7 Feb 2014 14:24:12 +0100 Subject: [PATCH 524/548] testcases emulator.OverrideTestCase, with some minor bugfixes to make test work as expected ... --- cdist/emulator.py | 3 +-- cdist/test/cdist_object/__init__.py | 4 ++-- cdist/test/cdist_type/__init__.py | 4 ++-- cdist/test/emulator/__init__.py | 15 +++++++++++---- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index 7fd89110..c910531c 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -130,7 +130,6 @@ class Emulator(object): self.args = parser.parse_args(self.argv[1:]) 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: @@ -146,7 +145,7 @@ class Emulator(object): if value is not None: self.parameters[key] = value - if self.cdist_object.exists and not 'CDIST_OVERRIDE' in os.environ: + if self.cdist_object.exists and not 'CDIST_OVERRIDE' in self.env: 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) diff --git a/cdist/test/cdist_object/__init__.py b/cdist/test/cdist_object/__init__.py index 54ecf637..0e2da103 100644 --- a/cdist/test/cdist_object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -58,10 +58,10 @@ class ObjectClassTestCase(test.CdistTestCase): def test_list_type_names(self): type_names = list(cdist.core.CdistObject.list_type_names(object_base_path)) - self.assertEqual(type_names, ['__first', '__second', '__third']) + self.assertEqual(sorted(type_names), ['__first', '__second', '__third']) def test_list_objects(self): - found_objects = list(core.CdistObject.list_objects(object_base_path, type_base_path)) + found_objects = sorted(list(core.CdistObject.list_objects(object_base_path, type_base_path))) self.assertEqual(found_objects, self.expected_objects) def test_create_singleton(self): diff --git a/cdist/test/cdist_type/__init__.py b/cdist/test/cdist_type/__init__.py index 79f824d3..36a524b4 100644 --- a/cdist/test/cdist_type/__init__.py +++ b/cdist/test/cdist_type/__init__.py @@ -34,7 +34,7 @@ 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(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') @@ -44,7 +44,7 @@ class TypeTestCase(test.CdistTestCase): core.CdistType(base_path, '__second'), core.CdistType(base_path, '__third'), ] - self.assertEqual(types, types_expected) + self.assertEqual(sorted(types), types_expected) def test_only_one_instance(self): base_path = fixtures diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 57874f9d..95c189d6 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -2,6 +2,7 @@ # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -150,16 +151,22 @@ class OverrideTestCase(test.CdistTestCase): def tearDown(self): shutil.rmtree(self.temp_dir) - def test_override(self): + def test_override_negative(self): argv = ['__file', '/tmp/foobar'] - self.env['require'] = '__file/etc/*' emu = emulator.Emulator(argv, env=self.env) emu.run() + argv = ['__file', '/tmp/foobar','--mode','404'] + emu = emulator.Emulator(argv, env=self.env) + self.assertRaises(cdist.Error, emu.run) + + def test_override_feature(self): argv = ['__file', '/tmp/foobar'] - self.env['require'] = '__file/etc/*' emu = emulator.Emulator(argv, env=self.env) emu.run() - # if we get here all is fine + argv = ['__file', '/tmp/foobar','--mode','404'] + self.env['CDIST_OVERRIDE'] = 'on' + emu = emulator.Emulator(argv, env=self.env) + emu.run() class ArgumentsTestCase(test.CdistTestCase): From f87fc63a7960a7efe42d354d64c3cfaf97c47942 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Feb 2014 00:13:33 +0100 Subject: [PATCH 525/548] cdist 3.0.7 Signed-off-by: Nico Schottelius --- docs/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 120d8e87..2bbe4edf 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,8 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.0.7: - * Core: Add support for in order execution (Daniel Heule) +3.0.7: 2014-02-08 + * Core: Allow dependencies to be created based execution order (Daniel Heule) + * Core: Add tests for override (Daniel Heule) 3.0.6: 2014-02-06 * New Type: __apt_key (Steven Armstrong) From 77df0ae324c95874f543bba213a54723771d2271 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Feb 2014 00:14:42 +0100 Subject: [PATCH 526/548] update reference Signed-off-by: Nico Schottelius --- docs/man/cdist-reference.text.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 5de59eab..88a002df 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -239,6 +239,9 @@ require:: CDIST_ALLOW_OVERRIDE:: Allow overwriting type parameters (see cdist-manifest(7)) +CDIST_ORDER_DEPENDENCY:: + Create dependencies based on the execution order (see cdist-manifest(7)) + SEE ALSO -------- - cdist(1) @@ -246,6 +249,6 @@ SEE ALSO COPYING ------- -Copyright \(C) 2011-2013 Nico Schottelius. Free use of this software is +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 From 4cca5930718c7584cde02a392c55e26c79342aee Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 8 Feb 2014 00:44:47 +0100 Subject: [PATCH 527/548] do not package .swp files (fixes #269) Signed-off-by: Nico Schottelius --- setup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setup.py b/setup.py index 32d734b8..c484a269 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ from distutils.core import setup import cdist import os +import re def data_finder(data_dir): entries = [] @@ -10,6 +11,11 @@ def data_finder(data_dir): if name == ".gitignore": continue + # Skip vim swp files + swpfile = re.search(r'^\..*\.swp$', name) + if swpfile: + continue + entry = os.path.join(data_dir, name) if os.path.isdir(entry): entries.extend(data_finder(entry)) From 423001b7026ab183fb204181c58ef5fb6a7901f0 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Sat, 8 Feb 2014 21:48:51 +0100 Subject: [PATCH 528/548] Make state parameter optional for all types, fixes #131 --- cdist/conf/type/__pf_ruleset/man.text | 2 +- cdist/conf/type/__pf_ruleset/parameter/default/state | 1 + cdist/conf/type/__pf_ruleset/parameter/optional | 1 + cdist/conf/type/__postgres_database/gencode-remote | 3 +-- cdist/conf/type/__postgres_database/man.text | 2 +- cdist/conf/type/__postgres_database/parameter/default/state | 1 + cdist/conf/type/__postgres_role/gencode-remote | 3 +-- cdist/conf/type/__postgres_role/parameter/default/state | 1 + cdist/conf/type/__rvm/man.text | 2 +- cdist/conf/type/__rvm/parameter/default/state | 1 + .../parameter/required => __rvm/parameter/optional} | 0 cdist/conf/type/__rvm_gemset/man.text | 2 +- cdist/conf/type/__rvm_gemset/parameter/default/state | 1 + .../parameter/required => __rvm_gemset/parameter/optional} | 0 cdist/conf/type/__rvm_gemset/parameter/required | 1 - cdist/conf/type/__rvm_ruby/man.text | 2 +- cdist/conf/type/__rvm_ruby/parameter/default/state | 1 + cdist/conf/type/__rvm_ruby/parameter/optional | 1 + cdist/conf/type/__rvm_ruby/parameter/required | 1 - 19 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 cdist/conf/type/__pf_ruleset/parameter/default/state create mode 100644 cdist/conf/type/__postgres_database/parameter/default/state create mode 100644 cdist/conf/type/__postgres_role/parameter/default/state create mode 100644 cdist/conf/type/__rvm/parameter/default/state rename cdist/conf/type/{__pf_ruleset/parameter/required => __rvm/parameter/optional} (100%) create mode 100644 cdist/conf/type/__rvm_gemset/parameter/default/state rename cdist/conf/type/{__rvm/parameter/required => __rvm_gemset/parameter/optional} (100%) create mode 100644 cdist/conf/type/__rvm_ruby/parameter/default/state create mode 100644 cdist/conf/type/__rvm_ruby/parameter/optional diff --git a/cdist/conf/type/__pf_ruleset/man.text b/cdist/conf/type/__pf_ruleset/man.text index 0dc07f71..29efe065 100644 --- a/cdist/conf/type/__pf_ruleset/man.text +++ b/cdist/conf/type/__pf_ruleset/man.text @@ -16,7 +16,7 @@ This type is used on *BSD systems to manage the pf firewall's ruleset. REQUIRED PARAMETERS ------------------- state:: - Either "absent" (no ruleset at all) or "present" + Either "absent" (no ruleset at all) or "present", defaults to "present". OPTIONAL PARAMETERS diff --git a/cdist/conf/type/__pf_ruleset/parameter/default/state b/cdist/conf/type/__pf_ruleset/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__pf_ruleset/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__pf_ruleset/parameter/optional b/cdist/conf/type/__pf_ruleset/parameter/optional index 5a18cd2f..d77f3048 100644 --- a/cdist/conf/type/__pf_ruleset/parameter/optional +++ b/cdist/conf/type/__pf_ruleset/parameter/optional @@ -1 +1,2 @@ source +state diff --git a/cdist/conf/type/__postgres_database/gencode-remote b/cdist/conf/type/__postgres_database/gencode-remote index 0ffc842a..c097efce 100755 --- a/cdist/conf/type/__postgres_database/gencode-remote +++ b/cdist/conf/type/__postgres_database/gencode-remote @@ -19,8 +19,7 @@ # name="$__object_id" -state_should="present" -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" state_is="$(cat "$__object/explorer/state")" if [ "$state_should" != "$state_is" ]; then diff --git a/cdist/conf/type/__postgres_database/man.text b/cdist/conf/type/__postgres_database/man.text index 88259b6f..c7c0d3cd 100644 --- a/cdist/conf/type/__postgres_database/man.text +++ b/cdist/conf/type/__postgres_database/man.text @@ -16,7 +16,7 @@ This cdist type allows you to create or drop postgres databases. OPTIONAL PARAMETERS ------------------- state:: - either 'present' or 'absent' + either 'present' or 'absent', defaults to 'present'. owner:: the role owning this database diff --git a/cdist/conf/type/__postgres_database/parameter/default/state b/cdist/conf/type/__postgres_database/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__postgres_database/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote index 65a9d588..0230e48e 100755 --- a/cdist/conf/type/__postgres_role/gencode-remote +++ b/cdist/conf/type/__postgres_role/gencode-remote @@ -20,8 +20,7 @@ name="$__object_id" state_is="$(cat "$__object/explorer/state")" -state_should="present" -[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")" +state_should="$(cat "$__object/parameter/state")" [ "$state_is" = "$state_should" ] && exit 0 diff --git a/cdist/conf/type/__postgres_role/parameter/default/state b/cdist/conf/type/__postgres_role/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__postgres_role/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__rvm/man.text b/cdist/conf/type/__rvm/man.text index c1f83e60..0408d125 100644 --- a/cdist/conf/type/__rvm/man.text +++ b/cdist/conf/type/__rvm/man.text @@ -16,7 +16,7 @@ RVM is the Ruby enVironment Manager for the Ruby programming language. REQUIRED PARAMETERS ------------------- state:: - Either "present" or "absent". + Either "present" or "absent", defaults to "present". EXAMPLES diff --git a/cdist/conf/type/__rvm/parameter/default/state b/cdist/conf/type/__rvm/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__rvm/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__pf_ruleset/parameter/required b/cdist/conf/type/__rvm/parameter/optional similarity index 100% rename from cdist/conf/type/__pf_ruleset/parameter/required rename to cdist/conf/type/__rvm/parameter/optional diff --git a/cdist/conf/type/__rvm_gemset/man.text b/cdist/conf/type/__rvm_gemset/man.text index 44c0c555..e85425f3 100644 --- a/cdist/conf/type/__rvm_gemset/man.text +++ b/cdist/conf/type/__rvm_gemset/man.text @@ -18,7 +18,7 @@ REQUIRED PARAMETERS user:: The remote user account to use state:: - Either "present" or "absent". + Either "present" or "absent", defaults to "present". BOOLEAN PARAMETERS ------------------- diff --git a/cdist/conf/type/__rvm_gemset/parameter/default/state b/cdist/conf/type/__rvm_gemset/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__rvm_gemset/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__rvm/parameter/required b/cdist/conf/type/__rvm_gemset/parameter/optional similarity index 100% rename from cdist/conf/type/__rvm/parameter/required rename to cdist/conf/type/__rvm_gemset/parameter/optional diff --git a/cdist/conf/type/__rvm_gemset/parameter/required b/cdist/conf/type/__rvm_gemset/parameter/required index 5aea6f1e..4eb8387f 100644 --- a/cdist/conf/type/__rvm_gemset/parameter/required +++ b/cdist/conf/type/__rvm_gemset/parameter/required @@ -1,2 +1 @@ -state user diff --git a/cdist/conf/type/__rvm_ruby/man.text b/cdist/conf/type/__rvm_ruby/man.text index dbbab85e..6419a4d4 100644 --- a/cdist/conf/type/__rvm_ruby/man.text +++ b/cdist/conf/type/__rvm_ruby/man.text @@ -18,7 +18,7 @@ REQUIRED PARAMETERS user:: The remote user account to use state:: - Either "present" or "absent". + Either "present" or "absent", defaults to "present". BOOLEAN PARAMETERS ------------------ diff --git a/cdist/conf/type/__rvm_ruby/parameter/default/state b/cdist/conf/type/__rvm_ruby/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__rvm_ruby/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__rvm_ruby/parameter/optional b/cdist/conf/type/__rvm_ruby/parameter/optional new file mode 100644 index 00000000..ff72b5c7 --- /dev/null +++ b/cdist/conf/type/__rvm_ruby/parameter/optional @@ -0,0 +1 @@ +state diff --git a/cdist/conf/type/__rvm_ruby/parameter/required b/cdist/conf/type/__rvm_ruby/parameter/required index 5aea6f1e..4eb8387f 100644 --- a/cdist/conf/type/__rvm_ruby/parameter/required +++ b/cdist/conf/type/__rvm_ruby/parameter/required @@ -1,2 +1 @@ -state user From f3172fda957557174fe8d123a28ef50d0076658e Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Sat, 8 Feb 2014 22:06:27 +0100 Subject: [PATCH 529/548] 2 more types for issue 131 --- cdist/conf/type/__jail/man.text | 2 +- cdist/conf/type/__jail/parameter/default/state | 1 + cdist/conf/type/__jail/parameter/optional | 1 + cdist/conf/type/__jail/parameter/required | 1 - cdist/conf/type/__rvm_gem/man.text | 2 +- cdist/conf/type/__rvm_gem/parameter/default/state | 1 + cdist/conf/type/__rvm_gem/parameter/optional | 1 + cdist/conf/type/__rvm_gem/parameter/required | 1 - 8 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 cdist/conf/type/__jail/parameter/default/state delete mode 100644 cdist/conf/type/__jail/parameter/required create mode 100644 cdist/conf/type/__rvm_gem/parameter/default/state diff --git a/cdist/conf/type/__jail/man.text b/cdist/conf/type/__jail/man.text index b439e0f5..9c968d84 100644 --- a/cdist/conf/type/__jail/man.text +++ b/cdist/conf/type/__jail/man.text @@ -16,7 +16,7 @@ This type is used on FreeBSD to manage jails. REQUIRED PARAMETERS ------------------- state:: - Either "present" or "absent." + Either "present" or "absent", defaults to "present". jailbase:: The location of the .tgz archive containing the base fs for your jails. diff --git a/cdist/conf/type/__jail/parameter/default/state b/cdist/conf/type/__jail/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__jail/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__jail/parameter/optional b/cdist/conf/type/__jail/parameter/optional index 08ecd469..b36f0fa5 100644 --- a/cdist/conf/type/__jail/parameter/optional +++ b/cdist/conf/type/__jail/parameter/optional @@ -5,3 +5,4 @@ interface devfs-ruleset jaildir jailbase +state diff --git a/cdist/conf/type/__jail/parameter/required b/cdist/conf/type/__jail/parameter/required deleted file mode 100644 index ff72b5c7..00000000 --- a/cdist/conf/type/__jail/parameter/required +++ /dev/null @@ -1 +0,0 @@ -state diff --git a/cdist/conf/type/__rvm_gem/man.text b/cdist/conf/type/__rvm_gem/man.text index 2b72e7ae..d7eff3be 100644 --- a/cdist/conf/type/__rvm_gem/man.text +++ b/cdist/conf/type/__rvm_gem/man.text @@ -20,7 +20,7 @@ user:: gemset:: The gemset to use state:: - Either "present" or "absent" + Either "present" or "absent", defaults to "present". OPTIONAL PARAMETERS ------------------- diff --git a/cdist/conf/type/__rvm_gem/parameter/default/state b/cdist/conf/type/__rvm_gem/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__rvm_gem/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__rvm_gem/parameter/optional b/cdist/conf/type/__rvm_gem/parameter/optional index 4ad96d51..96983811 100644 --- a/cdist/conf/type/__rvm_gem/parameter/optional +++ b/cdist/conf/type/__rvm_gem/parameter/optional @@ -1 +1,2 @@ default +state diff --git a/cdist/conf/type/__rvm_gem/parameter/required b/cdist/conf/type/__rvm_gem/parameter/required index 75f60bb8..58243a95 100644 --- a/cdist/conf/type/__rvm_gem/parameter/required +++ b/cdist/conf/type/__rvm_gem/parameter/required @@ -1,3 +1,2 @@ -state gemset user From 2dd2f5593f5c32f0a0286d1b5ded27a623ee7b22 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Sun, 9 Feb 2014 17:10:43 +0100 Subject: [PATCH 530/548] bugfixes for issue 161 and FIXME: also check that there is no object ID when type is singleton? --- cdist/core/cdist_object.py | 5 ++++- cdist/test/cdist_object/__init__.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cdist/core/cdist_object.py b/cdist/core/cdist_object.py index b17bd339..e8c58a67 100644 --- a/cdist/core/cdist_object.py +++ b/cdist/core/cdist_object.py @@ -121,7 +121,8 @@ class CdistObject(object): return os.path.join(type_name, object_id) def validate_object_id(self): - # FIXME: also check that there is no object ID when type is singleton? + if self.cdist_type.is_singleton and self.object_id: + raise IllegalObjectIdError('singleton objects can\'t have a object_id') """Validate the given object_id and raise IllegalObjectIdError if it's not valid. """ @@ -130,6 +131,8 @@ class CdistObject(object): raise IllegalObjectIdError(self.object_id, 'object_id may not contain \'%s\'' % OBJECT_MARKER) 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 .') # 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 0e2da103..7396bc57 100644 --- a/cdist/test/cdist_object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -94,6 +94,17 @@ class ObjectIdTestCase(test.CdistTestCase): core.CdistObject(cdist_type, object_base_path, 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) + + 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) class ObjectTestCase(test.CdistTestCase): From a5426ff4b5054561367b005d0c4a98536b1832d2 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Sun, 9 Feb 2014 17:43:31 +0100 Subject: [PATCH 531/548] completed copyright infos ... --- cdist/test/cdist_object/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/test/cdist_object/__init__.py b/cdist/test/cdist_object/__init__.py index 7396bc57..28f2455b 100644 --- a/cdist/test/cdist_object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -2,6 +2,7 @@ # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2012 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # From b4373b91b345d19765ad8ea493c7f71ffa5f3526 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Mon, 10 Feb 2014 07:22:57 +0100 Subject: [PATCH 532/548] add document to describe the flow when installing Signed-off-by: Nico Schottelius --- docs/gfx/instalation-using-preos.odg | Bin 0 -> 15330 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/gfx/instalation-using-preos.odg diff --git a/docs/gfx/instalation-using-preos.odg b/docs/gfx/instalation-using-preos.odg new file mode 100644 index 0000000000000000000000000000000000000000..6424bbc5f35165e4f10c26bd488bf9b667b0c028 GIT binary patch literal 15330 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�$Q;+zTRiqaYH&da=)sYsLprnJZu4>w6j02A?`@6z!eB3t}uw)gAz0+ultf$3UIg`X(_(>_5Y+UcWS zZ-<pyS3UDSGT@9d1rVN#44ppCVZg7Y|9*=N;?Ho~OWsE$N?G7g8~)11T#-9VqQuA`T;h z&BTq+53W(vGl=tMjwS+9MwK0F7b&m>a~=hRGxv*I>Tzu*h5)5pdkXs5TNt%t(5RGR zmPW{0Pm2BhM!kdur8`*raXFWg?;R!TkuV6phm8H{bJ0JhFDq{iYMjf_LB2pp@@AbF zYc(EIiLk9Ihs(`Kzu2+s>8g6dB)n{&?v7Pn8JX!y)q^NU$5~u4Q=7_XDJ;PyP%3qf z1(%wq7OTwr-R%8%AR{Lo1H0V#;j+=sAI2vA#0SEj?-vk0KeD?_V8Dk00^Ovc+|VV= zwr~^Nkfhp)ME)j|91b%~LMy?$N~lOel4$`JjccR9OB$!`JBSw`GnTH8U@JLlD{@`K zBFF5B=%aIkmIp}b=|<@@!=4nz3u?{%f+GmV0m2wF4{F_(?5I+-9eH@lPFD29fJ#SF z0VawXUC5Y{DAS?r45Qj+GCvnmF;!I~2u85>jg7o)DC*Zz%e0?KdGcD$pc^-u#sQ52 zX#Z#XI>jT)AO&{Hju=8c)34}1o6U7HEs9wB{o;cry~5lBP*DQq?;g8lc}vPLz>Ce)mIVd(+|3$?^#YHj0)gY7-g^NHs^{(@Sjt| z$s!`4yh1xY{k?DB+c+Xq2$=N6dZp#Jj4Y&%qGOKjyp_u~=@aR;VlWG$v!J@Q0^4RtL^2B95c8P+SLxL%|!+N(W_^4ctYh z8i0yx52x~^6)^WA^Z)AoIhteY?S=L;vk>gm9dqTIj zS8&=0tlXr>`wp1RAqzuvH(NFS@n`~I)>GOPGKL&m51neT9DCGjQhD`X>XZ4jN_4_9VoZRgt z*-BO0aLM8lquq(OvZk^UqeK+;wAXvycdKA>W+K?w6Q;qylq;2vexn@{8l=XJB4@rK&A(%oryxns1M?OVY#iTY)cnzL)^+Ie^R4V)ZTBmmD)>J8>D z#W=e-zlaxQt+69Ae`Vn9=&*vU&F&zVp&IUW$H=0S^m^$nc3*p9s9TLPchqOrlguw3 zorv`uZ}W))6bQdo2ViCxk%E< zn>HRjnXGZd+J)&vWYQcu!aSDjaA59e+-)GtC2%)9_9sp9dJ`5hQ?#WLeyUQ!CCpB0 zkRrMg?JVg_E!}3FGL$0HrqMp&05IQ_y*99F^o0_qpM*L!&xx}#e4X^|*WvaCa*(O{ z6mJ23V;)|zdoIMmG#8K~7f^(oPcg>8sx#0+5TT$AkSYWB$5!-G%Y5W*-`YfeE+z># z$wS&yT?*MVYuj0sbF$f84KRfRQIJKq1)SHGkbDIwUo#b1@?5XAJvZRbcS$8xn~=LB zUSL|0hw*xixY>Fxb*7i~Wd%VgOx$KvyXr`6a5RF4UU2~H(Q6HXJtSh>ocGghHdl0- zR$gnc5D-K{Os^GNk2vaBLyrOJeg|qtkAX=vUeCON*U^zaLV6P!h2@=DmpZ6`EI{q?s#7H;%FpM4KWZF_oWlu&p%v?0QuRTE1I745)rUt&C;0euJg$g81aT zBYO{WVgsYagIJ9O!4$;NtEIB8u(f13M9XC~=CraycQZHO&1d-YD6a(ln)kz93Tu|@ z^&cDY%WuPR4J2c%Rr4>8N4HGIJobBkY{++|QVS6}na_!(w(A2Zs|2MM{4vup5V3O% zG~I^7mA`M+Y5kgoH*z3coP!-3A2z!&@C)X~pF%rI__~ow@HsUu8ho`Z#xiG-(31#? z>LxM6*)$wHq0k3FA7#XMyGZCkKH?)Y;?1&mr1Sa)`=h{djya#e-9emFz2b-++fCHk zhGT6b+^sv`fvGCG)-q0d5xMoARXQkor&Cr%0i{81(AM9^^I)j&zI1=-$ z(*v}S-(B*~OjE{AlgGG~Nfw***d?o5ZB?2}vi6eb#G966m{uDOQ+JpF)@Pnx;4el+ zbh5RaMRbyrPQ!4#j*fGL8H)Hg=|OPXB1J9@?EA8&xOn|imu%pMG0|YJl7-*WkghBm z_NBlb(Mqo)@rLnm!nHBA)dV897Wjvcgw4y3D^}fI0-^UivuA{!;7CMmZyBOB2%h1WMqaaRMqn26ms)#uo2{Jt=e?F`L zRfbPpfQvrDV_;V(XeH){l@TSJvqbOZ{4@$@pL5YBZk-^Pi;VnYTaEU08Q8eEK z=$kb4@h74A|Bzevj7a7ed&)OKuF%i^p>_Bm>-~1W9fdV3iM{~iy9-}=8 zxHMM(6oLpt&lzJkJ>>4wq@4p^NV8Yv;oZQ`@I`io{PV?k>CkNfx1`H=-B`MO>P)bu z-h`(4+@`cA&#nzh6C6;>h8_^eCUEK&cTE%r;iuF>MD;Q|EoPsM3plp)(B|gxcj8yC z#%As+uDJVcGHZ~QZcd4{0To!wiyg;+wp*R2xuU5CV36$_+QUq9xJlL-^?QN!qR{!X zRWqX%#g?Wj$f*8f)x-Dz2FNz*q^*dmL!1ko()V$-Kw-F?>E0tbxFfN$rAStcQaNYY zYPS)hu|XQY4iYQ!`*|*Og2EKxn8_LZBhMz|Xc88}7(D^eSdiCBT+Q?0XF@2dNb=X7 z7vH9LqWmRSX$9N|*53Vhkl%9Pas>`)?!(*PSNl^A{2A9IEnoeHg9Zfj`;GA-2b4@4 zEe)*nO)c!{9sX?6*;pBWmy;3w42=c-@h6|f#e@_-KKp=xfPo-CeYA{uGtq&7P`AZ} z_?2AJPcz)*;#8mdbp_}GBpX9kD(A3sRa%q^KB1xZo0ifxJC!>*sdCoW9XHkSYMN)5 zzE7kaHP+|h9xEMNY0_KN&8}7~Yxh#=l|$<|@fG+8gXRzs42(vDK6q|gtoLO@4vJs3 zZ9ay_v9r6b+rzo?x{i_VwG54o$@mgHy=?!-96s(xVpKakf%3a7qAuEV3bvuIbo4AhL4ilfuy8&$_Rs zKiB-y(%N<-gOe(2)4G8_j%u+rId7$}moR4d;^DLnP2B{e~1e~L~eV&5=;=`WY&MW9X38Lkyw@nH)gH! zUdWG6OT(^o62oa;t6=5u3RNg?Rd*9#pF-jB@DSeob-h7 z?mAIQF{<~ar?2m>ni=Ngb?|ZqEPLBtwFEry^WgZ?P`33iZRI0e1dpOZh2w2ion&m( z`($nG4sNNdbKl|CrU1rTxGdj{~7x$AN@l1tQp9sPuT=N zP0Y>BEiHQw%c3(lopYrE1>_YKyGyXSTrOryRplwE1Rk56&-*B=m{?g^Nl8gbNb;MS zmgeW@Tf_&L>2dI*N=izSlQCw@pP#2W6|-CeNek&cK%#I@$pYQyg&8n!B0Bk$Vkb_??=`fZMVzRYvFL%fUx&Q)0{urUfvJwo^;I?z)fb z)RE3^e|NqfH5}fNJ$)F7!ycQF!R>x$@c`{E2V*4slJ?b7LtY+{I={6Q7x2xQ6v%?tg|PG-x#uhJW5*SkuVrWMx{GjKRfkCcH6_l!!Ouu z^*{vxv-x89l!is|G*8vl)#WPCw_JSU^vM7)W6he~t~NW{`XYL5EdH|J-;nz-B_$M& z-#c4ZwE{u#_>qjGrGm-6e8F(I27yIR{u>S7MpJuwdOq$i9GeyHagpbb=wHrL#@Wn9`7~IpSY&f58if~Oj)q~vzRm6Z<{>21Q)fPZf%Hkl)%7u& zP%s-NNDESU4}#!zD~!JF?dcdpZ1tmmR-M;{vjxU)r)7EhVR{Jh@v{mG$#BTf{4(JH zsjBE$SkRk8LqiMG+RaY0v$LJ@@lfc99oe`<(XMd_xg#(QtZ#(!xVX5y325oOHLRv@ z&|FRq$zR0i$A+aeU#!kpy#c25>wFJAQ)_Sh$*`FV&6ldB^_LA=Z^?{km$CuAx|g9w84xPQp9d z9XNOxL?ET!9{1u$1Y3k)sO{FOyziPMG+UYX-pelNFpa71E&h49ry4E-3g(mt^!^@$#4T$7~DxV5QT{yj8up@(y|yt)OC{ZNo^; zXqDSmaHuer)8g%o#zV6?RNQ^A`USi{nbL7G?FV1^Efw{{+H`-GCpj`IZ;I~qDJ12r zwMEi*`E+NgWz-8|_ zoQ3pTL}^q3IDyK&1NZl=yPp!T)*rhCJ$f!@%ryvy^J9)8d;+U^2e(ZUpt9%Lqj_mMNg5rw77NkvgaBEZYT@ zQVMftOxxlX?BJzqfvd`e8pWd2s1Dt_ar}B0W>g9Fi(`%{P#}qmk4gF1-o(Ty*x?(& zBJAX#fRSSoIu?LuOWC~}l9r>~I@k&2N__6v*kKftp^Ozjt5(;L7<^qN0X?J;?i>Wz zw0+>iI=5w1zphxmtc)2iM!=R)_Z&K7le=}1OQ?G`T<-LQsi<=3-Gj!ljh#P0!tC&X z6a3wIiQkEScBB9BUHVcaW|iU_e?j>ocBe0Z`*Ff4m(XcCgmBneDq`1dQ{h)Q`N=CVcD9yrCtN>bT*@^ckDEVj&~NT}^LRAaz)G^*FiFt@ViGuT*k}T=l0Ftq-n(h|IiX$O>?`hV1h| zYDzRhfwO||#MMZO#rZiSj&RTS@BZCK7u`C@ZWP4Nw$rdRT&r`{;142H07Dd5Jnc?L z%6zQVWQi-h8KB*dxcE{AVeTiaxm`ZaVTl~<1W!F{5_XbvVgi(%QiWqyYGkkV+L2VV_NF!3Y*`zQeMe#Pgr9B?Leu+CVxe8tW)P)7))fer~sZZvc^cF7w}{E|*$8kC!By@72wl+l`FB1aMocuPSMOj5k5Np+3#;`I`g{kZ%SX|Ns%cJkx(%9Xc%`R({8 z!hlkxP?9cuOW61!-$L6=Bdg^$kT{*uHeB-(kMz{icrhWM)+K|RJKIdN?1$o{o>-tD z;Ejgtk!W*4@zyojioE}#QgF$2 z9fdocrK@b8Cxni%SD`fQJWlIMO=?poK_h2lF+s)k`WeTpqTTWCf*g^U%;SDHm?}c0 z&E0BHhq4n+1u9ZIEGjZ9SIOKuQD>@wIS?LSSKfurZDgkAMUipUei$_#>BKNWjZt!; zQt;*<+&`*y?glL(O5bVbs{1Q2PSEn=@s=*6Y4kQi2kYkEdhyuvOwEeC_zp*`1$R`x z&sO@O!QRjXL(8mk2h}B%R?T2pX4dhbBCv6*nVNJ3DBWHe*}}9mlj{>9lz4@9r(}lG zu9NxX-si>GGfQd^)>3_60|mYhuC5lkC5jX#&mFyBmr!%Hc-XYGzLCf@W-IvRl_4D? zdBH_^&J6RCl;q`Y7ftzHi{6oq>iYIa!Xbkn_PVB+hOLjj?p4y9?qWk`sVyz@LdJC> zyR*KT%{oE6$k%VAN-{o)?B09v!%D*`nZH0zqwDEZNdGs^=1q8GAWBlPk&=PN?@x(^lI+1(Z?EbPRRPpR zaCy$%7&wN7Gs4zHKT7I!0ATCxPY<={M!8$$oXvxt26`XB!IG^OLk;Wp9^<5p*M0IR zl6nBO-U+?v?VMFCkF3mzu_Q>yRVkS_rOhxf9;6G|N%*!`&me#!*_)w9G+1Y+9b6~8jdvSm^ zoM=VOUxxF&V3aR49h9&p1sHb+pc!w&q=gGTZl#bp%kbhz+9Qj5o&+$v#f~y0-@@E7IN}pgTZ*2xjygrUWX=ojA zeyq=j^ILwjoWx5Z)9pGW1y7>uocv2_F$dIl7#b_p@M?5od zPvf$5sLo1#>E?zT%pu?o&r9`zDFLK7<&2o0Ps#GqHiFbh&#H4KpYmy3Ub`ker@dZ9 zmrHF(^5btWYD(DdLpH5oLaBzhiOxz9k+5}Lo^<);i5r<`W1g3p4>K(Vb+C+ zI1OtRwmTW|#l;>Cy2HlH*9HqRA_L-UP?z8LKV3uRbG>`h#4vmJj+!S0ODAtuDDggU zeHW0p>^zd0Fn9*3Pa#60s_PHiuJ6y6U09niD0n0&KZK|?#l zS%QtyS1%@K`g5}zNvzm6#MS0#8=X-iL1X2uqkC8t9ivdmJXchfmVTsJ(ca%OCfnMy zM{d=sd=H*-S4xDOm)go30g1Du<%_C^_zF>HwzZ=HOu0|I9T{*A!`?E!gOgJgHba#* zYA-F)PGACU;&TSAWxzhV$G2sCwUbnO(JWBS-1vujomMv%8k&*mX+@9XU%!5pl$ae% zcvjnq62}IN06YJ$sA(EOm8#eaYr@q828_P*hVh^)GQ< z>V(*aPu_%|MT+lv6H{4v{vmsLpHG+)?VoNAE8E}PULG#b+uwO~XelT{zJKpzU}0f# zYt<=M`cTg-w6ve0Q>Dlb4$jx>)B!d&Hja)gC>EBM5uu@ez>Pa*by!ysIP3}q3Y*Ee zoK7@qReX7qRdzN+?x?_mgf(yUHcSlIpk3?Om3*4kWN{#j>l zZ?7;vKOi6=TZdVe#%!}IaKLDPOYCR=_&9tP!V4ksUa^9rN<(4pm z@%!6r8mn~>&h`GdZo3yZ-SV<^d+UdakHBUfOJzCk@C6BBZVbT0#B8i^aqJC6y|C^M z`i$>!!7nP>|I>7u=l$h6Kc56LfO!93Dx2MYFJw1t7ZenP2IUXNFRL|&H*J)HE^R1W*Sk&ie)UNIYtU6?RG@ue0U=yQYhdYi|iU2>Dv zDhKv@#k0Wuc5`rHVd4Fn`+0f88j`&Y=0th6Zg)|8TN~c|Ue9-AT3XtH6mIvgQx6mH zm{WE3T%UmGPICm`HM=?;g+Ws}o$2gsHW5od2HE!ELO%>of(Bx9XQR{K1r=hw)&0I7 z-@B~592K6LmKG35&_O~*28Yj+zFXvEf3-8nVm?RUJ)X(E-4`L~ffOddj5IF1 zV9TMam5B+34lOmcq>RkkFMD#jogeaf(eN;nb&n4Z+0)@6A&pL_OP-}X-fvv)s0mvo zf+!1GIyz%Is4%{m_}(wJwzdqz>viU;+S<5HO0c)t^j#z;LZBZP28%o{JZ$OV{q$)y z>KyOOL)AcMfq<+pUtqL<(E-|`7-TCH-ehNW_XRUGHOwpVh|6{atIfhxf#jlOv;r4Q zj1k1tH0$EU5pL#QC>5W$bA$&qXF!;A;fBJ!oOFe_SRXyA>)!%zaXJKC&! z?P=)a>w}sB&}x*m54|)u${(}0S~1FNdbxA@@7bGZ_*PwD=>Pgy5YFzlz)Hor{RAz1g)*UnHoFV{gESU&q!}-sc#Ihrx!4F zu++D)r~l7jtbYL8Slc+-d}P%+{ts~u*47p_`c?po{~^xaLEpjA-ay~(zrf-A({i;-s zoqRI1uDJs=G&bjU083YzEV(>Up8Q!(G z#(V0Ns8twOPPyLLq`XK^ ziJf5FO$k!``B;NYoSr&_>6*}!?;;jrtbW}kV|wE!F%29Jf6<)1B6D1tyQ~Z(2)^sm z1=#!oK8oEc9-#O~SkFQy&;Xt!8GEcrVG%7Sb>rMn4>^tLIInS_OlomS%2D_8ysk$+ zB3BoI__A_(9OuuiqpjOSr1Q;7KntF1+wZKy#;f%YT(Fv&;IYCAT`ebkxh~q~ zzO;*}?q_PQ*J^#PpZUzY@{9EKnB3YrONNFy$QGo#BfL6ZF2yA&I4q7|4>#tr$6nB6 z7#X((qj8^Tc!wn#^=$F9$8@I8BN)%W!GPUB>t{Dmg@*x$!ZVqnRs$BSXj5UfxgsP> z4PvY}iVK*J-mdwV*XJe$u2oZf8dElY=SA7pt2E7@aVQJ z7Y_WDd2-$=lLP~3jKG&T-yoFBY4QNcxwS{+ei`W9AN@dq(|<-%<{^4Gu`_~;X~am` z7*i2hu*Wvz@HUSSv8?K><^A@rkGy^wuEQS=i&+>Rr_`W@B4lECWLn>bCB*7Y>-!Sna_A^N zRg275G(GDdPIEu1iis?s^dZuqb2-gQ;?LAHvlsMN@fN-?@xuC9-~JGZJO=mE$L(=& zfajA%sq6Z@%rQ!6%0D9#>efnFf2b6)r3KGFzY-ke*`#vdiyY8Uuc_aMRSb}+<&Ko5 z+&9aEVgaI&_U@Z)P`5HKpDHsZ4y63y0EN;Pcy@4er#^NoShkgTd_`x%Wd8$wY2v=| zGqWMA51o8)RDlzVGaq~BmkJicS<^=zU_Ylb0!Z5aFR--3KnS#+7@@#ur}{MXtTT;A z@-*U!wuyI*1uh5ILpuD+Ib3DBvBk8D;#7mo;Nt2I_4x(acX*A!=2O>3}UcXLqCpl*W%*ZkG^Pi;&$HS z$DHM$Zdu{4DX&%u9h?4hoyoK=V-g%Kz<4S~AKR6OR}68U#HRfL^8>J=UStiuhec!* zkv$@&dE|key^yRIT0=vD-us|>Ke#DYe^~E4z@LHN%88w3w`h}(VI9fs#9f_xo#p8y zx7(=Oy!vJ-BL^K^_1f<3wBF6E(O_+kH+g>*xygVVZI;Xe z&YM8Q*{OdGM5a2ri+`lgS3N}32XVe|X{RXiABLll!vD2!X0Jim>n&`~8 zya9C#9p)#X*u3a>V=^=>TzN3>5iTB-b%3&%k zsKug{;_8E&VGiB3ZHwdm;t~f1N4?Yv$S-crgYXhl*a=2dKNbynQ)Kd!2byGh$1B1T z8)goMYLQ?Ng_bgx;G_*H1FFhT(tJuDVzLl(c&1CYi;cmCPP#wBrTyp#;n`LQ8Du^a z6h2WUI!Co)+NE1cY3BR{hatU{Kfu{uPkW6z?rfI8B!}X{u1JEUel42p$~$A-n#W)D z{3Cm%1ZcM(>7$ft4di#H0)IjQLivw%dB6S6zwFN{y+2WZy10KY&icb;{a+CIkJd+J z-yfxT|Bm{5QvL73t-nn2!{z;Z8P~rf|DJ#IJL&!}8~ix^-%{}Z1pX|E@s(4}tc-_xN96AfVq8?JqO_2eQ8lw*M|q)<5w4 zUBLZ!dFKCt=kJ2i}ydU{3QVY zyDWA8!19+M{1?lg|1ZDq;7?WeTN3_d$N#|c9|Yo`PvxJaf1fLV3&OulfcEe5@ZWKN lpALS{q< Date: Mon, 10 Feb 2014 07:32:58 +0100 Subject: [PATCH 533/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 2bbe4edf..6aef1891 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.0.8: + * Core: Enhance object id verification (Daniel Heule) + 3.0.7: 2014-02-08 * Core: Allow dependencies to be created based execution order (Daniel Heule) * Core: Add tests for override (Daniel Heule) From e29255b9f250c15197406bed3b2d5869cc8751b7 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 11 Feb 2014 15:20:26 +0100 Subject: [PATCH 534/548] add an unittest for CDIST_ORDER_DEPENDENCY --- cdist/test/emulator/__init__.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/cdist/test/emulator/__init__.py b/cdist/test/emulator/__init__.py index 95c189d6..870d6245 100644 --- a/cdist/test/emulator/__init__.py +++ b/cdist/test/emulator/__init__.py @@ -103,6 +103,31 @@ class EmulatorTestCase(test.CdistTestCase): emu = emulator.Emulator(argv, env=self.env) # if we get here all is fine + def test_requirement_via_order_dependency(self): + self.env['CDIST_ORDER_DEPENDENCY'] = 'on' + argv = ['__planet', 'erde'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + argv = ['__planet', 'mars'] + emu = emulator.Emulator(argv, env=self.env) + emu.run() + # In real world, this is not shared over instances + del self.env['require'] + argv = ['__file', '/tmp/cdisttest'] + emu = emulator.Emulator(argv, env=self.env) + 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') + cdist_type = core.CdistType(self.local.type_path, '__file') + file_object = core.CdistObject(cdist_type, self.local.object_path, '/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 AutoRequireEmulatorTestCase(test.CdistTestCase): From 6a5f9082698f51e041c8932ddac10595d4301a1a Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Tue, 11 Feb 2014 21:17:19 +0100 Subject: [PATCH 535/548] yep, dryrun option has now a unittest, was hard to work out ... --- cdist/test/config/__init__.py | 17 +++++++++++++++++ .../config/fixtures/manifest/dryrun_manifest | 1 + .../config/fixtures/type/__dryrun_test/.keep | 0 .../fixtures/type/__dryrun_test/gencode-local | 3 +++ .../fixtures/type/__dryrun_test/gencode-remote | 3 +++ 5 files changed, 24 insertions(+) create mode 100644 cdist/test/config/fixtures/manifest/dryrun_manifest create mode 100644 cdist/test/config/fixtures/type/__dryrun_test/.keep create mode 100644 cdist/test/config/fixtures/type/__dryrun_test/gencode-local create mode 100644 cdist/test/config/fixtures/type/__dryrun_test/gencode-remote diff --git a/cdist/test/config/__init__.py b/cdist/test/config/__init__.py index 80a45d9b..70501c89 100644 --- a/cdist/test/config/__init__.py +++ b/cdist/test/config/__init__.py @@ -2,6 +2,7 @@ # # 2010-2011 Steven Armstrong (steven-cdist at armstrong.cc) # 2012-2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2014 Daniel Heule (hda at sfs.biz) # # This file is part of cdist. # @@ -137,6 +138,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 ] ) + + 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 # - but maybe only in the emulator - to be discussed. diff --git a/cdist/test/config/fixtures/manifest/dryrun_manifest b/cdist/test/config/fixtures/manifest/dryrun_manifest new file mode 100644 index 00000000..53bb9aa5 --- /dev/null +++ b/cdist/test/config/fixtures/manifest/dryrun_manifest @@ -0,0 +1 @@ +__dryrun_test testit diff --git a/cdist/test/config/fixtures/type/__dryrun_test/.keep b/cdist/test/config/fixtures/type/__dryrun_test/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cdist/test/config/fixtures/type/__dryrun_test/gencode-local b/cdist/test/config/fixtures/type/__dryrun_test/gencode-local new file mode 100644 index 00000000..ccd584bd --- /dev/null +++ b/cdist/test/config/fixtures/type/__dryrun_test/gencode-local @@ -0,0 +1,3 @@ +# this type is only for testing the dryrun feature, it does nothing usefull +echo 'echo "This gencode-local script should never be executed >&2"' +echo 'exit 1' diff --git a/cdist/test/config/fixtures/type/__dryrun_test/gencode-remote b/cdist/test/config/fixtures/type/__dryrun_test/gencode-remote new file mode 100644 index 00000000..e57e4e27 --- /dev/null +++ b/cdist/test/config/fixtures/type/__dryrun_test/gencode-remote @@ -0,0 +1,3 @@ +# this type is only for testing the dryrun feature, it does nothing usefull +echo 'echo "this gencode-remote script should never be executed >&2"' +echo 'exit 1' From 9ce3809eb37ec5c2d259f878aeb8ff2d0459e107 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Feb 2014 22:31:30 +0100 Subject: [PATCH 536/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog b/docs/changelog index 6aef1891..33b22f5b 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,8 @@ Changelog 3.0.8: * Core: Enhance object id verification (Daniel Heule) + * Core: Add unit tests for dependencies based on execution order (Daniel Heule) + * Core: Add unit tests for dry run (Daniel Heule) 3.0.7: 2014-02-08 * Core: Allow dependencies to be created based execution order (Daniel Heule) From e3464bef1b0499e19027772097a17b437aadcdb7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Tue, 11 Feb 2014 22:46:25 +0100 Subject: [PATCH 537/548] release 3.0.8 Signed-off-by: Nico Schottelius --- docs/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index 33b22f5b..53df9fa7 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,7 +5,7 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.0.8: +3.0.8: 2014-02-11 * Core: Enhance object id verification (Daniel Heule) * Core: Add unit tests for dependencies based on execution order (Daniel Heule) * Core: Add unit tests for dry run (Daniel Heule) From cfbc68aa113ddf74fa0d7fe4c78da5a251491ff8 Mon Sep 17 00:00:00 2001 From: Daniel Heule Date: Wed, 12 Feb 2014 10:31:46 +0100 Subject: [PATCH 538/548] bugfix if both override and order is specified --- cdist/emulator.py | 3 ++- docs/man/cdist-reference.text.sh | 2 +- docs/man/man7/cdist-manifest.text | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cdist/emulator.py b/cdist/emulator.py index c910531c..41834fbf 100644 --- a/cdist/emulator.py +++ b/cdist/emulator.py @@ -189,7 +189,8 @@ class Emulator(object): def record_requirements(self): """record requirements""" - if "CDIST_ORDER_DEPENDENCY" 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 not 'CDIST_OVERRIDE' in self.env: # load object name created bevor this one from typeorder file ... with open(self.typeorder_path, 'r') as typecreationfile: typecreationorder = typecreationfile.readlines() diff --git a/docs/man/cdist-reference.text.sh b/docs/man/cdist-reference.text.sh index 88a002df..62614c55 100755 --- a/docs/man/cdist-reference.text.sh +++ b/docs/man/cdist-reference.text.sh @@ -236,7 +236,7 @@ The following environment variables influence the behaviour of cdist: require:: Setup dependencies between objects (see cdist-manifest(7)) -CDIST_ALLOW_OVERRIDE:: +CDIST_OVERRIDE:: Allow overwriting type parameters (see cdist-manifest(7)) CDIST_ORDER_DEPENDENCY:: diff --git a/docs/man/man7/cdist-manifest.text b/docs/man/man7/cdist-manifest.text index 25637242..057905ea 100644 --- a/docs/man/man7/cdist-manifest.text +++ b/docs/man/man7/cdist-manifest.text @@ -152,6 +152,10 @@ ATTENTION: Only use this feature if you are 100% sure in which order cdist encounter the affected objects, otherwhise this results into an undefined situation. +If CDIST_OVERRIDE and CDIST_ORDER_DEPENDENCY is set for an object, +CDIST_ORDER_DEPENDENCY will be ignored, because adding a dependency in case of +overrides would result in circular dependencies, which is an error. + THIS IS A BETA FEATURE AND MAY BE REMOVED OR CHANGED AT ANY TIME. From 23f85118f5bae462d0f1c1776dcc17650295b17c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Feb 2014 16:42:02 +0100 Subject: [PATCH 539/548] add a hint about unsupported os Signed-off-by: Nico Schottelius --- cdist/conf/type/__locale/man.text | 4 ++-- cdist/conf/type/__locale/manifest | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cdist/conf/type/__locale/man.text b/cdist/conf/type/__locale/man.text index f76c2059..5ccd3eab 100644 --- a/cdist/conf/type/__locale/man.text +++ b/cdist/conf/type/__locale/man.text @@ -16,7 +16,7 @@ This cdist type allows you to setup locales. OPTIONAL PARAMETERS ------------------- state:: - 'present' or 'absent' + 'present' or 'absent', defaults to present EXAMPLES @@ -43,5 +43,5 @@ SEE ALSO COPYING ------- -Copyright \(C) 2013 Nico Schottelius. Free use of this software is +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). diff --git a/cdist/conf/type/__locale/manifest b/cdist/conf/type/__locale/manifest index 5dd5fd8f..f3d75d59 100644 --- a/cdist/conf/type/__locale/manifest +++ b/cdist/conf/type/__locale/manifest @@ -1,6 +1,6 @@ #!/bin/sh # -# 2013 Nico Schottelius (nico-cdist at schottelius.org) +# 2013-2014 Nico Schottelius (nico-cdist at schottelius.org) # # This file is part of cdist. # @@ -29,4 +29,9 @@ case "$os" in # Debian needs a seperate package __package locales --state present ;; + *) + echo "Sorry, do not know how to handle os: $os" >&2 + echo "Please edit the type ${__type##*/} to fix this." >&2 + exit 1 + ;; esac From c615a822129c992df3198682388f42742ef5e659 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Feb 2014 16:42:39 +0100 Subject: [PATCH 540/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog b/docs/changelog index 53df9fa7..2ebd08e8 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,6 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius +3.0.9: + * Type __locale: Error out in case of unsupported OS + 3.0.8: 2014-02-11 * Core: Enhance object id verification (Daniel Heule) * Core: Add unit tests for dependencies based on execution order (Daniel Heule) From a4376b4d744f118b148c3875c08e2704e4449021 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Feb 2014 16:57:29 +0100 Subject: [PATCH 541/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 2ebd08e8..dabb1da3 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.0.9: * Type __locale: Error out in case of unsupported OS + * Core: Ignore order dependencies if override is set (Daniel Heule) 3.0.8: 2014-02-11 * Core: Enhance object id verification (Daniel Heule) From 2afa0ad2fc717730630789349e1b1ac6451b2acc Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Wed, 12 Feb 2014 17:07:07 +0100 Subject: [PATCH 542/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/changelog b/docs/changelog index dabb1da3..4b3a01e1 100644 --- a/docs/changelog +++ b/docs/changelog @@ -6,8 +6,17 @@ Changelog 3.0.9: - * Type __locale: Error out in case of unsupported OS * Core: Ignore order dependencies if override is set (Daniel Heule) + * Type __locale: Error out in case of unsupported OS + * Type __jail: Use default parameters for state (Daniel Heule) + * Type __pf_ruleset: Use default parameters for state (Daniel Heule) + * Type __postgres_database: Use default parameters for state (Daniel Heule) + * Type __postgres_role: Use default parameters for state (Daniel Heule) + * Type __rvm: Use default parameters for state (Daniel Heule) + * Type __rvm_gem: Use default parameters for state (Daniel Heule) + * Type __rvm_gemset: Use default parameters for state (Daniel Heule) + * Type __rvm_ruby: Use default parameters for state (Daniel Heule) + 3.0.8: 2014-02-11 * Core: Enhance object id verification (Daniel Heule) From a2c2cc139aade56886d8c474fa3c159a0c29222b Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Thu, 13 Feb 2014 10:33:24 +0100 Subject: [PATCH 543/548] adjust default branch hint Signed-off-by: Nico Schottelius --- cdist/conf/type/__git/man.text | 1 + 1 file changed, 1 insertion(+) diff --git a/cdist/conf/type/__git/man.text b/cdist/conf/type/__git/man.text index 7c6b83cd..5f74108b 100644 --- a/cdist/conf/type/__git/man.text +++ b/cdist/conf/type/__git/man.text @@ -26,6 +26,7 @@ state:: branch:: Create this branch by checking out the remote branch of this name + Default branch is "master" group:: Group to chgrp to. From 46459053f463789f01a4afc159d1ab02a1940a11 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Feb 2014 21:02:18 +0100 Subject: [PATCH 544/548] use posix -L in favour of longopts Signed-off-by: Steven Armstrong --- cdist/test/fixtures/remote/copy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdist/test/fixtures/remote/copy b/cdist/test/fixtures/remote/copy index a4627716..05f43eb1 100755 --- a/cdist/test/fixtures/remote/copy +++ b/cdist/test/fixtures/remote/copy @@ -1,7 +1,7 @@ #!/bin/sh # # 2012-2013 Nico Schottelius (nico-cdist schottelius.org) -# 2013 Steven Armstrong (steven-cdist armstrong.cc) +# 2013-2014 Steven Armstrong (steven-cdist armstrong.cc) # # This file is part of cdist. # @@ -20,4 +20,4 @@ # code="$(echo "$@" | sed "s|\([[:space:]]\)$__target_host:|\1|g")" -cp --dereference $code +cp -L $code From f82a6224f228cf9bb52b44302e8371cfd5a125c6 Mon Sep 17 00:00:00 2001 From: Steven Armstrong Date: Thu, 13 Feb 2014 21:05:37 +0100 Subject: [PATCH 545/548] use positional arguments in favour of keyword arguments for backwards compatibility with older python Signed-off-by: Steven Armstrong --- cdist/test/cdist_object/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdist/test/cdist_object/__init__.py b/cdist/test/cdist_object/__init__.py index 28f2455b..3c25a959 100644 --- a/cdist/test/cdist_object/__init__.py +++ b/cdist/test/cdist_object/__init__.py @@ -49,7 +49,7 @@ class ObjectClassTestCase(test.CdistTestCase): self.expected_objects = [] for cdist_object_name in self.expected_object_names: - cdist_type, cdist_object_id = cdist_object_name.split("/", maxsplit=1) + 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) self.expected_objects.append(cdist_object) From a765fe5c07117c8abfe33207952d0ad3cac24aa7 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Feb 2014 01:48:33 +0100 Subject: [PATCH 546/548] ++changes Signed-off-by: Nico Schottelius --- docs/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog b/docs/changelog index 4b3a01e1..0930f01d 100644 --- a/docs/changelog +++ b/docs/changelog @@ -7,6 +7,7 @@ Changelog 3.0.9: * Core: Ignore order dependencies if override is set (Daniel Heule) + * Core: Improve unit tests for Mac OS X (Steven Armstrong) * Type __locale: Error out in case of unsupported OS * Type __jail: Use default parameters for state (Daniel Heule) * Type __pf_ruleset: Use default parameters for state (Daniel Heule) From d55763ad6d0c7da333be297c6770225a1c094e28 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Feb 2014 09:59:56 +0100 Subject: [PATCH 547/548] ++release Signed-off-by: Nico Schottelius --- docs/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog b/docs/changelog index 0930f01d..e8f98c01 100644 --- a/docs/changelog +++ b/docs/changelog @@ -5,9 +5,9 @@ Changelog * Exception: No braces means author == Nico Schottelius -3.0.9: +3.0.9: 2014-02-14 * Core: Ignore order dependencies if override is set (Daniel Heule) - * Core: Improve unit tests for Mac OS X (Steven Armstrong) + * Core: Improve Mac OS X support for unit tests (Steven Armstrong) * Type __locale: Error out in case of unsupported OS * Type __jail: Use default parameters for state (Daniel Heule) * Type __pf_ruleset: Use default parameters for state (Daniel Heule) From 134a4a7b3402673013af293523fedfff3e8cd0cf Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Fri, 14 Feb 2014 12:45:34 +0100 Subject: [PATCH 548/548] add discussion notes Signed-off-by: Nico Schottelius --- docs/dev/logs/2014-02-13.discussion | 86 +++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 docs/dev/logs/2014-02-13.discussion diff --git a/docs/dev/logs/2014-02-13.discussion b/docs/dev/logs/2014-02-13.discussion new file mode 100644 index 00000000..70c0f4fc --- /dev/null +++ b/docs/dev/logs/2014-02-13.discussion @@ -0,0 +1,86 @@ +With Steven + +t marker .cdist breaks + - use random marker that starts with .cdist- + - has fixed number of following characters (like 6 or 10) + - write marker name to $__global/marker + - export $__global/marker path as $__marker + - document variable in cdist-reference + - also document the pattern how the marker is built + so that other people may be able to dig into the structure + from outside + +t save method + - in $__global/method + - values + - config + - install + - document path and description in cdist-reference + +t save whole runtime in cache + - missing items + - initial manifest may be specified on commandline + - always save the initial manifest to $__global/initial-manifest + - currently it is a lost tempfile + - remote exec / remote copy + - save to $__global/remote_exec + - save to $__global/remote_copy + - stdout and stderr of everything + - need to implement Steven's patch of stderr/stdout capturing + - exit code of cdist + - if it is complete, we can use it for replay / reconfigure + +- new idea: replay / reconfig / reinstall + - --from-cache? + +t stderr/stdout + - capture all messages + - prefix with target_host + - implementation exists in one of Steven's branches + - ping steven for updated pull request + +x on error dump all information about the failing object + - where created + - stderr + - stdout + - parameter (+values) + - everything known [tm] + +t multiple versions of cache + - see #298 + +t absolute path of types, explorer + - resolve instead of using the temporary link name + - #305 + +t report command + - from cache? + - #306 + +t add session to "run directories" + - instead of /var/lib/cdist (remote) + - instead of static dir in cache + - same id remote and local + - maybe timestamp + - in or excluding the pid of cdist? + +- cache + - also save when cdist fails + - save exit code + - be able to restore config + +- new command: cdist clean-cache + - --since + - --keep-versions --keep-lala $num + +- cdist 4.0.0pre2 + - cleanup in preos + +- logging for types + cdist log ...? + + - cdist logserver + - $__global/log.socket + - fifo? + echo into logpipe? +